
net.sf.saxon.expr.instruct.GeneralVariable 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.instruct;
import net.sf.saxon.event.LocationProvider;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.parser.ExpressionTool;
import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.expr.parser.RoleLocator;
import net.sf.saxon.expr.parser.TypeChecker;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.IntegerValue;
import net.sf.saxon.value.SequenceType;
import javax.xml.transform.SourceLocator;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* This class defines common behaviour across xsl:variable, xsl:param, and xsl:with-param;
* also saxon:assign
*/
public abstract class GeneralVariable implements Binding, SourceLocator {
private static final int REQUIRED = 4;
private static final int TUNNEL = 8;
private static final int IMPLICITLY_REQUIRED = 16; // a parameter that is required because the fallback
// value is not a valid instance of the type.
private byte properties = 0;
Expression select = null;
protected StructuredQName variableQName;
SequenceType requiredType;
protected int slotNumber;
protected int referenceCount = 10;
protected int evaluationMode = ExpressionTool.UNDECIDED;
private Container container;
private int locationId = -1;
/**
* Create a general variable
*/
public GeneralVariable() {}
/**
* Initialize the properties of the variable
* @param select the expression to which the variable is bound
* @param qName the name of the variable
*/
public void init(Expression select, StructuredQName qName) {
this.select = select;
variableQName = qName;
//adoptChildExpression(select);
}
/**
* Mark a variable as being in a given Container. This link is used primarily for diagnostics:
* the container links to the location map held in the executable.
*
* This affects the expression and all its subexpressions. Any subexpressions that are not in the
* same container are marked with the new container, and this proceeds recursively. However, any
* subexpression that is already in the correct container is not modified.
*
* @param container The container of this expression.
*/
public void setContainer(Container container) {
this.container = container;
if (container != null) {
Iterator children = iterateSubExpressions();
while (children.hasNext()) {
Expression child = (Expression)children.next();
// child can be null while expressions are under construction
Container childContainer;
if (child != null &&
(childContainer = child.getContainer()) != container &&
(childContainer == null || childContainer.getContainerGranularity() < container.getContainerGranularity())) {
child.setContainer(container);
}
}
}
}
/**
* Get the container in which this expression is located. This will usually be a top-level construct
* such as a function or global variable, and XSLT template, or an XQueryExpression. In the case of
* free-standing XPath expressions it will be the StaticContext object
* @return the expression's container
*/
public Container getContainer() {
return container;
}
/**
* Set the location ID on an expression.
* @param id the location id
*/
public void setLocationId(int id) {
locationId = id;
}
/**
* Get the location ID of the expression
* @return a location identifier, which can be turned into real
* location information by reference to a location provider
*/
public final int getLocationId() {
return locationId;
}
/**
* Get the line number of the expression
*/
public int getLineNumber() {
if (locationId == -1) {
return -1;
}
return locationId & 0xfffff;
}
/**
* Get the column number of the expression
*/
public int getColumnNumber() {
return -1;
}
/**
* Get the systemId of the module containing the expression
*/
public String getSystemId() {
if (locationId == -1) {
return null;
}
Executable exec = getExecutable();
if (exec == null) {
return null;
}
LocationMap map = exec.getLocationMap();
if (map == null) {
return null;
}
return map.getSystemId(locationId);
}
/**
* Get the publicId of the module containing the expression (to satisfy the SourceLocator interface)
*/
public final String getPublicId() {
return null;
}
/**
* Get the executable containing this expression
* @return the containing Executable
*/
public Executable getExecutable() {
Container container = getContainer();
return container == null ? null : container.getExecutable();
}
/**
* Get the LocationProvider allowing location identifiers to be resolved.
* @return the LocationProvider used to turn the location id into real location information
*/
public LocationProvider getLocationProvider() {
Container container = getContainer();
return container == null ? null : container.getLocationProvider();
}
public String getSystemId(long locationId) {
return getLocationProvider().getSystemId(locationId);
}
// public int getLineNumber(long locationId) {
// return getLineNumber();
// }
//
// public int getColumnNumber(long locationId) {
// return getColumnNumber();
// }
/**
* Set the expression to which this variable is bound
* @param select the initializing expression
*/
public void setSelectExpression(Expression select) {
this.select = select;
evaluationMode = ExpressionTool.UNDECIDED;
}
/**
* Get the expression to which this variable is bound
* @return the initializing expression
*/
public Expression getSelectExpression() {
return select;
}
/**
* Set the required type of this variable
* @param required the required type
*/
public void setRequiredType(SequenceType required) {
requiredType = required;
}
/**
* Get the required type of this variable
* @return the required type
*/
public SequenceType getRequiredType() {
return requiredType;
}
/**
* If the variable is bound to an integer, get the minimum and maximum possible values.
* Return null if unknown or not applicable
*/
public IntegerValue[] getIntegerBoundsForVariable() {
if (select != null) {
return select.getIntegerBounds();
} else {
return null;
}
}
/**
* Indicate that this variable represents a required parameter
* @param requiredParam true if this is a required parameter
*/
public void setRequiredParam(boolean requiredParam) {
if (requiredParam) {
properties |= REQUIRED;
} else {
properties &= ~REQUIRED;
}
}
/**
* Indicate that this variable represents a parameter that is implicitly required (because there is no
* usable default value)
* @param requiredParam true if this is an implicitly required parameter
*/
public void setImplicitlyRequiredParam(boolean requiredParam) {
if (requiredParam) {
properties |= IMPLICITLY_REQUIRED;
} else {
properties &= ~IMPLICITLY_REQUIRED;
}
}
/**
* Indicate whether this variable represents a tunnel parameter
* @param tunnel true if this is a tunnel parameter
*/
public void setTunnel(boolean tunnel) {
if (tunnel) {
properties |= TUNNEL;
} else {
properties &= ~TUNNEL;
}
}
/**
* Set the nominal number of references to this variable
* @param refCount the nominal number of references
*/
public void setReferenceCount(int refCount) {
referenceCount = refCount;
}
/**
* Get the evaluation mode of the variable
* @return the evaluation mode (a constant in {@link ExpressionTool}
*/
public int getEvaluationMode() {
if (evaluationMode == ExpressionTool.UNDECIDED) {
if (referenceCount == FilterExpression.FILTERED) {
evaluationMode = ExpressionTool.MAKE_INDEXED_VARIABLE;
} else {
evaluationMode = ExpressionTool.lazyEvaluationMode(select);
}
}
return evaluationMode;
}
/**
* Get the cardinality of the result of this instruction. An xsl:variable instruction returns nothing, so the
* type is empty.
* @return the empty cardinality.
*/
public int getCardinality() {
return StaticProperty.EMPTY;
}
public boolean isAssignable() {
return false;
}
public boolean isGlobal() {
return false;
}
/**
* If this is a local variable held on the local stack frame, return the corresponding slot number.
* In other cases, return -1.
*/
public int getLocalSlotNumber() {
return slotNumber;
}
/**
* Ask whether this variable represents a required parameter
* @return true if this is a required parameter
*/
public final boolean isRequiredParam() {
return (properties & REQUIRED) != 0;
}
/**
* Ask whether this variable represents a parameter that is implicitly required, because there is no usable
* default value
* @return true if this variable is an implicitly required parameter
*/
public final boolean isImplicitlyRequiredParam() {
return (properties & IMPLICITLY_REQUIRED) != 0;
}
/**
* Ask whether this variable represents a tunnel parameter
* @return true if this is a tunnel parameter
*/
public final boolean isTunnelParam() {
return (properties & TUNNEL) != 0;
}
/**
* Get the name of this instruction (that is xsl:variable, xsl:param etc) for diagnostics
* @return the name of this instruction, as a name pool name code
*/
public int getInstructionNameCode() {
return StandardNames.XSL_VARIABLE;
}
/**
* Simplify this variable
* @param visitor an expression
* @throws XPathException if a failure occurs
*/
public void simplify(ExpressionVisitor visitor) throws XPathException {
if (select != null) {
select = visitor.simplify(select);
}
}
public void typeCheck(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException {
if (select != null) {
select = visitor.typeCheck(select, contextItemType);
//adoptChildExpression(select);
}
checkAgainstRequiredType(visitor);
}
public void optimize(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException {
if (select != null) {
select = visitor.optimize(select, contextItemType);
//adoptChildExpression(select);
computeEvaluationMode();
}
}
public void computeEvaluationMode() {
if (isAssignable()) {
evaluationMode = ExpressionTool.eagerEvaluationMode(select);
} else if (referenceCount == FilterExpression.FILTERED) {
evaluationMode = ExpressionTool.MAKE_INDEXED_VARIABLE;
} else {
evaluationMode = ExpressionTool.lazyEvaluationMode(select);
}
}
/**
* Copy an expression. This makes a deep copy.
*
* @return the copy of the original expression
*/
public Expression copy() {
throw new UnsupportedOperationException("GeneralVariable.copy()");
}
public void addReference(boolean isLoopingReference) {
}
/**
* Check the select expression against the required type.
* @param visitor an expression visitor
* @throws XPathException if the check fails
*/
public void checkAgainstRequiredType(ExpressionVisitor visitor)
throws XPathException {
// Note, in some cases we are doing this twice.
RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, variableQName, 0);
//role.setSourceLocator(this);
SequenceType r = requiredType;
if (r != null && select != null) {
// check that the expression is consistent with the required type
select = TypeChecker.staticTypeCheck(select, requiredType, false, role, visitor);
}
}
/**
* Evaluate the variable. That is,
* get the value of the select expression if present or the content
* of the element otherwise, either as a tree or as a sequence
* @param context the XPath dynamic context
* @return the result of evaluating the variable
* @throws net.sf.saxon.trans.XPathException if evaluation of the select expression fails
* with a dynamic error
*/
public Sequence getSelectValue(XPathContext context) throws XPathException {
if (select==null) {
throw new AssertionError("*** No select expression!!");
// The value of the variable is a sequence of nodes and/or atomic values
} else {
// There is a select attribute: do a lazy evaluation of the expression,
// which will already contain any code to force conversion to the required type.
return ExpressionTool.evaluate(select, evaluationMode, context, referenceCount);
}
}
/**
* Get all the XPath expressions associated with this instruction
* (in XSLT terms, the expression present on attributes of the instruction,
* as distinct from the child instructions in a sequence construction)
* @return an iterator over all the contained expressions (in practice,
* the select expression)
*/
public Iterator iterateSubExpressions() {
if (select != null) {
return new MonoIterator(select);
} else {
List list = Collections.emptyList();
return list.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;
if (select == original) {
select = replacement;
found = true;
}
return found;
}
/**
* Diagnostic print of expression structure. The abstract expression tree
* is written to the supplied output destination.
* @param out the object used to present the output
*/
public void explain(ExpressionPresenter out) {
out.startElement("variable");
out.emitAttribute("name", variableQName.getDisplayName());
if (select != null) {
select.explain(out);
}
out.endElement();
}
/**
* Get the slot number allocated to this variable
* @return the slot number, that is the position allocated to the variable on its stack frame
*/
public int getSlotNumber() {
return slotNumber;
}
/**
* Set the slot number of this variable
* @param s the slot number, that is, the position allocated to this variable on its stack frame
*/
public void setSlotNumber(int s) {
slotNumber = s;
}
/**
* Set the name of the variable
* @param s the name of the variable (a QName)
*/
public void setVariableQName(StructuredQName s) {
variableQName = s;
}
/**
* Get the name of this variable
* @return the name of this variable (a QName)
*/
public StructuredQName getVariableQName() {
return variableQName;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy