KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > instruct > Instruction


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.Controller;
4 import net.sf.saxon.value.Value;
5 import net.sf.saxon.event.SequenceOutputter;
6 import net.sf.saxon.event.SequenceReceiver;
7 import net.sf.saxon.expr.*;
8 import net.sf.saxon.om.*;
9 import net.sf.saxon.trace.InstructionInfo;
10 import net.sf.saxon.trans.DynamicError;
11 import net.sf.saxon.trans.XPathException;
12 import net.sf.saxon.type.ItemType;
13 import net.sf.saxon.type.Type;
14
15 import javax.xml.transform.SourceLocator JavaDoc;
16
17 /**
18 * Abstract superclass for all instructions in the compiled stylesheet.
19 * This represents a compiled instruction, and as such, the minimum information is
20 * retained from the original stylesheet. <br>
21 * Note: this class implements SourceLocator: that is, it can identify where in the stylesheet
22 * the source instruction was located.
23 */

24
25 public abstract class Instruction extends ComputedExpression implements SourceLocator JavaDoc, TailCallReturner {
26
27     /**
28     * Constructor
29     */

30
31     public Instruction() {}
32
33     /**
34      * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
35      * This method indicates which of these methods is prefered. For instructions this is the process() method.
36      */

37
38     public int getImplementationMethod() {
39         return Expression.PROCESS_METHOD;
40     }
41
42     /**
43     * Get the namecode of the instruction for use in diagnostics
44     */

45
46     public int getInstructionNameCode() {
47         return -1;
48     };
49
50     /**
51      * Get the item type of the items returned by evaluating this instruction
52      * @return the static item type of the instruction
53      */

54
55     public ItemType getItemType() {
56         return Type.ITEM_TYPE;
57     }
58
59     /**
60      * Get the cardinality of the sequence returned by evaluating this instruction
61      * @return the static cardinality
62      */

63
64     public int computeCardinality() {
65         return StaticProperty.ALLOWS_ZERO_OR_MORE;
66     }
67
68     /**
69     * ProcessLeavingTail: called to do the real work of this instruction. This method
70     * must be implemented in each subclass. The results of the instruction are written
71     * to the current Receiver, which can be obtained via the Controller.
72     * @param context The dynamic context of the transformation, giving access to the current node,
73     * the current variables, etc.
74     * @return null if the instruction has completed execution; or a TailCall indicating
75     * a function call or template call that is delegated to the caller, to be made after the stack has
76     * been unwound so as to save stack space.
77     */

78
79     public abstract TailCall processLeavingTail(XPathContext context) throws XPathException;
80
81     /**
82     * Process the instruction, without returning any tail calls
83     * @param context The dynamic context, giving access to the current node,
84     * the current variables, etc.
85     */

86
87     public void process(XPathContext context) throws XPathException {
88         TailCall tc = processLeavingTail(context);
89         while (tc != null) {
90             tc = tc.processLeavingTail(context);
91         }
92     }
93
94     /**
95      * Get a SourceLocator identifying the location of this instruction
96      */

97
98     public SourceLocator JavaDoc getSourceLocator() {
99         return this;
100     }
101
102     /**
103     * Construct an exception with diagnostic information. Note that this method
104     * returns the exception, it does not throw it: that is up to the caller.
105     * @param error The exception containing information about the error
106     * @param context The controller of the transformation
107     * @return an exception based on the supplied exception, but with location information
108     * added relating to this instruction
109     */

110
111     protected static XPathException dynamicError(SourceLocator JavaDoc loc, XPathException error, XPathContext context) {
112         if (error instanceof TerminationException) return error;
113         if (error.getLocator()==null ||
114                 (error.getLocator() instanceof ExpressionLocation &&
115                         context.getController().getExecutable().getHostLanguage() != Configuration.XQUERY) ||
116                 error.getLocator().getLineNumber()==-1) {
117             // If the exception has no location information, construct a new
118
// exception containing the required information
119
try {
120                 DynamicError de = new DynamicError(error.getMessage(),
121                                                 loc,
122                                                 error.getException());
123                 if (error instanceof DynamicError) {
124                     de.setErrorCode(error.getErrorCodeLocalPart());
125                     if (((DynamicError)error).getXPathContext()==null) {
126                         de.setXPathContext(context);
127                     } else {
128                         de.setXPathContext(((DynamicError)error).getXPathContext());
129                     }
130                 }
131                 return de;
132             } catch (Exception JavaDoc secondaryError) {
133                 // currently happens when running XQuery
134
return error;
135             }
136         }
137         return error;
138     }
139
140     /**
141     * Raise a dynamic error
142     * @param message An English text error message
143     * @param controller The controller of the transformation
144     * @return an exception containing details of the dynamic error
145     */

146
147     protected XPathException dynamicError(String JavaDoc message, Controller controller) {
148         return new DynamicError(message, getSourceLocator());
149     }
150
151     /**
152      * Assemble a ParameterSet. Method used by instructions that have xsl:with-param
153      * children. This method is used for the non-tunnel parameters.
154      */

155
156     protected static ParameterSet assembleParams(XPathContext context,
157                                                  WithParam[] actualParams)
158     throws XPathException {
159         if (actualParams == null || actualParams.length == 0) {
160             return null;
161         }
162         ParameterSet params = new ParameterSet(actualParams.length);
163         for (int i=0; i<actualParams.length; i++) {
164             params.put(actualParams[i].getVariableFingerprint(),
165                        actualParams[i].getSelectValue(context));
166         }
167         return params;
168     }
169
170     /**
171      * Assemble a ParameterSet. Method used by instructions that have xsl:with-param
172      * children. This method is used for the tunnel parameters.
173      */

174
175     protected static ParameterSet assembleTunnelParams(XPathContext context,
176                                                        WithParam[] actualParams)
177     throws XPathException {
178         ParameterSet existingParams = context.getTunnelParameters();
179         if (existingParams == null) {
180             return assembleParams(context, actualParams);
181         }
182         ParameterSet newParams = new ParameterSet(existingParams, (actualParams==null ? 0 : actualParams.length));
183         if (actualParams == null || actualParams.length == 0) {
184             return newParams;
185         }
186         for (int i=0; i<actualParams.length; i++) {
187             newParams.put(actualParams[i].getVariableFingerprint(),
188                           actualParams[i].getSelectValue(context));
189         }
190         return newParams;
191     }
192
193     /**
194      * Simplify an expression. This performs any static optimization (by rewriting the expression
195      * as a different expression). The default implementation does nothing.
196      *
197      * @exception net.sf.saxon.trans.XPathException if an error is discovered during expression
198      * rewriting
199      * @return the simplified expression
200      */

201
202      public abstract Expression simplify(StaticContext env) throws XPathException;
203
204     /**
205      * Get the static properties of this expression (other than its type). The result is
206      * bit-signficant. These properties are used for optimizations. In general, if
207      * property bit is set, it is true, but if it is unset, the value is unknown.
208      *
209      * @return a set of flags indicating static properties of this expression
210      */

211
212     public int computeSpecialProperties() {
213         int p = super.computeSpecialProperties();
214         if (createsNewNodes()) {
215             return p;
216         } else {
217             return p | StaticProperty.NON_CREATIVE;
218         }
219     }
220
221     /**
222      * Determine whether this instruction creates new nodes.
223      * This implementation returns a default value of false
224      */

225
226     public boolean createsNewNodes() {
227         return false;
228     }
229
230
231     /**
232      * Handle promotion offers, that is, non-local tree rewrites.
233      * @param offer The type of rewrite being offered
234      * @throws XPathException
235      */

236
237     protected void promoteInst(PromotionOffer offer) throws XPathException {
238     }
239
240     /**
241      * Offer promotion for this subexpression. The offer will be accepted if the subexpression
242      * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer.
243      * This method is always called at compile time.
244      *
245      * @param offer details of the offer, for example the offer to move
246      * expressions that don't depend on the context to an outer level in
247      * the containing expression
248      * @exception net.sf.saxon.trans.XPathException if any error is detected
249      * @return if the offer is not accepted, return this expression unchanged.
250      * Otherwise return the result of rewriting the expression to promote
251      * this subexpression
252      */

253
254     public Expression promote(PromotionOffer offer) throws XPathException {
255         Expression exp = offer.accept(this);
256         if (exp!=null) {
257             return exp;
258         } else {
259             promoteInst(offer);
260             return this;
261         }
262     }
263
264      /**
265      * Evaluate an expression as a single item. This always returns either a single Item or
266      * null (denoting the empty sequence). No conversion is done. This method should not be
267      * used unless the static type of the expression is a subtype of "item" or "item?": that is,
268      * it should not be called if the expression may return a sequence. There is no guarantee that
269      * this condition will be detected.
270      *
271      * @param context The context in which the expression is to be evaluated
272      * @exception XPathException if any dynamic error occurs evaluating the
273      * expression
274      * @return the node or atomic value that results from evaluating the
275      * expression; or null to indicate that the result is an empty
276      * sequence
277      */

278
279     public Item evaluateItem(XPathContext context) throws XPathException {
280         int m = getImplementationMethod();
281         if ((m & EVALUATE_METHOD) != 0) {
282                 dynamicError("evaluateItem() is not implemented in the subclass " + this.getClass(), context.getController());
283         } else if ((m & ITERATE_METHOD) != 0) {
284             return iterate(context).next();
285         } else {
286             Controller controller = context.getController();
287             XPathContext c2 = context.newMinorContext();
288             c2.setOrigin(this);
289             SequenceOutputter seq = new SequenceOutputter(1);
290             seq.setPipelineConfiguration(controller.makePipelineConfiguration());
291             c2.setTemporaryReceiver(seq);
292             process(c2);
293             seq.close();
294             return seq.getFirstItem();
295         }
296         return null;
297     }
298
299     /**
300      * Return an Iterator to iterate over the values of a sequence. The value of every
301      * expression can be regarded as a sequence, so this method is supported for all
302      * expressions. This default implementation handles iteration for expressions that
303      * return singleton values: for non-singleton expressions, the subclass must
304      * provide its own implementation.
305      *
306      * @exception XPathException if any dynamic error occurs evaluating the
307      * expression
308      * @param context supplies the context for evaluation
309      * @return a SequenceIterator that can be used to iterate over the result
310      * of the expression
311      */

312
313     public SequenceIterator iterate(XPathContext context) throws XPathException {
314         int m = getImplementationMethod();
315         if ((m & EVALUATE_METHOD) != 0) {
316             Item item = evaluateItem(context);
317             if (item==null) {
318                 return EmptyIterator.getInstance();
319             } else {
320                 return SingletonIterator.makeIterator(item);
321             }
322         } else if ((m & ITERATE_METHOD) != 0) {
323             dynamicError("iterate() is not implemented in the subclass " + this.getClass(), context.getController());
324         } else {
325             Controller controller = context.getController();
326             XPathContext c2 = context.newMinorContext();
327             c2.setOrigin(this);
328             SequenceOutputter seq = new SequenceOutputter();
329             seq.setPipelineConfiguration(controller.makePipelineConfiguration());
330             c2.setTemporaryReceiver(seq);
331             process(c2);
332             seq.close();
333             return seq.iterate();
334         }
335         return null;
336     }
337
338     /**
339      * Evaluate an expression as a String. This function must only be called in contexts
340      * where it is known that the expression will return a single string (or where an empty sequence
341      * is to be treated as a zero-length string). Implementations should not attempt to convert
342      * the result to a string, other than converting () to "". This method is used mainly to
343      * evaluate expressions produced by compiling an attribute value template.
344      *
345      * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the
346      * expression
347      * @exception java.lang.ClassCastException if the result type of the
348      * expression is not xs:string?
349      * @param context The context in which the expression is to be evaluated
350      * @return the value of the expression, evaluated in the current context.
351      * The expression must return a string or (); if the value of the
352      * expression is (), this method returns "".
353      */

354
355     public final String JavaDoc evaluateAsString(XPathContext context) throws XPathException {
356         Item item = evaluateItem(context);
357         if (item==null) {
358             return "";
359         } else {
360             return item.getStringValue();
361         }
362     }
363
364     /**
365      * Get the effective boolean value of the expression. This returns false if the value
366      * is the empty sequence, a zero-length string, a number equal to zero, or the boolean
367      * false. Otherwise it returns true.
368      *
369      * @param context The context in which the expression is to be evaluated
370      * @exception XPathException if any dynamic error occurs evaluating the
371      * expression
372      * @return the effective boolean value
373      */

374
375
376     public final boolean effectiveBooleanValue(XPathContext context) throws XPathException {
377         return ExpressionTool.effectiveBooleanValue(iterate(context));
378     }
379
380     public InstructionInfo getInstructionInfo() {
381         InstructionDetails details = new InstructionDetails();
382         details.setSystemId(getSystemId());
383         details.setLineNumber(getLineNumber());
384         details.setConstructType(getInstructionNameCode());
385         return details;
386     }
387
388     /**
389      * Static method to append an item that results from evaluating an expression to the current
390      * result receiver. The method checks to see whether the item returned from the expression is
391      * actually a function-call-package representing the result of a tail call optimization; if so,
392      * the tail function calls are complete and the final result is passed on.
393      * @param it the item: possibly a FunctionCallPackage
394      * @param out the Receiver
395      * @throws XPathException
396      */

397
398     public static void appendItem(Item it, SequenceReceiver out, int locationId) throws XPathException {
399         // If this call to xsl:sequence is in a template (rather than a function) it may
400
// be marked as a tail call; in this situation we need to evaluate the returned
401
// function call package. Doing so may return further function call packages, which also need
402
// to be processed. This has to be iterative rather than recursive to avoid consuming stack space.
403
while (true) {
404             if (it == null) {
405                 return;
406             } else if (it instanceof UserFunctionCall.FunctionCallPackage) {
407                 // the rather curious structure of this method came about by inlining the following
408
// commented-out line. It seems to work, but it's not clear that the nested loops are needed.
409
//it = (Item)((UserFunctionCall.FunctionCallPackage)it).appendTo(out);
410
UserFunctionCall.FunctionCallPackage fcp = (UserFunctionCall.FunctionCallPackage)it;
411                 ValueRepresentation v = fcp.call();
412                 SequenceIterator fv = Value.getIterator(v);
413                 while (true) {
414                     Item fvit = fv.next();
415                     if (fvit == null) {
416                         it = null;
417                         break;
418                     } else if (fvit instanceof UserFunctionCall.FunctionCallPackage) {
419                         it = fvit;
420                         break;
421                     } else {
422                         out.append(fvit, locationId, NodeInfo.ALL_NAMESPACES);
423                     }
424                 }
425                 // continue round the loop to unwind all recursive calls
426
} else {
427                 out.append(it, locationId, NodeInfo.ALL_NAMESPACES);
428                 return;
429             }
430         }
431     }
432
433     /**
434      * Establish whether this is an XSLT instruction or an XQuery instruction
435      * (used to produce appropriate diagnostics)
436      * @param context
437      * @return true for XSLT, false for XQuery
438      */

439     public boolean isXSLT(XPathContext context) {
440         return context.getController().getExecutable().getHostLanguage() == Configuration.XSLT;
441     }
442 }
443
444
445 //
446
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
447
// you may not use this file except in compliance with the License. You may obtain a copy of the
448
// License at http://www.mozilla.org/MPL/
449
//
450
// Software distributed under the License is distributed on an "AS IS" basis,
451
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
452
// See the License for the specific language governing rights and limitations under the License.
453
//
454
// The Original Code is: all this file.
455
//
456
// The Initial Developer of the Original Code is Michael H. Kay
457
//
458
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
459
//
460
// Contributor(s): none
461
//
Popular Tags