001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.Item;
004: import net.sf.saxon.om.NamePool;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.type.ItemType;
008: import net.sf.saxon.type.Type;
009: import net.sf.saxon.type.TypeHierarchy;
010: import net.sf.saxon.value.BooleanValue;
011: import net.sf.saxon.value.NumericValue;
012: import net.sf.saxon.value.IntegerValue;
013:
014: import java.io.PrintStream;
015: import java.util.Iterator;
016:
017: /**
018: * PositionRange: a boolean expression that tests whether the position() is
019: * within a certain range. This expression can occur in any context but it is
020: * optimized when it appears as a predicate (see FilterIterator)
021: */
022:
023: public final class PositionRange extends ComputedExpression {
024:
025: private Expression minPosition;
026: private Expression maxPosition; // may be null to indicate an open range
027:
028: /**
029: * Create a position range
030: */
031:
032: public PositionRange(Expression min, Expression max) {
033: minPosition = min;
034: maxPosition = max;
035: adoptChildExpression(min);
036: adoptChildExpression(max);
037: }
038:
039: /**
040: * Create a constant position range
041: */
042:
043: public PositionRange(int min, int max) {
044: minPosition = new IntegerValue(min);
045: if (max == Integer.MAX_VALUE) {
046: maxPosition = null;
047: } else {
048: maxPosition = new IntegerValue(max);
049: }
050: }
051:
052: /**
053: * Simplify an expression
054: * @return the simplified expression
055: */
056:
057: public Expression simplify(StaticContext env) throws XPathException {
058: minPosition = minPosition.simplify(env);
059: if (maxPosition != null) {
060: maxPosition = maxPosition.simplify(env);
061: }
062: return this ;
063: }
064:
065: /**
066: * Type-check the expression
067: */
068:
069: public Expression typeCheck(StaticContext env,
070: ItemType contextItemType) throws XPathException {
071: minPosition = minPosition.typeCheck(env, contextItemType);
072: if (maxPosition != null) {
073: maxPosition = maxPosition.typeCheck(env, contextItemType);
074: }
075: return this ;
076: }
077:
078: /**
079: * Perform optimisation of an expression and its subexpressions.
080: * <p/>
081: * <p>This method is called after all references to functions and variables have been resolved
082: * to the declaration of the function or variable, and after all type checking has been done.</p>
083: *
084: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
085: * different optimization strategies to be used in different circumstances.
086: * @param env the static context of the expression
087: * @param contextItemType the static type of "." at the point where this expression is invoked.
088: * The parameter is set to null if it is known statically that the context item will be undefined.
089: * If the type of the context item is not known statically, the argument is set to
090: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
091: * @return the original expression, rewritten if appropriate to optimize execution
092: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
093: * (typically a type error)
094: */
095:
096: public Expression optimize(Optimizer opt, StaticContext env,
097: ItemType contextItemType) throws XPathException {
098: minPosition = minPosition.optimize(opt, env, contextItemType);
099: if (maxPosition != null) {
100: maxPosition = maxPosition.optimize(opt, env,
101: contextItemType);
102: }
103: return this ;
104: }
105:
106: /**
107: * Determine the special properties of this expression
108: * @return {@link StaticProperty#NON_CREATIVE}.
109: */
110:
111: public int computeSpecialProperties() {
112: int p = super .computeSpecialProperties();
113: return p | StaticProperty.NON_CREATIVE;
114: }
115:
116: /**
117: * Evaluate the expression
118: */
119:
120: public Item evaluateItem(XPathContext c) throws XPathException {
121: int p = c.getContextPosition();
122: if (maxPosition == null) {
123: NumericValue min = (NumericValue) minPosition
124: .evaluateItem(c);
125: return BooleanValue.get(p >= min.longValue());
126: } else {
127: NumericValue min = (NumericValue) minPosition
128: .evaluateItem(c);
129: NumericValue max = (NumericValue) maxPosition
130: .evaluateItem(c);
131: return BooleanValue.get(p >= min.longValue()
132: && p <= max.longValue());
133: }
134: }
135:
136: /**
137: * Make an iterator over a range of a sequence determined by this position range
138: */
139:
140: public SequenceIterator makePositionIterator(SequenceIterator base,
141: XPathContext c) throws XPathException {
142: int low, high;
143: NumericValue min = (NumericValue) minPosition.evaluateItem(c);
144: low = (int) min.longValue();
145: if (maxPosition == null) {
146: high = Integer.MAX_VALUE;
147: } else {
148: NumericValue max = (NumericValue) maxPosition
149: .evaluateItem(c);
150: high = (int) max.longValue();
151: }
152: return PositionIterator.make(base, low, high);
153: }
154:
155: /**
156: * Determine the data type of the expression
157: * @return Type.BOOLEAN
158: * @param th
159: */
160:
161: public ItemType getItemType(TypeHierarchy th) {
162: return Type.BOOLEAN_TYPE;
163: }
164:
165: /**
166: * Determine the static cardinality
167: */
168:
169: public int computeCardinality() {
170: return StaticProperty.EXACTLY_ONE;
171: }
172:
173: /**
174: * Get the dependencies
175: */
176:
177: public int getIntrinsicDependencies() {
178: return StaticProperty.DEPENDS_ON_POSITION;
179: }
180:
181: /**
182: * Get the immediate sub-expressions of this expression. Default implementation
183: * returns a zero-length array, appropriate for an expression that has no
184: * sub-expressions.
185: *
186: * @return an iterator containing the sub-expressions of this expression
187: */
188:
189: public Iterator iterateSubExpressions() {
190: if (maxPosition == null) {
191: return new MonoIterator(minPosition);
192: } else {
193: return new PairIterator(minPosition, maxPosition);
194: }
195: }
196:
197: /**
198: * Test if the first and last position are both constant 1
199: */
200:
201: public boolean isFirstPositionOnly() {
202: try {
203: return (minPosition instanceof NumericValue && ((NumericValue) minPosition)
204: .longValue() == 1)
205: && (maxPosition instanceof NumericValue && ((NumericValue) maxPosition)
206: .longValue() == 1);
207: } catch (XPathException e) {
208: return false;
209: }
210: }
211:
212: /**
213: * Test whether the range is focus-dependent. An example of a focus-dependent range is
214: * (1 to position()). We could treat last() specially but we don't.
215: */
216:
217: public boolean hasFocusDependentRange() {
218: return ((minPosition.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0)
219: || (maxPosition != null && (maxPosition
220: .getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0);
221: }
222:
223: /**
224: * Test if the position range matches at most one item
225: */
226:
227: public boolean matchesAtMostOneItem() {
228: return maxPosition != null && minPosition.equals(maxPosition)
229: && !hasFocusDependentRange();
230: }
231:
232: /**
233: * If this is an open-ended range with a constant start position, make a TailExpression.
234: * Otherwise return null
235: */
236:
237: public TailExpression makeTailExpression(Expression start) {
238: if (maxPosition == null && minPosition instanceof IntegerValue) {
239: return new TailExpression(start,
240: (int) ((IntegerValue) minPosition).longValue());
241: } else {
242: return null;
243: }
244:
245: }
246:
247: /**
248: * Diagnostic print of expression structure
249: */
250:
251: public void display(int level, NamePool pool, PrintStream out) {
252: out.println(ExpressionTool.indent(level) + "positionRange");
253: minPosition.display(level + 1, pool, out);
254: maxPosition.display(level + 1, pool, out);
255: }
256: }
257:
258: //
259: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
260: // you may not use this file except in compliance with the License. You may obtain a copy of the
261: // License at http://www.mozilla.org/MPL/
262: //
263: // Software distributed under the License is distributed on an "AS IS" basis,
264: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
265: // See the License for the specific language governing rights and limitations under the License.
266: //
267: // The Original Code is: all this file.
268: //
269: // The Initial Developer of the Original Code is Michael H. Kay.
270: //
271: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
272: //
273: // Contributor(s): none.
274: //
|