001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.*;
004: import net.sf.saxon.instruct.InstructionDetails;
005: import net.sf.saxon.instruct.SlotManager;
006: import net.sf.saxon.om.*;
007: import net.sf.saxon.trace.Location;
008: import net.sf.saxon.trans.DynamicError;
009: import net.sf.saxon.trans.IndependentContext;
010: import net.sf.saxon.trans.Variable;
011: import net.sf.saxon.trans.XPathException;
012: import net.sf.saxon.type.ItemType;
013: import net.sf.saxon.type.Type;
014: import net.sf.saxon.value.*;
015:
016: import java.util.Iterator;
017: import java.io.Serializable;
018:
019: /**
020: * This class implements the saxon:evaluate(), saxon:expression(), and saxon:eval() extension functions,
021: * which are specially-recognized by the system because they need access to parts of the static context
022: */
023:
024: public class Evaluate extends SystemFunction {
025:
026: // TODO: make saxon:expression into a data type rather than a function. The function then comes "for free"
027: // as a constructor function, but it also becomes possible to write things like
028: // <xsl:variable name="exp" as="saxon:expression">@price * @qty</xsl:variable>
029: // <xsl:value-of select="sum(//item, $exp)"/>
030:
031: IndependentContext staticContext;
032: // This staticContext is created at stylesheet compile time. It is therefore shared by all
033: // threads in which this stylesheet executes. Therefore it is immutable at run-time. When
034: // an XPath expression is compiled, a mutable copy of the staticContext is made.
035: InstructionDetails details;
036: public static final int EVALUATE = 0;
037: public static final int EXPRESSION = 1;
038: public static final int EVAL = 2;
039: public static final int EVALUATE_NODE = 3;
040:
041: /**
042: * Get the required type of the nth argument
043: */
044:
045: protected SequenceType getRequiredType(int arg) {
046: if (arg == 0) {
047: return super .getRequiredType(arg);
048: } else {
049: return SequenceType.ANY_SEQUENCE;
050: }
051: }
052:
053: /**
054: * Method supplied by each class of function to check arguments during parsing, when all
055: * the argument expressions have been read
056: */
057:
058: public void checkArguments(StaticContext env) throws XPathException {
059: if (staticContext == null) {
060: // only do this once
061: super .checkArguments(env);
062: if (operation == EVALUATE || operation == EXPRESSION) {
063: NamespaceResolver nsContext = env
064: .getNamespaceResolver();
065: staticContext = new IndependentContext(env
066: .getConfiguration());
067: staticContext.setBaseURI(env.getBaseURI());
068: staticContext.setImportedSchemaNamespaces(env
069: .getImportedSchemaNamespaces());
070: staticContext.setDefaultFunctionNamespace(env
071: .getDefaultFunctionNamespace());
072:
073: for (Iterator iter = nsContext.iteratePrefixes(); iter
074: .hasNext();) {
075: String prefix = (String) iter.next();
076: String uri = nsContext
077: .getURIForPrefix(prefix, true);
078: staticContext.declareNamespace(prefix, uri);
079: }
080: details = new InstructionDetails();
081: details.setConstructType(Location.SAXON_EVALUATE);
082: details.setSystemId(env.getLocationMap().getSystemId(
083: this .locationId));
084: details.setLineNumber(env.getLocationMap()
085: .getLineNumber(this .locationId));
086: } else if (operation == EVALUATE_NODE) {
087: // for saxon:evaluate-node() the static context of the expression is based
088: // on the node in the source document containing the expression.
089: staticContext = new IndependentContext(env
090: .getConfiguration());
091: }
092: }
093: }
094:
095: /**
096: * preEvaluate: for saxon:expression, if the expression is
097: * known at compile time, then it is compiled at compile time.
098: * In other cases this method suppresses compile-time evaluation by doing nothing
099: * (because the value of the expression depends on the runtime context).
100: */
101:
102: public Expression preEvaluate(StaticContext env)
103: throws XPathException {
104: if (operation == EXPRESSION) {
105: // compile-time evaluation of saxon:expression is allowed
106: if (argument[0] instanceof StringValue) {
107: PreparedExpression pexpr = new PreparedExpression();
108: //staticContext.setFunctionLibrary(env.getFunctionLibrary());
109: String exprText = ((StringValue) argument[0])
110: .getStringValue();
111: pexpr.variables = new Variable[10];
112: for (int i = 1; i < 10; i++) {
113: QNameValue qname = new QNameValue("", "", "p" + i,
114: null);
115: pexpr.variables[i - 1] = staticContext
116: .declareVariable(qname);
117: }
118: Expression expr = ExpressionTool.make(exprText,
119: staticContext, 0, Token.EOF, 1);
120:
121: ItemType contextItemType = Type.ITEM_TYPE;
122: expr = expr.typeCheck(staticContext, contextItemType);
123: pexpr.stackFrameMap = staticContext.getStackFrameMap();
124: ExpressionTool.allocateSlots(expr, pexpr.stackFrameMap
125: .getNumberOfVariables(), pexpr.stackFrameMap);
126: pexpr.expression = expr;
127: return new ObjectValue(pexpr);
128: }
129: }
130: // the other operations don't allow compile time evaluation because they need a run-time context
131: return this ;
132: }
133:
134: private PreparedExpression prepareExpression(XPathContext context)
135: throws XPathException {
136: if (operation == EVAL) {
137: Item item = argument[0].evaluateItem(context);
138: if (!(item instanceof ObjectValue)) {
139: dynamicError(
140: "First argument to saxon:eval must be an expression prepared using saxon:expression",
141: context);
142: return null;
143: }
144: ObjectValue obj = (ObjectValue) item;
145: Object v = obj.getObject();
146: if (!(v instanceof PreparedExpression)) {
147: dynamicError(
148: "First argument to saxon:eval must be an expression prepared using saxon:expression",
149: context);
150: return null;
151: }
152: return (PreparedExpression) v;
153:
154: }
155:
156: PreparedExpression pexpr = new PreparedExpression();
157: String exprText;
158: if (operation == EVALUATE_NODE) {
159: NodeInfo node = (NodeInfo) argument[0]
160: .evaluateItem(context);
161: IndependentContext env = staticContext.copy();
162: pexpr.expStaticContext = env;
163: env.setBaseURI(node.getBaseURI());
164: env
165: .setFunctionLibrary(getExecutable()
166: .getFunctionLibrary());
167: env.setNamespaces(node);
168: exprText = node.getStringValue();
169: AxisIterator single = SingletonIterator.makeIterator(node);
170: single.next();
171: context.setCurrentIterator(single);
172: Expression expr;
173: try {
174: expr = ExpressionTool.make(exprText, env, 0, Token.EOF,
175: 1);
176: } catch (XPathException e) {
177: String name = context.getNamePool().getDisplayName(
178: getFunctionNameCode());
179: DynamicError err = new DynamicError(
180: "Static error in XPath expression supplied to "
181: + name + ": " + e.getMessage().trim());
182: err.setXPathContext(context);
183: throw err;
184: }
185: ItemType contextItemType = Type.ITEM_TYPE;
186: expr = expr.typeCheck(env, contextItemType);
187: pexpr.stackFrameMap = env.getStackFrameMap();
188: ExpressionTool.allocateSlots(expr, pexpr.stackFrameMap
189: .getNumberOfVariables(), pexpr.stackFrameMap);
190: pexpr.expression = expr;
191: if (expr instanceof ComputedExpression) {
192: ((ComputedExpression) expr).setParentExpression(this );
193: }
194: return pexpr;
195:
196: }
197:
198: AtomicValue exprSource = (AtomicValue) argument[0]
199: .evaluateItem(context);
200: exprText = exprSource.getStringValue();
201: IndependentContext env = staticContext.copy();
202: env.setFunctionLibrary(getExecutable().getFunctionLibrary());
203: pexpr.expStaticContext = env;
204: pexpr.variables = new Variable[10];
205: for (int i = 1; i < 10; i++) {
206: QNameValue qname = new QNameValue("", "", "p" + i, null);
207: pexpr.variables[i - 1] = env.declareVariable(qname);
208: }
209:
210: Expression expr;
211: try {
212: expr = ExpressionTool.make(exprText, env, 0, Token.EOF, 1);
213: } catch (XPathException e) {
214: String name = context.getNamePool().getDisplayName(
215: getFunctionNameCode());
216: DynamicError err = new DynamicError(
217: "Static error in XPath expression supplied to "
218: + name + ": " + e.getMessage().trim());
219: err.setXPathContext(context);
220: throw err;
221: }
222: ItemType contextItemType = Type.ITEM_TYPE;
223: expr = expr.typeCheck(env, contextItemType);
224: pexpr.stackFrameMap = env.getStackFrameMap();
225: ExpressionTool.allocateSlots(expr, pexpr.stackFrameMap
226: .getNumberOfVariables(), pexpr.stackFrameMap);
227: pexpr.expression = expr;
228:
229: return pexpr;
230: }
231:
232: /**
233: * Evaluate in a general context
234: */
235:
236: public Item evaluateItem(XPathContext c) throws XPathException {
237: if (operation == EXPRESSION) {
238: PreparedExpression pexpr = prepareExpression(c);
239: return new ObjectValue(pexpr);
240: } else if (operation == EVALUATE_NODE) {
241: XPathContextMajor c2 = c.newCleanContext();
242: PreparedExpression pexpr = prepareExpression(c2);
243: c2.setOrigin(details);
244: c2.openStackFrame(pexpr.stackFrameMap);
245: return pexpr.expression.evaluateItem(c2);
246: } else {
247: PreparedExpression pexpr = prepareExpression(c);
248: for (int i = 1; i < argument.length; i++) {
249: pexpr.variables[i - 1].setXPathValue(ExpressionTool
250: .eagerEvaluate(argument[i], c));
251: }
252: XPathContextMajor c2 = c.newCleanContext();
253: c2.setOrigin(details);
254: c2.openStackFrame(pexpr.stackFrameMap);
255: c2.setCurrentIterator(c.getCurrentIterator());
256: return pexpr.expression.evaluateItem(c2);
257: }
258: }
259:
260: /**
261: * Iterate over the results of the function
262: */
263:
264: public SequenceIterator iterate(XPathContext c)
265: throws XPathException {
266: PreparedExpression pexpr = prepareExpression(c);
267:
268: if (operation == EXPRESSION) {
269: return SingletonIterator
270: .makeIterator(new ObjectValue(pexpr));
271: } else {
272: for (int i = 1; i < argument.length; i++) {
273: pexpr.variables[i - 1].setXPathValue(ExpressionTool
274: .eagerEvaluate(argument[i], c));
275: }
276: XPathContextMajor c2 = c.newCleanContext();
277: c2.setOrigin(details);
278: c2.openStackFrame(pexpr.stackFrameMap);
279: c2.setCurrentIterator(c.getCurrentIterator());
280: return Value.getIterator(ExpressionTool.lazyEvaluate(
281: pexpr.expression, c2, 1));
282: }
283: }
284:
285: /**
286: * Determine the dependencies
287: */
288:
289: public int getIntrinsicDependencies() {
290: return StaticProperty.DEPENDS_ON_FOCUS;
291: }
292:
293: /**
294: * Inner class PreparedExpression represents a compiled XPath expression together
295: * with the standard variables $p1 .. $p9 available for use when the expression is
296: * evaluated
297: */
298:
299: public static class PreparedExpression implements Serializable {
300: public IndependentContext expStaticContext;
301: public Expression expression;
302: public Variable[] variables;
303: public SlotManager stackFrameMap;
304: }
305:
306: }
307:
308: //
309: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
310: // you may not use this file except in compliance with the License. You may obtain a copy of the
311: // License at http://www.mozilla.org/MPL/
312: //
313: // Software distributed under the License is distributed on an "AS IS" basis,
314: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
315: // See the License for the specific language governing rights and limitations under the License.
316: //
317: // The Original Code is: all this file.
318: //
319: // The Initial Developer of the Original Code is Michael H. Kay.
320: //
321: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
322: //
323: // Contributor(s): none.
324: //
|