KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Controller;
3 import net.sf.saxon.expr.*;
4 import net.sf.saxon.om.*;
5 import net.sf.saxon.style.StandardNames;
6 import net.sf.saxon.trace.InstructionInfo;
7 import net.sf.saxon.trans.DynamicError;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.ItemType;
10
11 import java.io.PrintStream JavaDoc;
12 import java.util.ArrayList JavaDoc;
13 import java.util.Iterator JavaDoc;
14
15 /**
16 * Instruction representing an xsl:call-template element in the stylesheet.
17 */

18
19 public class CallTemplate extends Instruction {
20
21     private Template template = null;
22     private WithParam[] actualParams = null;
23     private WithParam[] tunnelParams = null;
24     private boolean useTailRecursion = false;
25     private Expression calledTemplateExpression; // allows name to be an AVT
26
private NamespaceResolver nsContext; // needed only for a dynamic call
27

28     /**
29     * Construct a CallTemplate instruction.
30     * @param template the Template object identifying the template to be called, in the normal
31     * case where this is known statically
32     * @param useTailRecursion
33     * @param calledTemplateExpression expression to calculate the name of the template to be called
34     * at run-time, this supports the saxon:allow-avt option
35     * @param nsContext the static namespace context of the instruction, needed only in the case
36     * where the name of the called template is to be calculated dynamically
37     */

38
39     public CallTemplate ( Template template,
40                             boolean useTailRecursion,
41                             Expression calledTemplateExpression,
42                             NamespaceResolver nsContext ) {
43
44         this.template = template;
45         this.useTailRecursion = useTailRecursion;
46         this.calledTemplateExpression = calledTemplateExpression;
47         this.nsContext = nsContext;
48         adoptChildExpression(calledTemplateExpression);
49     }
50
51    /**
52      * Set the actual parameters on the call
53      */

54
55     public void setActualParameters(
56                         WithParam[] actualParams,
57                         WithParam[] tunnelParams ) {
58         this.actualParams = actualParams;
59         this.tunnelParams = tunnelParams;
60         for (int i=0; i<actualParams.length; i++) {
61             adoptChildExpression(actualParams[i]);
62         }
63         for (int i=0; i<tunnelParams.length; i++) {
64             adoptChildExpression(tunnelParams[i]);
65         }
66     }
67
68     /**
69     * Return the name of this instruction.
70     */

71
72     public int getInstructionNameCode() {
73         return StandardNames.XSL_CALL_TEMPLATE;
74     }
75
76     /**
77      * Set additional trace properties appropriate to the kind of instruction. This
78      * implementation adds the template property, which identities the template to be called
79      */

80
81     public InstructionInfo getInstructionInfo() {
82         InstructionDetails details = (InstructionDetails)super.getInstructionInfo();
83         if (template != null) {
84             details.setProperty("template", template);
85         }
86         return details;
87     }
88
89     /**
90      * Simplify an expression. This performs any static optimization (by rewriting the expression
91      * as a different expression).
92      *
93      * @exception XPathException if an error is discovered during expression
94      * rewriting
95      * @return the simplified expression
96      */

97
98     public Expression simplify(StaticContext env) throws XPathException {
99         WithParam.simplify(actualParams, env);
100         WithParam.simplify(tunnelParams, env);
101         if (calledTemplateExpression != null) {
102             calledTemplateExpression = calledTemplateExpression.simplify(env);
103         }
104         return this;
105     }
106
107     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
108         WithParam.typeCheck(actualParams, env, contextItemType);
109         WithParam.typeCheck(tunnelParams, env, contextItemType);
110         if (calledTemplateExpression != null) {
111             calledTemplateExpression = calledTemplateExpression.typeCheck(env, contextItemType);
112             adoptChildExpression(calledTemplateExpression);
113         }
114         return this;
115     }
116
117     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
118         WithParam.optimize(opt, actualParams, env, contextItemType);
119         WithParam.optimize(opt, tunnelParams, env, contextItemType);
120         if (calledTemplateExpression != null) {
121             calledTemplateExpression = calledTemplateExpression.optimize(opt, env, contextItemType);
122             adoptChildExpression(calledTemplateExpression);
123         }
124         return this;
125     }
126
127     public int getIntrinsicDependencies() {
128         // we could go to the called template and find which parts of the context it depends on, but this
129
// would create the risk of infinite recursion. So we just assume that the dependencies exist
130
return StaticProperty.DEPENDS_ON_XSLT_CONTEXT |
131                 StaticProperty.DEPENDS_ON_FOCUS;
132     }
133
134     /**
135      * Determine whether this instruction creates new nodes.
136      * This implementation currently returns true unconditionally.
137      */

138
139     public final boolean createsNewNodes() {
140         return true;
141     }
142
143     /**
144      * Get all the XPath expressions associated with this instruction
145      * (in XSLT terms, the expression present on attributes of the instruction,
146      * as distinct from the child instructions in a sequence construction)
147      */

148
149     public Iterator JavaDoc iterateSubExpressions() {
150         ArrayList JavaDoc list = new ArrayList JavaDoc(10);
151         if (calledTemplateExpression != null) {
152             list.add(calledTemplateExpression);
153         }
154         WithParam.getXPathExpressions(actualParams, list);
155         WithParam.getXPathExpressions(tunnelParams, list);
156         return list.iterator();
157     }
158
159     /**
160      * Handle promotion offers, that is, non-local tree rewrites.
161      * @param offer The type of rewrite being offered
162      * @throws net.sf.saxon.trans.XPathException
163      */

164
165     protected void promoteInst(PromotionOffer offer) throws XPathException {
166         if (calledTemplateExpression != null) {
167             calledTemplateExpression = doPromotion(calledTemplateExpression, offer);
168         }
169         WithParam.promoteParams(actualParams, offer);
170         WithParam.promoteParams(tunnelParams, offer);
171     }
172
173     /**
174      * Process this instruction, without leaving any tail calls.
175      * @param context the dynamic context for this transformation
176      * @throws XPathException if a dynamic error occurs
177      */

178
179     public void process(XPathContext context) throws XPathException {
180
181         Template t = getTargetTemplate(context);
182         XPathContextMajor c2 = context.newContext();
183         c2.setOrigin(this);
184         c2.openStackFrame(t.getStackFrameMap());
185         c2.setLocalParameters(assembleParams(context, actualParams));
186         c2.setTunnelParameters(assembleTunnelParams(context, tunnelParams));
187
188         try {
189             TailCall tc = t.expand(c2);
190             while (tc != null) {
191                 tc = tc.processLeavingTail(c2);
192             }
193         } catch (StackOverflowError JavaDoc e) {
194             DynamicError err = new DynamicError(
195                     "Too many nested template or function calls. The stylesheet is probably looping.");
196             err.setLocator(this);
197             err.setXPathContext(context);
198             throw err;
199         }
200     }
201
202     /**
203     * Process this instruction. If the called template contains a tail call (which may be
204     * an xsl:call-template of xsl:apply-templates instruction) then the tail call will not
205     * actually be evaluated, but will be returned in a TailCall object for the caller to execute.
206     * @param context the dynamic context for this transformation
207     * @return an object containing information about the tail call to be executed by the
208     * caller. Returns null if there is no tail call.
209     */

210
211     public TailCall processLeavingTail(XPathContext context) throws XPathException
212     {
213         if (!useTailRecursion) {
214             process(context);
215             return null;
216         }
217
218         // if name is determined dynamically, determine it now
219

220         Template target = getTargetTemplate(context);
221
222         // handle parameters if any
223

224         ParameterSet params = assembleParams(context, actualParams);
225         ParameterSet tunnels = assembleTunnelParams(context, tunnelParams);
226
227         // Call the named template. Actually, don't call it; rather construct a call package
228
// and return it to the caller, who will then process this package.
229

230         //System.err.println("Call template using tail recursion");
231
if (params==null) { // bug 490967
232
params = ParameterSet.EMPTY_PARAMETER_SET;
233         }
234
235         // clear all the local variables: they are no longer needed
236
StackFrame frame = context.getStackFrame();
237         ValueRepresentation[] vars = frame.getStackFrameValues();
238         for (int i=0; i<vars.length; i++) {
239             vars[i] = null;
240         }
241
242         return new CallTemplatePackage(target, params, tunnels, context);
243     }
244
245     /**
246      * Get the template, in the case where it is specified dynamically.
247      * @param context The dynamic context of the transformation
248      * @return The template to be called
249      * @throws XPathException if a dynamic error occurs: specifically, if the
250      * template name is computed at run-time (Saxon extension) and the name is invalid
251      * or does not reference a known template
252      */

253
254     public Template getTargetTemplate(XPathContext context) throws XPathException {
255         if (calledTemplateExpression != null) {
256             Controller controller = context.getController();
257             String JavaDoc qname = calledTemplateExpression.evaluateAsString(context);
258
259             String JavaDoc prefix;
260             String JavaDoc localName;
261             try {
262                 String JavaDoc[] parts = Name.getQNameParts(qname);
263                 prefix = parts[0];
264                 localName = parts[1];
265             } catch (QNameException err) {
266                 throw dynamicError("Invalid template name. " + err.getMessage(), controller);
267             }
268             String JavaDoc uri = nsContext.getURIForPrefix(prefix, false);
269             if (uri==null) {
270                 throw dynamicError("Namespace prefix " + prefix + " has not been declared", controller);
271             }
272             int fprint = controller.getNamePool().getFingerprint(uri, localName);
273             Template target = controller.getExecutable().getNamedTemplate(fprint);
274             if (target==null) {
275                 throw dynamicError("Template " + qname + " has not been defined", controller);
276             }
277             return target;
278         } else {
279             return template;
280         }
281     }
282
283     /**
284      * Diagnostic print of expression structure. The expression is written to the System.err
285      * output stream
286      *
287      * @param level indentation level for this expression
288      * @param out
289      */

290
291     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
292         out.println(ExpressionTool.indent(level) + "call-template");
293     }
294
295     /**
296     * A CallTemplatePackage is an object that encapsulates the name of a template to be called,
297     * the parameters to be supplied, and the execution context. This object can be returned as a tail
298     * call, so that the actual call is made from a lower point on the stack, allowing a tail-recursive
299     * template to execute in a finite stack size
300     */

301
302     private class CallTemplatePackage implements TailCall {
303
304         private Template target;
305         private ParameterSet params;
306         private ParameterSet tunnelParams;
307         private XPathContext evaluationContext;
308
309         /**
310         * Construct a CallTemplatePackage that contains information about a call.
311         * @param template the Template to be called
312         * @param params the parameters to be supplied to the called template
313         * @param evaluationContext saved context information from the Controller (current mode, etc)
314         * which must be reset to ensure that the template is called with all the context information
315         * intact
316         */

317
318         public CallTemplatePackage(Template template,
319                                    ParameterSet params,
320                                    ParameterSet tunnelParams,
321                                    XPathContext evaluationContext) {
322             this.target = template;
323             this.params = params;
324             this.tunnelParams = tunnelParams;
325             this.evaluationContext = evaluationContext;
326         }
327
328         /**
329         * Process the template call encapsulated by this package.
330         * @param context the dynamic context for this transformation
331         * @return another TailCall. This will never be the original call, but it may be the next
332         * recursive call. For example, if A calls B which calls C which calls D, then B may return
333         * a TailCall to A representing the call from B to C; when this is processed, the result may be
334         * a TailCall representing the call from C to D.
335          * @throws XPathException if a dynamic error occurs
336         */

337
338         public TailCall processLeavingTail(XPathContext context) throws XPathException {
339             // TODO: the idea of tail call optimization is to reuse the caller's stack frame rather than
340
// creating a new one. We're doing this for the Java stack, but not for the context stack where
341
// local variables are held. It should be possible to avoid creating a new context, and instead
342
// to update the existing one in situ.
343
XPathContextMajor c2 = evaluationContext.newContext();
344             c2.setOrigin(CallTemplate.this);
345             c2.setLocalParameters(params);
346             c2.setTunnelParameters(tunnelParams);
347             c2.openStackFrame(target.getStackFrameMap());
348
349             // System.err.println("Tail call on template");
350

351             TailCall tc = target.expand(c2);
352             return tc;
353         }
354     }
355
356 }
357
358 //
359
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
360
// you may not use this file except in compliance with the License. You may obtain a copy of the
361
// License at http://www.mozilla.org/MPL/
362
//
363
// Software distributed under the License is distributed on an "AS IS" basis,
364
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
365
// See the License for the specific language governing rights and limitations under the License.
366
//
367
// The Original Code is: all this file.
368
//
369
// The Initial Developer of the Original Code is Michael H. Kay.
370
//
371
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
372
//
373
// Contributor(s): none.
374
//
375
Popular Tags