PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/saxon-9.3.0.4/net/sf/saxon/expr/QuantifiedExpression.java

#
Java | 319 lines | 148 code | 58 blank | 113 comment | 19 complexity | 9b0c3041dba7e27190f120d8a8e8f7dc MD5 | raw file
Possible License(s): GPL-3.0
  1. package net.sf.saxon.expr;
  2. import net.sf.saxon.functions.BooleanFn;
  3. import net.sf.saxon.om.Item;
  4. import net.sf.saxon.om.SequenceIterator;
  5. import net.sf.saxon.trace.ExpressionPresenter;
  6. import net.sf.saxon.trans.XPathException;
  7. import net.sf.saxon.type.BuiltInAtomicType;
  8. import net.sf.saxon.type.ItemType;
  9. import net.sf.saxon.type.TypeHierarchy;
  10. import net.sf.saxon.value.BooleanValue;
  11. import net.sf.saxon.value.SequenceType;
  12. /**
  13. * A QuantifiedExpression tests whether some/all items in a sequence satisfy
  14. * some condition.
  15. */
  16. public class QuantifiedExpression extends Assignation {
  17. private int operator; // Token.SOME or Token.EVERY
  18. /**
  19. * Get a name identifying the kind of expression, in terms meaningful to a user.
  20. * @return a name identifying the kind of expression, in terms meaningful to a user.
  21. * The name will always be in the form of a lexical XML QName, and should match the name used
  22. * in explain() output displaying the expression.
  23. */
  24. public String getExpressionName() {
  25. return (operator == Token.SOME ? "some" : "every");
  26. }
  27. /**
  28. * Set the operator, either {@link Token#SOME} or {@link Token#EVERY}
  29. * @param operator the operator
  30. */
  31. public void setOperator(int operator) {
  32. this.operator = operator;
  33. }
  34. /**
  35. * Get the operator, either {@link Token#SOME} or {@link Token#EVERY}
  36. * @return the operator
  37. */
  38. public int getOperator() {
  39. return operator;
  40. }
  41. /**
  42. * Determine the static cardinality
  43. */
  44. public int computeCardinality() {
  45. return StaticProperty.EXACTLY_ONE;
  46. }
  47. /**
  48. * Type-check the expression
  49. */
  50. public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException {
  51. final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy();
  52. // The order of events is critical here. First we ensure that the type of the
  53. // sequence expression is established. This is used to establish the type of the variable,
  54. // which in turn is required when type-checking the action part.
  55. sequence = visitor.typeCheck(sequence, contextItemType);
  56. if (Literal.isEmptySequence(sequence)) {
  57. return Literal.makeLiteral(BooleanValue.get(operator != Token.SOME));
  58. }
  59. // "some" and "every" have no ordering constraints
  60. Optimizer opt = visitor.getConfiguration().getOptimizer();
  61. sequence = ExpressionTool.unsorted(opt, sequence, false);
  62. SequenceType decl = getRequiredType();
  63. SequenceType sequenceType = SequenceType.makeSequenceType(decl.getPrimaryType(),
  64. StaticProperty.ALLOWS_ZERO_OR_MORE);
  65. RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, getVariableQName(), 0);
  66. //role.setSourceLocator(this);
  67. sequence = TypeChecker.strictTypeCheck(
  68. sequence, sequenceType, role, visitor.getStaticContext());
  69. ItemType actualItemType = sequence.getItemType(th);
  70. refineTypeInformation(actualItemType,
  71. StaticProperty.EXACTLY_ONE,
  72. null,
  73. sequence.getSpecialProperties(), visitor, this);
  74. //declaration = null; // let the garbage collector take it
  75. action = visitor.typeCheck(action, contextItemType);
  76. XPathException err = TypeChecker.ebvError(action, visitor.getConfiguration().getTypeHierarchy());
  77. if (err != null) {
  78. err.setLocator(this);
  79. throw err;
  80. }
  81. return this;
  82. }
  83. /**
  84. * Perform optimisation of an expression and its subexpressions.
  85. * <p/>
  86. * <p>This method is called after all references to functions and variables have been resolved
  87. * to the declaration of the function or variable, and after all type checking has been done.</p>
  88. *
  89. * @param visitor an expression visitor
  90. * @param contextItemType the static type of "." at the point where this expression is invoked.
  91. * The parameter is set to null if it is known statically that the context item will be undefined.
  92. * If the type of the context item is not known statically, the argument is set to
  93. * {@link net.sf.saxon.type.Type#ITEM_TYPE}
  94. * @return the original expression, rewritten if appropriate to optimize execution
  95. * @throws XPathException if an error is discovered during this phase
  96. * (typically a type error)
  97. */
  98. public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException {
  99. Optimizer opt = visitor.getConfiguration().getOptimizer();
  100. sequence = visitor.optimize(sequence, contextItemType);
  101. action = visitor.optimize(action, contextItemType);
  102. Expression ebv = BooleanFn.rewriteEffectiveBooleanValue(action, visitor, contextItemType);
  103. if (ebv != null) {
  104. action = ebv;
  105. adoptChildExpression(ebv);
  106. }
  107. PromotionOffer offer = new PromotionOffer(opt);
  108. offer.containingExpression = this;
  109. offer.action = PromotionOffer.RANGE_INDEPENDENT;
  110. offer.bindingList = new Binding[] {this};
  111. action = doPromotion(action, offer);
  112. if (offer.containingExpression instanceof LetExpression) {
  113. offer.containingExpression =
  114. visitor.optimize(visitor.typeCheck(offer.containingExpression, contextItemType), contextItemType);
  115. }
  116. Expression e2 = offer.containingExpression;
  117. if (e2 != this) {
  118. return e2;
  119. }
  120. // if streaming, convert to an expression that can be streamed
  121. if (visitor.isOptimizeForStreaming()) {
  122. Expression e3 = visitor.getConfiguration().getOptimizer().optimizeQuantifiedExpressionForStreaming(this);
  123. if (e3 != this) {
  124. return visitor.optimize(e3, contextItemType);
  125. }
  126. }
  127. return this;
  128. }
  129. /**
  130. * Check to ensure that this expression does not contain any updating subexpressions.
  131. * This check is overridden for those expressions that permit updating subexpressions.
  132. *
  133. * @throws net.sf.saxon.trans.XPathException
  134. * if the expression has a non-permitted updateing subexpression
  135. */
  136. public void checkForUpdatingSubexpressions() throws XPathException {
  137. sequence.checkForUpdatingSubexpressions();
  138. action.checkForUpdatingSubexpressions();
  139. }
  140. /**
  141. * Determine whether this is an updating expression as defined in the XQuery update specification
  142. * @return true if this is an updating expression
  143. */
  144. public boolean isUpdatingExpression() {
  145. return false;
  146. }
  147. /**
  148. * Copy an expression. This makes a deep copy.
  149. * @return the copy of the original expression
  150. */
  151. public Expression copy() {
  152. QuantifiedExpression qe = new QuantifiedExpression();
  153. qe.setOperator(operator);
  154. qe.setVariableQName(variableName);
  155. qe.setRequiredType(requiredType);
  156. qe.setSequence(sequence.copy());
  157. Expression newAction = action.copy();
  158. qe.setAction(newAction);
  159. qe.variableName = variableName;
  160. qe.slotNumber = slotNumber;
  161. ExpressionTool.rebindVariableReferences(newAction, this, qe);
  162. return qe;
  163. }
  164. /**
  165. * Given an expression that is an immediate child of this expression, test whether
  166. * the evaluation of the parent expression causes the child expression to be
  167. * evaluated repeatedly
  168. * @param child the immediate subexpression
  169. * @return true if the child expression is evaluated repeatedly
  170. */
  171. public boolean hasLoopingSubexpression(Expression child) {
  172. return child == action;
  173. }
  174. /**
  175. * Determine the special properties of this expression
  176. * @return {@link StaticProperty#NON_CREATIVE}.
  177. */
  178. public int computeSpecialProperties() {
  179. int p = super.computeSpecialProperties();
  180. return p | StaticProperty.NON_CREATIVE;
  181. }
  182. /**
  183. * Evaluate the expression to return a singleton value
  184. */
  185. public Item evaluateItem(XPathContext context) throws XPathException {
  186. return BooleanValue.get(effectiveBooleanValue(context));
  187. }
  188. /**
  189. * Get the result as a boolean
  190. */
  191. public boolean effectiveBooleanValue(XPathContext context) throws XPathException {
  192. // First create an iteration of the base sequence.
  193. SequenceIterator base = sequence.iterate(context);
  194. // Now test to see if some or all of the tests are true. The same
  195. // logic is used for the SOME and EVERY operators
  196. final boolean some = (operator==Token.SOME);
  197. int slot = getLocalSlotNumber();
  198. while (true) {
  199. final Item it = base.next();
  200. if (it == null) {
  201. break;
  202. }
  203. context.setLocalVariable(slot, it);
  204. if (some == action.effectiveBooleanValue(context)) {
  205. base.close();
  206. return some;
  207. }
  208. }
  209. return !some;
  210. }
  211. /**
  212. * Determine the data type of the items returned by the expression
  213. * @return Type.BOOLEAN
  214. * @param th the type hierarchy cache
  215. */
  216. public ItemType getItemType(TypeHierarchy th) {
  217. return BuiltInAtomicType.BOOLEAN;
  218. }
  219. /**
  220. * The toString() method for an expression attempts to give a representation of the expression
  221. * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath.
  222. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax
  223. * @return a representation of the expression as a string
  224. */
  225. public String toString() {
  226. return (operator==Token.SOME ? "some" : "every") + " $" + getVariableName() +
  227. " in " + sequence.toString() + " satisfies " + action.toString();
  228. }
  229. /**
  230. * Diagnostic print of expression structure. The abstract expression tree
  231. * is written to the supplied output destination.
  232. */
  233. public void explain(ExpressionPresenter out) {
  234. out.startElement(Token.tokens[operator]);
  235. out.emitAttribute("variable", getVariableName());
  236. out.startSubsidiaryElement("in");
  237. sequence.explain(out);
  238. out.endSubsidiaryElement();
  239. out.startSubsidiaryElement("satisfies");
  240. action.explain(out);
  241. out.endSubsidiaryElement();
  242. out.endElement();
  243. }
  244. }
  245. //
  246. // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
  247. // you may not use this file except in compliance with the License. You may obtain a copy of the
  248. // License at http://www.mozilla.org/MPL/
  249. //
  250. // Software distributed under the License is distributed on an "AS IS" basis,
  251. // WITHOUT WARRANTY OF ANY KIND, either express or implied.
  252. // See the License for the specific language governing rights and limitations under the License.
  253. //
  254. // The Original Code is: all this file.
  255. //
  256. // The Initial Developer of the Original Code is Michael H. Kay
  257. //
  258. // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
  259. //
  260. // Contributor(s): none.
  261. //