KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > value > Closure


1 package net.sf.saxon.value;
2 import net.sf.saxon.event.SequenceReceiver;
3 import net.sf.saxon.expr.*;
4 import net.sf.saxon.om.*;
5 import net.sf.saxon.trace.Location;
6 import net.sf.saxon.trans.XPathException;
7 import net.sf.saxon.type.ItemType;
8 import net.sf.saxon.type.AnyItemType;
9
10 import java.io.PrintStream JavaDoc;
11
12 /**
13  * A Closure represents a value that has not yet been evaluated: the value is represented
14  * by an expression, together with saved values of all the context variables that the
15  * expression depends on.
16  *
17  * <p>This Closure is designed for use when the value is only read once. If the value
18  * is read more than once, a new iterator over the underlying expression is obtained
19  * each time: this may (for example in the case of a filter expression) involve
20  * significant re-calculation.</p>
21  *
22  * <p>The expression may depend on local variables and on the context item; these values
23  * are held in the saved XPathContext object that is kept as part of the Closure, and they
24  * will always be read from that object. The expression may also depend on global variables;
25  * these are unchanging, so they can be read from the Bindery in the normal way. Expressions
26  * that depend on other contextual information, for example the values of position(), last(),
27  * current(), current-group(), should not be evaluated using this mechanism: they should
28  * always be evaluated eagerly. This means that the Closure does not need to keep a copy
29  * of these context variables.</p>
30  *
31 */

32
33 public class Closure extends Value {
34
35     protected Expression expression;
36     protected XPathContextMajor savedXPathContext;
37     protected int depth = 0;
38
39     // The base iterator is used to copy items on demand from the underlying value
40
// to the reservoir. It only ever has one instance (for each Closure) and each
41
// item is read only once.
42

43     protected SequenceIterator inputIterator;
44
45 // private static int countClosures = 0;
46
// private static int countMemoClosures = 0;
47

48     /**
49      * Constructor should not be called directly, instances should be made using the make() method.
50      */

51
52     public Closure() {
53     }
54
55     /**
56      * Construct a Closure over an existing SequenceIterator. This is used when an extension function
57      * returns a SequenceIterator as its result (it replaces the old SequenceIntent class for this
58      * purpose). There is no known expression in this case. Note that the caller must
59      * ensure this is a "clean" iterator: it must be positioned at the start, and must
60      * not be shared by anyone else.
61      */

62
63     public static Closure makeIteratorClosure(SequenceIterator iterator) {
64         Closure c = new Closure();
65         c.inputIterator = iterator;
66         return c;
67     }
68
69     /**
70     * Construct a Closure by supplying the expression and the set of context variables.
71     */

72
73     public static Value make(Expression expression, XPathContext context, int ref) throws XPathException {
74
75         // Don't allow lazy evaluation of an ErrorExpression, the results are too confusing
76

77         if (expression instanceof ErrorExpression) {
78             expression.evaluateItem(context); // throws the exception
79
return null; // keep the compiler happy
80
}
81
82         // Treat tail recursion as a special case, to avoid creating a deeply-nested
83
// tree of Closures. If this expression is a TailExpression, and its first
84
// argument is also a TailExpression, we combine the two TailExpressions into
85
// one and return a closure over that.
86

87         if (expression instanceof TailExpression) {
88             TailExpression tail = (TailExpression)expression;
89             Expression base = tail.getBaseExpression();
90             if (base instanceof VariableReference) {
91                 base = Value.asValue(ExpressionTool.lazyEvaluate(base, context, ref));
92                 if (base instanceof MemoClosure) {
93                     SequenceIterator it = base.iterate(null);
94                     base = ((GroundedIterator)it).materialize();
95                 }
96                 if (base instanceof IntegerRange) {
97                     long start = ((IntegerRange)base).getStart() + 1;
98                     long end = ((IntegerRange)base).getEnd();
99                     if (start == end) {
100                         return new IntegerValue(end);
101                     } else {
102                         return new IntegerRange(start, end);
103                     }
104                 }
105                 if (base instanceof SequenceExtent) {
106                     return new SequenceExtent(
107                             (SequenceExtent)base,
108                             tail.getStart() - 1,
109                             ((SequenceExtent)base).getLength() - tail.getStart() + 1);
110                 }
111             }
112         }
113
114         Closure c = context.getController().getConfiguration().getOptimizer().makeClosure(expression, ref);
115         //Closure c = (save? new MemoClosure() : new Closure());
116
// if (save) {
117
// countMemoClosures++;
118
// if (countMemoClosures % 100 == 0) System.err.println("MEMO_CLOSURES " + countMemoClosures);
119
// } else {
120
// countClosures++;
121
// if (countClosures % 100 == 0) System.err.println("CLOSURES " + countClosures);
122
// }
123
c.expression = expression;
124         c.savedXPathContext = context.newContext();
125         c.savedXPathContext.setOriginatingConstructType(Location.LAZY_EVALUATION);
126
127         // Make a copy of all local variables. If the value of any local variable is a closure
128
// whose depth exceeds a certain threshold, we evaluate the closure eagerly to avoid
129
// creating deeply nested lists of Closures, which consume memory unnecessarily
130

131         // We only copy the local variables if the expression has dependencies on local variables.
132
// What's more, we only copy those variables that the expression actually depends on.
133

134         if (expression instanceof ComputedExpression &&
135                 (expression.getDependencies() & StaticProperty.DEPENDS_ON_LOCAL_VARIABLES) != 0) {
136             StackFrame localStackFrame = context.getStackFrame();
137             ValueRepresentation[] local = localStackFrame.getStackFrameValues();
138             int[] slotsUsed = ((ComputedExpression)expression).getSlotsUsed();
139             if (local != null) {
140                 ValueRepresentation[] savedStackFrame = new ValueRepresentation[local.length];
141                 for (int s=0; s<slotsUsed.length; s++) {
142                     int i = slotsUsed[s];
143                     if (local[i] instanceof Closure) {
144                         int cdepth = ((Closure)local[i]).depth;
145                         if (cdepth >= 10) {
146                             local[i] = ExpressionTool.eagerEvaluate((Closure)local[i], context);
147                         } else if (cdepth + 1 > c.depth) {
148                             c.depth = cdepth + 1;
149                         }
150                     }
151                     savedStackFrame[i] = local[i];
152                 }
153
154                 c.savedXPathContext.setStackFrame(localStackFrame.getStackFrameMap(), savedStackFrame);
155             }
156         }
157
158         // Make a copy of the context item
159
SequenceIterator currentIterator = context.getCurrentIterator();
160         if (currentIterator != null) {
161             Item contextItem = currentIterator.current();
162             AxisIterator single = SingletonIterator.makeIterator(contextItem);
163             single.next();
164             c.savedXPathContext.setCurrentIterator(single);
165             // we don't save position() and last() because we have no way
166
// of restoring them. So the caller must ensure that a Closure is not
167
// created if the expression depends on position() or last()
168
}
169
170         c.savedXPathContext.setReceiver(null);
171         return c;
172     }
173
174     /**
175     * Get the static item type
176     */

177
178     public ItemType getItemType() {
179         if (expression == null) {
180             return AnyItemType.getInstance();
181         } else {
182             return expression.getItemType();
183         }
184         // This is probably not used, because a Closure has no static existence
185
}
186
187     /**
188     * Get the cardinality
189     */

190
191     public int getCardinality() {
192         if (expression == null) {
193             return StaticProperty.ALLOWS_ZERO_OR_MORE;
194         } else {
195             return expression.getCardinality();
196         }
197     }
198
199     /**
200     * Get the static properties of this expression (other than its type). The result is
201     * bit-signficant. These properties are used for optimizations. In general, if
202     * property bit is set, it is true, but if it is unset, the value is unknown.
203     */

204
205     public int getSpecialProperties() {
206         if (expression == null) {
207             return StaticProperty.ALLOWS_ZERO_OR_MORE;
208         } else {
209             return expression.getSpecialProperties();
210         }
211     }
212
213     /**
214      * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
215      * This method indicates which of these methods is provided. This implementation provides both iterate() and
216      * process() methods natively.
217      */

218
219     public int getImplementationMethod() {
220         return ITERATE_METHOD | PROCESS_METHOD;
221     }
222
223     /**
224      * Evaluate the expression in a given context to return an iterator over a sequence
225      * @param context the evaluation context. This is ignored; we use the context saved
226      * as part of the Closure instead.
227     */

228
229     public SequenceIterator iterate(XPathContext context) throws XPathException {
230
231         if (inputIterator == null) {
232             inputIterator = expression.iterate(savedXPathContext);
233             return inputIterator;
234         } else {
235             // In an ideal world this shouldn't happen: if the value is needed more than once, we should
236
// have chosen a MemoClosure. In fact, this path is never taken when executing the standard
237
// test suite (April 2005). However, it provides robustness in case the compile-time analysis
238
// is flawed. I believe it's also possible that this path can be taken if a Closure needs to be
239
// evaluated when the chain of dependencies gets too long: this was happening routinely when
240
// all local variables were saved, rather than only those that the expression depends on.
241
return inputIterator.getAnother();
242         }
243
244     }
245
246     /**
247      * Process the instruction, without returning any tail calls
248      * @param context The dynamic context, giving access to the current node,
249      * the current variables, etc.
250      */

251
252     public void process(XPathContext context) throws XPathException {
253         // To evaluate the closure in push mode, we need to use the original context of the
254
// expression for everything except the current output destination, which is newly created
255
XPathContext c2 = savedXPathContext.newContext();
256         SequenceReceiver out = context.getReceiver();
257         c2.setTemporaryReceiver(out);
258         expression.process(c2);
259     }
260
261     /**
262      * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value
263      * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing
264      * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression
265      * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue
266      */

267
268     public Value reduce() throws XPathException {
269         return new SequenceExtent(iterate(null)).reduce();
270     }
271
272     /**
273      * Determine wither this Closure is indexable
274      */

275
276     public boolean isIndexable() {
277         return false;
278     }
279
280     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
281         out.println(ExpressionTool.indent(level) + "Closure of expression:");
282         expression.display(level+1, pool, out);
283     }
284
285 }
286
287 //
288
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
289
// you may not use this file except in compliance with the License. You may obtain a copy of the
290
// License at http://www.mozilla.org/MPL/
291
//
292
// Software distributed under the License is distributed on an "AS IS" basis,
293
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
294
// See the License for the specific language governing rights and limitations under the License.
295
//
296
// The Original Code is: all this file.
297
//
298
// The Initial Developer of the Original Code is Michael H. Kay.
299
//
300
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
301
//
302
// Contributor(s): none.
303
//
304
Popular Tags