KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > expr > RangeExpression


1 package net.sf.saxon.expr;
2 import net.sf.saxon.om.*;
3 import net.sf.saxon.trans.XPathException;
4 import net.sf.saxon.type.ItemType;
5 import net.sf.saxon.type.Type;
6 import net.sf.saxon.value.*;
7
8 /**
9 * A RangeExpression is an expression that represents an integer sequence as
10 * a pair of end-points (for example "x to y").
11 * If the end-points are equal, the sequence is of length one.
12  * <p>From Saxon 7.8, the sequence must be ascending; if the end-point is less
13  * than the start-point, an empty sequence is returned. This is to allow
14  * expressions of the form "for $i in 1 to count($seq) return ...." </p>
15 */

16
17 public class RangeExpression extends BinaryExpression {
18
19     /**
20     * Construct a RangeExpression
21     */

22
23     public RangeExpression(Expression start, int op, Expression end) {
24         super(start, op, end);
25     }
26
27     /**
28     * Type-check the expression
29     */

30
31     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
32         operand0 = operand0.typeCheck(env, contextItemType);
33         operand1 = operand1.typeCheck(env, contextItemType);
34
35         RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, "to", 0, null);
36         role0.setSourceLocator(this);
37         operand0 = TypeChecker.staticTypeCheck(
38                 operand0, SequenceType.OPTIONAL_INTEGER, false, role0, env);
39
40         RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, "to", 1, null);
41         role1.setSourceLocator(this);
42         operand1 = TypeChecker.staticTypeCheck(
43                 operand1, SequenceType.OPTIONAL_INTEGER, false, role1, env);
44
45         return this;
46     }
47
48     /**
49      * Perform optimisation of an expression and its subexpressions.
50      * <p/>
51      * <p>This method is called after all references to functions and variables have been resolved
52      * to the declaration of the function or variable, and after all type checking has been done.</p>
53      *
54      * @param opt the optimizer in use. This provides access to supporting functions; it also allows
55      * different optimization strategies to be used in different circumstances.
56      * @param env the static context of the expression
57      * @param contextItemType the static type of "." at the point where this expression is invoked.
58      * The parameter is set to null if it is known statically that the context item will be undefined.
59      * If the type of the context item is not known statically, the argument is set to
60      * {@link net.sf.saxon.type.Type#ITEM_TYPE}
61      * @return the original expression, rewritten if appropriate to optimize execution
62      * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
63      * (typically a type error)
64      */

65
66     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
67         operand0 = operand0.optimize(opt, env, contextItemType);
68         operand1 = operand1.optimize(opt, env, contextItemType);
69
70         if (operand0 instanceof IntegerValue && operand1 instanceof IntegerValue) {
71             long i0 = ((IntegerValue)operand0).longValue();
72             long i1 = ((IntegerValue)operand1).longValue();
73             if (i0 > i1) {
74                 return EmptySequence.getInstance();
75             } else {
76                 return new IntegerRange(i0, i1);
77             }
78         }
79         return this;
80
81     }
82
83
84     /**
85     * Get the data type of the items returned
86     */

87
88     public ItemType getItemType() {
89         return Type.INTEGER_TYPE;
90     }
91
92     /**
93     * Determine the static cardinality
94     */

95
96     public int computeCardinality() {
97         return StaticProperty.ALLOWS_ZERO_OR_MORE;
98     }
99
100     /**
101     * Return an iteration over the sequence
102     */

103
104     public SequenceIterator iterate(XPathContext context) throws XPathException {
105         AtomicValue av1 = (AtomicValue)operand0.evaluateItem(context);
106         if (av1 == null) {
107             return new EmptyIterator();
108         }
109         NumericValue v1 = (NumericValue)av1.getPrimitiveValue();
110
111         AtomicValue av2 = (AtomicValue)operand1.evaluateItem(context);
112         if (av2 == null) {
113             return new EmptyIterator();
114         }
115         NumericValue v2 = (NumericValue)av2.getPrimitiveValue();
116
117         if (v1.compareTo(v2) > 0) {
118             return new EmptyIterator();
119         }
120         return new RangeIterator(v1.longValue(), v2.longValue());
121     }
122
123     /**
124     * Iterator that produces numeric values in a monotonic sequence,
125     * ascending or descending. Although a range expression (N to M) is always
126      * in ascending order, applying the reverse() function will produce
127      * a RangeIterator that works in descending order.
128     */

129
130     public static class RangeIterator implements SequenceIterator,
131                                                   ReversibleIterator,
132                                                   LastPositionFinder,
133                                                   LookaheadIterator,
134                                                   GroundedIterator {
135
136         long start;
137         long currentValue;
138         int increment; // always +1 or -1
139
long limit;
140
141         public RangeIterator(long start, long end) {
142             this.start = start;
143             increment = (start <= end ? +1 : -1);
144             currentValue = start;
145             limit = end;
146         }
147
148         public boolean hasNext() {
149             if (increment>0) {
150                 return currentValue <= limit;
151             } else if (increment<0) {
152                 return currentValue >= limit;
153             } else {
154                 return false;
155             }
156         }
157
158         public Item next() {
159             if (!hasNext()) {
160                 increment = 0;
161                 return null;
162             }
163             long d = currentValue;
164             currentValue += increment;
165             return new IntegerValue(d);
166         }
167
168         public Item current() {
169             if (increment == 0) {
170                 return null;
171             } else {
172                 return new IntegerValue(currentValue - increment);
173             }
174         }
175
176         public int position() {
177             if (increment > 0) {
178                 return (int)(currentValue - start);
179             } else if (increment < 0) {
180                 return (int)(start - currentValue);
181             } else {
182                 return -1;
183             }
184         }
185
186         public int getLastPosition() {
187             return (int)((limit - start) * increment + 1);
188         }
189
190         public SequenceIterator getAnother() throws XPathException {
191             return new RangeIterator(start, limit);
192         }
193
194         /**
195          * Get properties of this iterator, as a bit-significant integer.
196          *
197          * @return the properties of this iterator. This will be some combination of
198          * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
199          * and {@link LOOKAHEAD}. It is always
200          * acceptable to return the value zero, indicating that there are no known special properties.
201          * It is acceptable for the properties of the iterator to change depending on its state.
202          */

203
204         public int getProperties() {
205             int props = LOOKAHEAD | LAST_POSITION_FINDER;
206             if (increment == 1) {
207                 props |= GROUNDED;
208             }
209             return props;
210         }
211
212         public SequenceIterator getReverseIterator() {
213             return new RangeIterator(limit, start);
214         }
215
216         /**
217          * Return a Value containing all the items in the sequence returned by this
218          * SequenceIterator. This should be an "in-memory" value, not a Closure.
219          *
220          * @return the corresponding Value
221          */

222
223         public Value materialize() throws XPathException {
224             if (increment == 1) {
225                 return new IntegerRange(start, limit);
226             } else {
227                 return new SequenceExtent(getAnother());
228             }
229         }
230     }
231 }
232
233 //
234
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
235
// you may not use this file except in compliance with the License. You may obtain a copy of the
236
// License at http://www.mozilla.org/MPL/
237
//
238
// Software distributed under the License is distributed on an "AS IS" basis,
239
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
240
// See the License for the specific language governing rights and limitations under the License.
241
//
242
// The Original Code is: all this file.
243
//
244
// The Initial Developer of the Original Code is Michael H. Kay
245
//
246
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
247
//
248
// Contributor(s): none.
249
//
250
Popular Tags