001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.*;
004: import net.sf.saxon.trans.XPathException;
005: import net.sf.saxon.type.ItemType;
006: import net.sf.saxon.type.Type;
007: import net.sf.saxon.type.TypeHierarchy;
008: import net.sf.saxon.value.*;
009:
010: /**
011: * A RangeExpression is an expression that represents an integer sequence as
012: * a pair of end-points (for example "x to y").
013: * If the end-points are equal, the sequence is of length one.
014: * <p>From Saxon 7.8, the sequence must be ascending; if the end-point is less
015: * than the start-point, an empty sequence is returned. This is to allow
016: * expressions of the form "for $i in 1 to count($seq) return ...." </p>
017: */
018:
019: public class RangeExpression extends BinaryExpression {
020:
021: /**
022: * Construct a RangeExpression
023: */
024:
025: public RangeExpression(Expression start, int op, Expression end) {
026: super (start, op, end);
027: }
028:
029: /**
030: * Type-check the expression
031: */
032:
033: public Expression typeCheck(StaticContext env,
034: ItemType contextItemType) throws XPathException {
035: operand0 = operand0.typeCheck(env, contextItemType);
036: operand1 = operand1.typeCheck(env, contextItemType);
037:
038: RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR,
039: "to", 0, null);
040: role0.setSourceLocator(this );
041: operand0 = TypeChecker.staticTypeCheck(operand0,
042: SequenceType.OPTIONAL_INTEGER, false, role0, env);
043:
044: RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR,
045: "to", 1, null);
046: role1.setSourceLocator(this );
047: operand1 = TypeChecker.staticTypeCheck(operand1,
048: SequenceType.OPTIONAL_INTEGER, false, role1, env);
049:
050: return this ;
051: }
052:
053: /**
054: * Perform optimisation of an expression and its subexpressions.
055: * <p/>
056: * <p>This method is called after all references to functions and variables have been resolved
057: * to the declaration of the function or variable, and after all type checking has been done.</p>
058: *
059: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
060: * different optimization strategies to be used in different circumstances.
061: * @param env the static context of the expression
062: * @param contextItemType the static type of "." at the point where this expression is invoked.
063: * The parameter is set to null if it is known statically that the context item will be undefined.
064: * If the type of the context item is not known statically, the argument is set to
065: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
066: * @return the original expression, rewritten if appropriate to optimize execution
067: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
068: * (typically a type error)
069: */
070:
071: public Expression optimize(Optimizer opt, StaticContext env,
072: ItemType contextItemType) throws XPathException {
073: operand0 = operand0.optimize(opt, env, contextItemType);
074: operand1 = operand1.optimize(opt, env, contextItemType);
075:
076: if (operand0 instanceof IntegerValue
077: && operand1 instanceof IntegerValue) {
078: long i0 = ((IntegerValue) operand0).longValue();
079: long i1 = ((IntegerValue) operand1).longValue();
080: if (i0 > i1) {
081: return EmptySequence.getInstance();
082: } else {
083: return new IntegerRange(i0, i1);
084: }
085: }
086: return this ;
087:
088: }
089:
090: /**
091: * Get the data type of the items returned
092: * @param th
093: */
094:
095: public ItemType getItemType(TypeHierarchy th) {
096: return Type.INTEGER_TYPE;
097: }
098:
099: /**
100: * Determine the static cardinality
101: */
102:
103: public int computeCardinality() {
104: return StaticProperty.ALLOWS_ZERO_OR_MORE;
105: }
106:
107: /**
108: * Return an iteration over the sequence
109: */
110:
111: public SequenceIterator iterate(XPathContext context)
112: throws XPathException {
113: AtomicValue av1 = (AtomicValue) operand0.evaluateItem(context);
114: if (av1 == null) {
115: return new EmptyIterator();
116: }
117: NumericValue v1 = (NumericValue) av1.getPrimitiveValue();
118:
119: AtomicValue av2 = (AtomicValue) operand1.evaluateItem(context);
120: if (av2 == null) {
121: return new EmptyIterator();
122: }
123: NumericValue v2 = (NumericValue) av2.getPrimitiveValue();
124:
125: if (v1.compareTo(v2) > 0) {
126: return new EmptyIterator();
127: }
128: return new RangeIterator(v1.longValue(), v2.longValue());
129: }
130:
131: /**
132: * Iterator that produces numeric values in a monotonic sequence,
133: * ascending or descending. Although a range expression (N to M) is always
134: * in ascending order, applying the reverse() function will produce
135: * a RangeIterator that works in descending order.
136: */
137:
138: public static class RangeIterator implements SequenceIterator,
139: ReversibleIterator, LastPositionFinder, LookaheadIterator,
140: GroundedIterator {
141:
142: long start;
143: long currentValue;
144: int increment; // always +1 or -1
145: long limit;
146:
147: public RangeIterator(long start, long end) {
148: this .start = start;
149: increment = (start <= end ? +1 : -1);
150: currentValue = start;
151: limit = end;
152: }
153:
154: public boolean hasNext() {
155: if (increment > 0) {
156: return currentValue <= limit;
157: } else if (increment < 0) {
158: return currentValue >= limit;
159: } else {
160: return false;
161: }
162: }
163:
164: public Item next() {
165: if (!hasNext()) {
166: increment = 0;
167: return null;
168: }
169: long d = currentValue;
170: currentValue += increment;
171: return new IntegerValue(d);
172: }
173:
174: public Item current() {
175: if (increment == 0) {
176: return null;
177: } else {
178: return new IntegerValue(currentValue - increment);
179: }
180: }
181:
182: public int position() {
183: if (increment > 0) {
184: return (int) (currentValue - start);
185: } else if (increment < 0) {
186: return (int) (start - currentValue);
187: } else {
188: return -1;
189: }
190: }
191:
192: public int getLastPosition() {
193: return (int) ((limit - start) * increment + 1);
194: }
195:
196: public SequenceIterator getAnother() throws XPathException {
197: return new RangeIterator(start, limit);
198: }
199:
200: /**
201: * Get properties of this iterator, as a bit-significant integer.
202: *
203: * @return the properties of this iterator. This will be some combination of
204: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
205: * and {@link LOOKAHEAD}. It is always
206: * acceptable to return the value zero, indicating that there are no known special properties.
207: * It is acceptable for the properties of the iterator to change depending on its state.
208: */
209:
210: public int getProperties() {
211: int props = LOOKAHEAD | LAST_POSITION_FINDER;
212: if (increment == 1) {
213: props |= GROUNDED;
214: }
215: return props;
216: }
217:
218: public SequenceIterator getReverseIterator() {
219: return new RangeIterator(limit, start);
220: }
221:
222: /**
223: * Return a Value containing all the items in the sequence returned by this
224: * SequenceIterator. This should be an "in-memory" value, not a Closure.
225: *
226: * @return the corresponding Value
227: */
228:
229: public Value materialize() throws XPathException {
230: if (increment == 1) {
231: return new IntegerRange(start, limit);
232: } else {
233: return new SequenceExtent(getAnother());
234: }
235: }
236: }
237: }
238:
239: //
240: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
241: // you may not use this file except in compliance with the License. You may obtain a copy of the
242: // License at http://www.mozilla.org/MPL/
243: //
244: // Software distributed under the License is distributed on an "AS IS" basis,
245: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
246: // See the License for the specific language governing rights and limitations under the License.
247: //
248: // The Original Code is: all this file.
249: //
250: // The Initial Developer of the Original Code is Michael H. Kay
251: //
252: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
253: //
254: // Contributor(s): none.
255: //
|