KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.Controller;
4 import net.sf.saxon.expr.*;
5 import net.sf.saxon.om.AxisIterator;
6 import net.sf.saxon.om.SingletonIterator;
7 import net.sf.saxon.om.ValueRepresentation;
8 import net.sf.saxon.om.NamePool;
9 import net.sf.saxon.style.StandardNames;
10 import net.sf.saxon.trace.InstructionInfo;
11 import net.sf.saxon.trans.DynamicError;
12 import net.sf.saxon.trans.StaticError;
13 import net.sf.saxon.trans.XPathException;
14
15 import java.util.ArrayList JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Stack JavaDoc;
18
19 /**
20 * Handler for global variables in a stylesheet or query. <br>
21 */

22
23 public class GlobalVariable extends GeneralVariable implements Container {
24
25     private Executable executable;
26     private SlotManager stackFrameMap = null;
27
28     public Executable getExecutable() {
29         return executable;
30     }
31
32     public void setExecutable(Executable executable) {
33         this.executable = executable;
34     }
35
36     public void setContainsLocals(SlotManager map) {
37         this.stackFrameMap = map;
38     }
39
40     public boolean isGlobal() {
41         return true;
42     }
43
44     /**
45      * Check for cycles in this variable definition
46      * @param referees the calls leading up to this one; it's an error if this variable is on the
47      * stack, because that means it calls itself directly or indirectly. The stack may contain
48      * variable definitions (GlobalVariable objects) and user-defined functions (UserFunction objects).
49      * It will never contain the same object more than once.
50      */

51
52     public void lookForCycles(Stack JavaDoc referees) throws StaticError {
53         if (referees.contains(this)) {
54             int s = referees.indexOf(this);
55             referees.push(this);
56             String JavaDoc message = "Circular definition of global variable. ";
57             NamePool pool = executable.getConfiguration().getNamePool();
58             for (int i=s; i<referees.size()-1; i++) {
59                 if (referees.get(i+1) instanceof GlobalVariable) {
60                     GlobalVariable next = (GlobalVariable)referees.get(i+1);
61                     if (i==s) {
62                         message += '$' + getVariableName() + " uses $" + next.getVariableName();
63                     } else {
64                         message += ", which uses $" + next.getVariableName();
65                     }
66                 } else if (referees.get(i+1) instanceof UserFunction) {
67                     UserFunction next = (UserFunction)referees.get(i+1);
68                     message += ", which calls " + pool.getDisplayName(next.getFunctionNameCode()) + "()";
69                 }
70             }
71             message += '.';
72             StaticError err = new StaticError(message);
73             err.setErrorCode("XQST0054");
74             err.setLocator(this);
75             throw err;
76         }
77         if (select != null) {
78             referees.push(this);
79             List JavaDoc list = new ArrayList JavaDoc(10);
80             ExpressionTool.gatherReferencedVariables(select, list);
81             for (int i=0; i<list.size(); i++) {
82                 Binding b = (Binding)list.get(i);
83                 if (b instanceof GlobalVariable) {
84                     ((GlobalVariable)b).lookForCycles(referees);
85                 }
86             }
87             list.clear();
88             ExpressionTool.gatherCalledFunctions(select, list);
89             for (int i=0; i<list.size(); i++) {
90                 UserFunction f = (UserFunction)list.get(i);
91                 if (!referees.contains(f)) {
92                     // recursive function calls are allowed
93
lookForFunctionCycles(f, referees);
94                 }
95             }
96             referees.pop();
97         }
98     }
99
100     /**
101      * Look for cyclic variable references that go via one or more function calls
102      */

103
104     private static void lookForFunctionCycles(UserFunction f, Stack JavaDoc referees) throws StaticError {
105         Expression body = f.getBody();
106         referees.push(f);
107         List JavaDoc list = new ArrayList JavaDoc(10);
108         ExpressionTool.gatherReferencedVariables(body, list);
109         for (int i=0; i<list.size(); i++) {
110             Binding b = (Binding)list.get(i);
111             if (b instanceof GlobalVariable) {
112                 ((GlobalVariable)b).lookForCycles(referees);
113             }
114         }
115         list.clear();
116         ExpressionTool.gatherCalledFunctions(body, list);
117         for (int i=0; i<list.size(); i++) {
118             UserFunction fn = (UserFunction)list.get(i);
119             if (!referees.contains(fn)) {
120                 // recursive function calls are allowed
121
lookForFunctionCycles(fn, referees);
122             }
123         }
124         referees.pop();
125     }
126
127
128     /**
129     * Process the variable declaration
130     */

131
132     public TailCall processLeavingTail(XPathContext context) throws XPathException {
133
134         // This code is not used. A global variable is not really an instruction, although
135
// it is modelled as such, and it will be evaluated using the evaluateVariable() call
136
return null;
137     }
138
139     /**
140      * Evaluate the variable. That is,
141      * get the value of the select expression if present or the content
142      * of the element otherwise, either as a tree or as a sequence
143     */

144
145     public ValueRepresentation getSelectValue(XPathContext context) throws XPathException {
146         if (select==null) {
147             throw new AssertionError JavaDoc("*** No select expression for global variable!!");
148         } else {
149             XPathContextMajor c2 = context.newCleanContext();
150             c2.setOrigin(this);
151             AxisIterator initialNode = SingletonIterator.makeIterator(c2.getController().getPrincipalSourceDocument());
152             initialNode.next();
153             c2.setCurrentIterator(initialNode);
154             if (stackFrameMap != null) {
155                 c2.openStackFrame(stackFrameMap);
156             }
157             return ExpressionTool.lazyEvaluate(select, c2, 10);
158         }
159     }
160
161     /**
162     * Evaluate the variable
163     */

164
165     public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException {
166         Controller controller = context.getController();
167         Bindery b = controller.getBindery();
168
169         ValueRepresentation v = b.getGlobalVariableValue(this);
170
171         if (v != null) {
172             return v;
173         } else {
174
175             // This is the first reference to a global variable; try to evaluate it now.
176
// But first set a flag to stop looping. This flag is set in the Bindery because
177
// the VariableReference itself can be used by multiple threads simultaneously
178

179             try {
180                 b.setExecuting(this, true);
181                 ValueRepresentation value = getSelectValue(context);
182                 b.defineGlobalVariable(this, value);
183                 b.setExecuting(this, false);
184                 return value;
185
186             } catch (XPathException err) {
187                 b.setExecuting(this, false);
188                 if (err instanceof XPathException.Circularity) {
189                     DynamicError e = new DynamicError("Circular definition of variable " + getVariableName());
190                     int lang = context.getController().getExecutable().getHostLanguage();
191                     e.setErrorCode(lang == Configuration.XQUERY ? "XQST0054" : "XTDE0640");
192                     e.setXPathContext(context);
193                     // Detect it more quickly the next time (in a pattern, the error is recoverable)
194
select = new ErrorExpression(e);
195                     throw e;
196                 } else {
197                     throw err;
198                 }
199             }
200         }
201     }
202
203     /**
204      * Get InstructionInfo for this expression
205      */

206
207     public InstructionInfo getInstructionInfo() {
208         InstructionDetails details = new InstructionDetails();
209         details.setConstructType(StandardNames.XSL_VARIABLE);
210         details.setObjectNameCode(getVariableFingerprint());
211         details.setProperty("expression", this);
212         details.setSystemId(getSystemId());
213         details.setLineNumber(getLineNumber());
214         details.setColumnNumber(getColumnNumber());
215         return details;
216     }
217
218
219 }
220
221 //
222
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
223
// you may not use this file except in compliance with the License. You may obtain a copy of the
224
// License at http://www.mozilla.org/MPL/
225
//
226
// Software distributed under the License is distributed on an "AS IS" basis,
227
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
228
// See the License for the specific language governing rights and limitations under the License.
229
//
230
// The Original Code is: all this file.
231
//
232
// The Initial Developer of the Original Code is Michael H. Kay.
233
//
234
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
235
//
236
// Contributor(s): none.
237
//
238
Popular Tags