All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.expr.SimpleExpression Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.expr;

import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.expr.parser.PromotionOffer;
import net.sf.saxon.om.*;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.Type;
import net.sf.saxon.type.TypeHierarchy;

import java.util.Arrays;
import java.util.Iterator;


/**
 * An abstract implementation of Expression designed to make it easy to implement new expressions,
 * in particular, expressions to support extension instructions.
 *
 * 

An implementation of this class must supply the {@link Callable#call(XPathContext, net.sf.saxon.om.Sequence[])} * method to evaluate the expression and return its result.

*/ public abstract class SimpleExpression extends Expression implements Callable { public static final Expression[] NO_ARGUMENTS = new Expression[0]; protected Expression[] arguments = NO_ARGUMENTS; /** * Constructor */ public SimpleExpression() { } /** * Set the immediate sub-expressions of this expression. * * @param sub an array containing the sub-expressions of this expression */ public void setArguments(Expression[] sub) { arguments = sub; for (Expression aSub : sub) { adoptChildExpression(aSub); } } /** * Get the immediate sub-expressions of this expression. * * @return an array containing the sub-expressions of this expression */ /*@NotNull*/ public Iterator iterateSubExpressions() { return Arrays.asList(arguments).iterator(); } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; for (int i = 0; i < arguments.length; i++) { if (arguments[i] == original) { arguments[i] = replacement; found = true; } } return found; } /** * Simplify the expression * * @param visitor an expression visitor * @return the simplified expression */ /*@NotNull*/ public Expression simplify(ExpressionVisitor visitor) throws XPathException { for (int i = 0; i < arguments.length; i++) { if (arguments[i] != null) { arguments[i] = visitor.simplify(arguments[i]); } } return this; } /*@NotNull*/ public Expression typeCheck(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException { for (int i = 0; i < arguments.length; i++) { if (arguments[i] != null) { arguments[i] = visitor.typeCheck(arguments[i], contextItemType); } } return this; } /*@NotNull*/ public Expression optimize(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException { for (int i = 0; i < arguments.length; i++) { if (arguments[i] != null) { arguments[i] = visitor.optimize(arguments[i], contextItemType); } } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ /*@NotNull*/ public Expression copy() { throw new UnsupportedOperationException("SimpleExpression.copy()"); } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @param parent the parent of this expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws XPathException if any error is detected */ public Expression promote(PromotionOffer offer, Expression parent) throws XPathException { for (int i = 0; i < arguments.length; i++) { if (arguments[i] != null) { arguments[i] = doPromotion(arguments[i], offer); } } return this; } /** * Determine the data type of the items returned by this expression. This implementation * returns "item()", which can be overridden in a subclass. * * @param th the type hierarchy cache * @return the data type */ /*@NotNull*/ public ItemType getItemType(TypeHierarchy th) { return Type.ITEM_TYPE; } /** * Determine the static cardinality of the expression. This implementation * returns "zero or more", which can be overridden in a subclass. */ public int computeCardinality() { if ((getImplementationMethod() & Expression.EVALUATE_METHOD) == 0) { return StaticProperty.ALLOWS_ONE_OR_MORE; } else { return StaticProperty.ALLOWS_ZERO_OR_ONE; } } /** * Compute the dependencies of an expression, as the union of the * dependencies of its subexpressions. (This is overridden for path expressions * and filter expressions, where the dependencies of a subexpression are not all * propogated). This method should be called only once, to compute the dependencies; * after that, getDependencies should be used. * * @return the depencies, as a bit-mask */ public int computeDependencies() { return super.computeDependencies(); } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws XPathException if any dynamic error occurs evaluating the * expression */ public final Item evaluateItem(XPathContext context) throws XPathException { return call(context, evaluateArguments(context)).head(); } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws XPathException if any dynamic error occurs evaluating the * expression */ /*@NotNull*/ public final SequenceIterator iterate(XPathContext context) throws XPathException { return call(context, evaluateArguments(context)).iterate(); } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public final void process(XPathContext context) throws XPathException { SequenceIterator iter = call(context, evaluateArguments(context)).iterate(); Item it; while ((it = iter.next()) != null) { context.getReceiver().append(it, locationId, NodeInfo.ALL_NAMESPACES); } } /** * Internal method to evaluate the arguments prior to calling the generic call() method * @param context the XPath dynamic context * @return the values of the (evaluated) arguments * @throws XPathException if a dynamic error occurs */ private Sequence[] evaluateArguments(XPathContext context) throws XPathException { Sequence[] iters = new Sequence[arguments.length]; for (int i = 0; i < arguments.length; i++) { iters[i] = SequenceTool.toLazySequence(arguments[i].iterate(context)); } return iters; } /** * Get the subexpressions (arguments to this expression) * * @return the arguments, as an array */ public Expression[] getArguments() { return arguments; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("userExpression"); destination.emitAttribute("class", getExpressionType()); for (Expression argument : arguments) { argument.explain(destination); } destination.endElement(); } /** * Return a distinguishing name for the expression, for use in diagnostics. * By default the class name is used. * * @return a distinguishing name for the expression (defaults to the name of the implementation class) */ public String getExpressionType() { return getClass().getName(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy