package client.net.sf.saxon.ce.expr; import client.net.sf.saxon.ce.Configuration; import client.net.sf.saxon.ce.expr.instruct.Executable; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.tree.util.SourceLocator; import client.net.sf.saxon.ce.type.ItemType; import java.util.Iterator; import java.util.Stack; /** * The ExpressionVisitor supports the various phases of processing of an expression tree which require * a recursive walk of the tree structure visiting each node in turn. In maintains a stack holding the * ancestor nodes of the node currently being visited. */ public class ExpressionVisitor { private Stack<Expression> stack; private Executable executable; private StaticContext staticContext; private Configuration configuration; /** * Create an ExpressionVisitor */ public ExpressionVisitor() { stack = new Stack<Expression>(); } private SourceLocator getLastLocator() { int stackSize = stack.size(); Expression[] expr = new Expression[stackSize]; stack.toArray(expr); SourceLocator result = null; for (int i = stackSize -1; i > -1; i--) { if (expr[i].sourceLocator != null) { return expr[i].sourceLocator; } } return result; } public String getLocation() { SourceLocator sl = getLastLocator(); String message = ""; if (sl != null) { message = sl.getLocation(); int pos = message.indexOf(" in "); if (pos > -1) { message = message.substring(0, pos); } } return message; } /** * Get the Saxon configuration * @return the Saxon configuration */ public Configuration getConfiguration() { return configuration; } /** * Set the Saxon configuration * @param configuration the Saxon configuration */ public void setConfiguration(Configuration configuration) { this.configuration = configuration; } /** * Get the Executable containing the expressions being visited * @return the Executable */ public Executable getExecutable() { return executable; } /** * Set the Executable containing the expressions being visited * @param executable the Executable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the static context for the expressions being visited. Note: this may not reflect all changes * in static context (e.g. namespace context, base URI) applying to nested expressions * @return the static context */ public StaticContext getStaticContext() { return staticContext; } /** * Set the static context for the expressions being visited. Note: this may not reflect all changes * in static context (e.g. namespace context, base URI) applying to nested expressions * @param staticContext the static context */ public void setStaticContext(StaticContext staticContext) { this.staticContext = staticContext; } /** * Factory method: make an expression visitor * @param env the static context * @return the new expression visitor */ public static ExpressionVisitor make(StaticContext env, Executable exec) { ExpressionVisitor visitor = new ExpressionVisitor(); visitor.setStaticContext(env); visitor.setExecutable(exec); visitor.setConfiguration(env.getConfiguration()); return visitor; } /** * Issue a warning message * @param message the message */ public void issueWarning(String message, SourceLocator locator) { staticContext.issueWarning(message, locator); } /** * Create a dynamic context suitable for early evaluation of constant subexpressions */ public XPathContext makeDynamicContext() { return staticContext.makeEarlyEvaluationContext(); } /** * Simplify an expression, via the ExpressionVisitor * @param exp the expression to be simplified * @return the simplified expression * @throws XPathException */ public Expression simplify(Expression exp) throws XPathException { if (exp != null) { stack.push(exp); Expression exp2 = exp.simplify(this); if (exp2 != exp) { ExpressionTool.copyLocationInfo(exp, exp2); } stack.pop(); return exp2; } else { return null; } } /** * Type check an expression, via the ExpressionVisitor * @param exp the expression to be typechecked * @param contextItemType the static type of the context item for this expression * @return the expression that results from type checking (this may be wrapped in expressions that * perform dynamic checking of the item type or cardinality, or that perform atomization or numeric * promotion) * @throws XPathException if static type checking fails, that is, if the expression cannot possibly * deliver a value of the required type */ public Expression typeCheck(Expression exp, ItemType contextItemType) throws XPathException { if (exp != null) { stack.push(exp); Expression exp2 = exp.typeCheck(this, contextItemType); if (exp2 != exp) { ExpressionTool.copyLocationInfo(exp, exp2); } stack.pop(); return exp2; } else { return null; } } /** * Optimize an expression, via the ExpressionVisitor * @param exp the expression to be typechecked * @param contextItemType the static type of the context item for this expression * @return the rewritten expression * @throws XPathException */ public Expression optimize(Expression exp, ItemType contextItemType) throws XPathException { if (exp != null) { stack.push(exp); Expression exp2 = exp.optimize(this, contextItemType); if (exp2 != exp) { ExpressionTool.copyLocationInfo(exp, exp2); } stack.pop(); return exp2; } else { return null; } } /** * Return true if the current expression at the top of the visitor's stack is evaluated repeatedly * when a given ancestor expression is evaluated once * @param ancestor the ancestor expression. May be null, in which case the search goes all the way * to the base of the stack. * @return true if the current expression is evaluated repeatedly */ public boolean isLoopingSubexpression(Expression ancestor) { int top = stack.size()-1; while (true) { if (top <= 0) { return false; } Expression parent = stack.get(top - 1); if (parent.hasLoopingSubexpression((stack.get(top)))) { return true; } if (parent == ancestor) { return false; } top--; } } /** * Reset the static properties for the current expression and for all its containing expressions. * This should be done whenever the expression is changed in a way that might * affect the properties. It causes the properties to be recomputed next time they are needed. */ public final void resetStaticProperties() { Iterator<Expression> up = stack.iterator(); while (up.hasNext()) { Expression exp = up.next(); exp.resetLocalStaticProperties(); } } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.