001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.sort.DocumentSorter;
004: import net.sf.saxon.sort.Reverser;
005: import net.sf.saxon.trans.XPathException;
006: import net.sf.saxon.value.SequenceType;
007: import net.sf.saxon.functions.Current;
008: import net.sf.saxon.type.TypeHierarchy;
009:
010: /**
011: * PromotionOffer is an object used transiently during compilation of an expression. It contains
012: * information passed by a containing expression to its subexpressions, when looking for subexpressions
013: * that can be promoted to a higher level because they are not dependent on the context established
014: * by the containing expression. The object is also used to pass back return information when the
015: * promotion actually takes place.
016: */
017:
018: public class PromotionOffer {
019:
020: /**
021: * FOCUS_INDEPENDENT requests promotion of all non-trivial subexpressions that don't depend on the
022: * focus. This is typically used to extract subexpressions from a filter predicate. The offer is
023: * optional - each subexpression can decide whether it's worth the trouble of promoting itself.
024: * The offer is normally passed on to subexpressions, except subexpressions that are evaluated
025: * with a different focus
026: */
027:
028: public static final int FOCUS_INDEPENDENT = 10;
029:
030: /**
031: * RANGE_INDEPENDENT requests promotion of all non-trivial subexpressions that don't depend on a
032: * specified range variable. This is typically used to extract subexpressions from the action of
033: * a for expression or the condition of a some/every quantified expression. The offer is
034: * optional - each subexpression can decide whether it's worth the trouble of promoting itself.
035: * The offer is normally passed on to subexpressions, except subexpressions that are evaluated
036: * with a different focus or a different range variable, because these may have other dependencies
037: * that prevent their promotion.
038: */
039:
040: public static final int RANGE_INDEPENDENT = 11;
041:
042: /**
043: * Inline variable references causes all references to a variable V to be replaced by the
044: * expression E. The variable is supplied in the "binding" property; the replacement expression
045: * in the containingExpression property. A special case is where the replacement expression is
046: * a ContextItemExpression; in this case the offer is not passed on to subexpressions where
047: * the context is different.
048: */
049:
050: public static final int INLINE_VARIABLE_REFERENCES = 12;
051:
052: // Note: After inlining variable references, it is possible for an expression to appear at more
053: // than one place in the expression tree. This seems dangerous, since a rewrite applied to one
054: // branch might be inappropriate in another branch. We get away with it because the only expressions
055: // that we are inline are very simple ones: (a) a ContextItemExpression, and (b) another VariableReference.
056:
057: /**
058: * UNORDERED indicates that the containing expression does not require the results
059: * to be delivered in any particular order. The boolean mustEliminateDuplicates
060: * is set if duplicate items in the result are not allowed.
061: */
062:
063: public static final int UNORDERED = 13;
064:
065: /**
066: * REPLACE_CURRENT causes calls to the XSLT current() function to be replaced by
067: * reference to a variable. The variable binding is the single member of the array bindingList
068: */
069:
070: public static final int REPLACE_CURRENT = 14;
071:
072: /**
073: * The optimizer in use
074: */
075:
076: private Optimizer optimizer;
077:
078: /**
079: * action is one of the possible promotion actions, FOCUS_INDEPENDENT, RANGE_INDEPENDENT,
080: * INLINE_VARIABLE_REFERENCES, ANY_ORDER, ANY_ORDER_UNIQUE
081: */
082:
083: public int action;
084:
085: /**
086: * In the case of FOCUS_INDEPENDENT, "promoteDocumentDependent" is a boolean that, when set to
087: * true, indicates that it is safe to promote a subexpression that depends on the context document
088: * but not on other aspects of the focus. This is the case, for example, in a filter expression when
089: * it is known that all the nodes selected by the expression will be in the same document - as happens
090: * when the filter is applied to a path expression. This allows subexpressions such as key() to be
091: * promoted
092: */
093:
094: public boolean promoteDocumentDependent = false;
095:
096: /**
097: * In the case of FOCUS_INDEPENDENT, "promoteXSLTFunctions" is a boolean that, when set to true, indicates
098: * that it is safe to promote XSLT functions such as current(). This flag is set when rewriting XPath expressions
099: * and is unset when rewriting XSLT templates.
100: */
101:
102: public boolean promoteXSLTFunctions = true;
103:
104: /**
105: * In the case of UNORDERED, "mustEliminateDuplicates" is a boolean that is set to
106: * true if the nodes can be delivered in any order so long as there are no duplicates
107: * (for example, as required by the count() function). If this boolean is false, the
108: * nodes can be delivered in any order and duplicates are allowed (for example, as
109: * required by the boolean() function).
110: */
111:
112: public boolean mustEliminateDuplicates = true;
113:
114: /**
115: * In the case of RANGE_INDEPENDENT and WHERE_CLAUSE, "binding" identifies the range variables whose dependencies
116: * we are looking for. For INLINE_VARIABLE_REFERENCES it is a single Binding that we are aiming to inline
117: */
118:
119: public Binding[] bindingList;
120:
121: /**
122: * When a promotion offer is made, containingExpression identifies the level to which the promotion
123: * should occur. When a subexpression is promoted, an expression of the form let $VAR := SUB return ORIG
124: * is created, and this replaces the original containingExpression within the PromotionOffer.
125: */
126:
127: public Expression containingExpression;
128:
129: /**
130: * Flag that is set if the offer has been accepted, that is, if the expression has changed
131: */
132:
133: public boolean accepted = false;
134:
135: /**
136: * Create a PromotionOffer for use with a particular Optimizer
137: */
138:
139: public PromotionOffer(Optimizer optimizer) {
140: this .optimizer = optimizer;
141: }
142:
143: /**
144: * Get the optimizer in use
145: */
146:
147: public Optimizer getOptimizer() {
148: return optimizer;
149: }
150:
151: /**
152: * Method to test whether a subexpression qualifies for promotion, and if so, to
153: * accept the promotion.
154: * @return if promotion was done, returns the expression that should be used in place
155: * of the child expression. If no promotion was done, returns null.
156: */
157:
158: public Expression accept(Expression child) throws XPathException {
159: switch (action) {
160: case RANGE_INDEPENDENT: {
161: int properties = child.getSpecialProperties();
162: if (((properties & StaticProperty.NON_CREATIVE) != 0)
163: && !ExpressionTool.dependsOnVariable(child,
164: bindingList)) {
165: return promote(child);
166: }
167: break;
168: }
169:
170: case FOCUS_INDEPENDENT: {
171: int dependencies = child.getDependencies();
172: int properties = child.getSpecialProperties();
173: if (!promoteXSLTFunctions
174: && ((dependencies & StaticProperty.DEPENDS_ON_XSLT_CONTEXT) != 0)) {
175: break;
176: }
177: if ((dependencies & StaticProperty.DEPENDS_ON_FOCUS) == 0
178: && (properties & StaticProperty.NON_CREATIVE) != 0) {
179: return promote(child);
180: } else if (promoteDocumentDependent
181: && (dependencies & StaticProperty.DEPENDS_ON_NON_DOCUMENT_FOCUS) == 0
182: && (properties & StaticProperty.NON_CREATIVE) != 0) {
183: return promote(child);
184: }
185: break;
186: }
187:
188: case REPLACE_CURRENT: {
189: if (child instanceof Current) {
190: VariableReference var = new VariableReference(
191: ((Assignation) containingExpression)
192: .getVariableDeclaration());
193: var.setParentExpression(child.getParentExpression());
194: return var;
195: }
196: break;
197: }
198:
199: case INLINE_VARIABLE_REFERENCES: {
200: if (child instanceof VariableReference
201: && ((VariableReference) child).getBinding() == bindingList[0]) {
202: return containingExpression;
203: }
204: break;
205: }
206: case UNORDERED: {
207: if (child instanceof Reverser) {
208: return ((Reverser) child).getBaseExpression();
209: } else if (child instanceof DocumentSorter
210: && !mustEliminateDuplicates) {
211: return ((DocumentSorter) child).getBaseExpression();
212: }
213: break;
214: }
215: default:
216: throw new UnsupportedOperationException(
217: "Unknown promotion action " + action);
218: }
219: return null;
220: }
221:
222: /**
223: * Method to do the promotion.
224: */
225:
226: private Expression promote(Expression child) {
227: final RangeVariableDeclaration decl = new RangeVariableDeclaration();
228: decl.setVariableName("zz:" + decl.hashCode());
229: final TypeHierarchy th = optimizer.getConfiguration()
230: .getNamePool().getTypeHierarchy();
231: SequenceType type = SequenceType.makeSequenceType(child
232: .getItemType(th), child.getCardinality());
233: decl.setRequiredType(type);
234:
235: VariableReference var = new VariableReference(decl);
236: ExpressionTool.copyLocationInfo(containingExpression, var);
237: var.setParentExpression(child.getParentExpression());
238:
239: Container container = containingExpression
240: .getParentExpression();
241: LetExpression let = new LetExpression();
242: let.setVariableDeclaration(decl);
243: let.setSequence(LazyExpression.makeLazyExpression(child));
244: let.setAction(containingExpression);
245: let.setParentExpression(container);
246: let.adoptChildExpression(containingExpression);
247: containingExpression = let;
248: accepted = true;
249:
250: return var;
251: }
252:
253: }
254:
255: //
256: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
257: // you may not use this file except in compliance with the License. You may obtain a copy of the
258: // License at http://www.mozilla.org/MPL/
259: //
260: // Software distributed under the License is distributed on an "AS IS" basis,
261: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
262: // See the License for the specific language governing rights and limitations under the License.
263: //
264: // The Original Code is: all this file.
265: //
266: // The Initial Developer of the Original Code is Michael H. Kay
267: //
268: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
269: //
270: // Contributor(s): none.
271: //
|