
net.sf.saxon.expr.instruct.GlobalVariable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Saxon-HE Show documentation
Show all versions of Saxon-HE Show documentation
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 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.Configuration;
import net.sf.saxon.Controller;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.GroundedValue;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.query.XQueryFunction;
import net.sf.saxon.query.XQueryFunctionLibrary;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trace.InstructionInfo;
import net.sf.saxon.trace.LocationKind;
import net.sf.saxon.trans.SymbolicName;
import net.sf.saxon.trans.Visibility;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.ManualIterator;
import net.sf.saxon.type.AnyItemType;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.TypeHierarchy;
import net.sf.saxon.value.IntegerValue;
import net.sf.saxon.value.SequenceExtent;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.SingletonClosure;
import java.util.*;
/**
* A compiled global variable in a stylesheet or query.
*/
public class GlobalVariable extends ComponentCode
implements Binding, net.sf.saxon.query.Declaration, InstructionInfo, ContextOriginator {
protected List references = new ArrayList(10);
// Note that variableReferences on this list might be dormant;
// that is, they might be disconnected from the live expression tree.
// References are maintained in XQuery but not in XSLT (where they are handled at the level of the
// XSLSourceBinding object)
private Expression select;
private StructuredQName variableQName;
private SequenceType requiredType;
private boolean indexed;
private boolean isPrivate = false;
private boolean isAssignable = false;
private GlobalVariable originalVariable;
private int binderySlotNumber;
private boolean isRequiredParam;
/**
* Create a global variable
*/
public GlobalVariable() {
}
/**
* 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;
setBody(select);
}
/**
* Get the symbolic name of the component
*
* @return the symbolic name
*/
@Override
public SymbolicName getSymbolicName() {
return new SymbolicName(StandardNames.XSL_VARIABLE, variableQName);
}
/**
* Set the expression to which this variable is bound
*
* @param select the initializing expression
*/
public void setSelectExpression(Expression select) {
this.select = select;
setBody(select);
}
/**
* 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;
}
/**
* Get the Configuration to which this Container belongs
*
* @return the Configuration
*/
private Configuration getConfiguration() {
return getPackageData().getConfiguration();
}
/**
* Say that this (XQuery) variable is a copy of some originally declared variable. It's a
* separate variable when imported into another module, but it retains the link
* to the original.
*
* @param var the variable in the imported module from which this variable is derived
*/
public void setOriginalVariable(GlobalVariable var) {
originalVariable = var;
}
/**
* Get the original declaration of this variable
*
* @return the variable in the imported module from which this variable is derived
*/
public GlobalVariable getOriginalVariable() {
return originalVariable;
}
/**
* Get the original declaration of this variable, or its original declaration, transitively
*
* @return the real variable declaration in some transitively imported module from which this variable is
* ultimately derived
*/
public GlobalVariable getUltimateOriginalVariable() {
if (originalVariable == null) {
return this;
} else {
return originalVariable.getUltimateOriginalVariable();
}
}
/**
* Say whether this variable is unused. Normally, unused variables are not
* compiled. However, in XSLT with debugging enabled (that is, with compileWithTracing
* set), dummy unused variables are created in respect of global variables that are
* declared but never referenced. These variables are included in the list
* of variables known to the Executable, but they are never evaluated, and do
* not have slot numbers allocated in the bindery.
* @param unused set to true if this global variable is to be marked as unused.
*/
public void setUnused(boolean unused) {
this.binderySlotNumber = -9234;
}
/**
* Ask whether this variable is unused. Normally, unused variables are not
* compiled. However, in XSLT with debugging enabled (that is, with compileWithTracing
* set), dummy unused variables are created in respect of global variables that are
* declared but never referenced. These variables are included in the list
* of variables known to the Executable, but they are never evaluated, and do
* not have slot numbers allocated in the bindery.
* @return true if this global variable is marked as unused.
*/
public boolean isUnused() {
return this.binderySlotNumber == -9234;
}
/**
* Ask whether this global variable is private
*
* @return true if this variable is private
*/
public boolean isPrivate() {
return isPrivate;
}
/**
* Say whether this global variable is private
*
* @param b true if this variable is external
*/
public void setPrivate(boolean b) {
isPrivate = b;
}
/**
* Indicate whether this variable is assignable using saxon:assign
*
* @param assignable true if this variable is assignable
*/
public void setAssignable(boolean assignable) {
isAssignable = assignable;
}
/**
* Test whether it is permitted to assign to the variable using the saxon:assign
* extension element. This will only be true if the extra attribute saxon:assignable="yes"
* is present.
*/
public final boolean isAssignable() {
return isAssignable;
}
/**
* Get the type of construct. This will either be the fingerprint of a standard XSLT instruction name
* (values in {@link net.sf.saxon.om.StandardNames}: all less than 1024)
* or it will be a constant in class {@link LocationKind}.
*
* @return an integer identifying the kind of construct
*/
public int getConstructType() {
return StandardNames.XSL_VARIABLE;
}
/**
* Get a name identifying the object of the expression, for example a function name, template name,
* variable name, key name, element name, etc. This is used only where the name is known statically.
*
* @return the QName of the object declared or manipulated by this instruction or expression
*/
public StructuredQName getObjectName() {
return getVariableQName();
}
/**
* Get the value of a particular property of the instruction. Properties
* of XSLT instructions are generally known by the name of the stylesheet attribute
* that defines them.
*
* @param name The name of the required property
* @return The value of the requested property, or null if the property is not available
*/
public Object getProperty(String name) {
return null;
}
/**
* Get an iterator over all the properties available. The values returned by the iterator
* will be of type String, and each string can be supplied as input to the getProperty()
* method to retrieve the value of the property. The iterator may return properties whose
* value is null.
*
* @return an iterator over the properties.
*/
public Iterator getProperties() {
List list = Collections.emptyList();
return list.iterator();
}
/**
* Get the host language (XSLT, XQuery, XPath) used to implement the code in this container
*
* @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY}
*/
public int getHostLanguage() {
return getPackageData().getHostLanguage();
}
/**
* Mark this as an indexed variable, to allow fast searching
*/
public void setIndexedVariable() {
indexed = true;
}
/**
* Ask whether this is an indexed variable
*
* @return true if this variable is indexed
*/
public boolean isIndexedVariable() {
return indexed;
}
/**
* The expression that initializes a global variable may itself use local variables.
* In this case a stack frame needs to be allocated while evaluating the global variable
*
* @param map The stack frame map for local variables used while evaluating this global
* variable.
*/
public void setContainsLocals(SlotManager map) {
setStackFrameMap(map);
}
/**
* Is this a global variable?
*
* @return true (yes, it is a global variable)
*/
public boolean isGlobal() {
return true;
}
/**
* Register a variable reference that refers to this global variable
*
* @param ref the variable reference
*/
public void registerReference(BindingReference ref) {
references.add(ref);
}
/**
* Iterate over the references to this variable
*
* @return an iterator over the references: returns objects of class {@link VariableReference}
*/
public Iterator iterateReferences() {
return references.iterator();
}
/**
* Get the slot number allocated to this variable in the Bindery
*
* @return the slot number, that is the position allocated to the variable within the Bindery
*/
public int getBinderySlotNumber() {
return binderySlotNumber;
}
/**
* Set the slot number of this variable in the Bindery
*
* @param s the slot number, that is, the position allocated to this variable within the Bindery
*/
public void setBinderySlotNumber(int s) {
if (!isUnused()) {
binderySlotNumber = s;
}
}
/**
* Indicate that this variable represents a required parameter
*
* @param requiredParam true if this is a required parameter
*/
public void setRequiredParam(boolean requiredParam) {
this.isRequiredParam = requiredParam;
}
/**
* Ask whether this variable represents a required parameter
*
* @return true if this variable represents a required parameter
*/
public boolean isRequiredParam() {
return this.isRequiredParam;
}
/**
* Create a compiled representation of this global variable
*
* @param exec the executable
* @param slot the slot number allocated to this variable
* @throws XPathException if compile-time errors are found.
*/
public void compile(/*@NotNull*/ Executable exec, int slot) throws XPathException {
// Not used in XSLT
// if (references.isEmpty()) {
// return;
// }
TypeHierarchy th = getConfiguration().getTypeHierarchy();
setBinderySlotNumber(slot);
if (this instanceof GlobalParam) {
setRequiredParam(select == null);
}
final SequenceType type = getRequiredType();
for (BindingReference ref : references) {
ref.fixup(this);
GroundedValue constantValue = null;
int properties = 0;
Expression select = getSelectExpression();
if (select instanceof Literal && !(this instanceof GlobalParam)) {
// we can't rely on the constant value because it hasn't yet been type-checked,
// which could change it (eg by numeric promotion). Rather than attempt all the type-checking
// now, we do a quick check. See test bug64
int relation = th.relationship(select.getItemType(), type.getPrimaryType());
if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY) {
constantValue = ((Literal) select).getValue();
}
}
if (select != null) {
properties = select.getSpecialProperties();
}
properties |= StaticProperty.NON_CREATIVE;
// a variable reference is non-creative even if its initializer is creative
ref.setStaticType(type, constantValue, properties);
}
//exec.registerGlobalVariable(this);
if (isRequiredParam()) {
exec.registerGlobalParameter((GlobalParam) this);
}
}
/**
* Type check the compiled representation of this global variable
*
* @param visitor an expression visitor
* @throws XPathException if compile-time errors are found.
*/
public void typeCheck(/*@NotNull*/ ExpressionVisitor visitor) throws XPathException {
Expression value = getSelectExpression();
if (value != null) {
value.checkForUpdatingSubexpressions();
if (value.isUpdatingExpression()) {
throw new XPathException(
"Initializing expression for global variable must not be an updating expression", "XUST0001");
}
RoleDiagnostic role = new RoleDiagnostic(
RoleDiagnostic.VARIABLE, getVariableQName().getDisplayName(), 0);
ContextItemStaticInfo cit = new ContextItemStaticInfo(AnyItemType.getInstance(), true);
Expression value2 = TypeChecker.strictTypeCheck(
value.simplify().typeCheck(visitor, cit),
getRequiredType(), role, visitor.getStaticContext());
value2 = value2.optimize(visitor, cit);
setSelectExpression(value2);
// the value expression may declare local variables
SlotManager map = getConfiguration().makeSlotManager();
int slots = ExpressionTool.allocateSlots(value2, 0, map);
if (slots > 0) {
setContainsLocals(map);
}
if (getRequiredType() == SequenceType.ANY_SEQUENCE && !(this instanceof GlobalParam)) {
// no type was declared; try to deduce a type from the value
try {
final ItemType itemType = value.getItemType();
final int cardinality = value.getCardinality();
setRequiredType(SequenceType.makeSequenceType(itemType, cardinality));
GroundedValue constantValue = null;
if (value2 instanceof Literal) {
constantValue = ((Literal) value2).getValue();
}
for (BindingReference reference : references) {
if (reference instanceof VariableReference) {
((VariableReference) reference).refineVariableType(
itemType, cardinality, constantValue, value.getSpecialProperties());
}
}
} catch (Exception err) {
// exceptions can happen because references to variables and functions are still unbound
}
}
}
}
/**
* Check for cycles in this variable definition
*
* @param referees the calls leading up to this one; it's an error if this variable is on the
* stack, because that means it calls itself directly or indirectly. The stack may contain
* variable definitions (GlobalVariable objects) and user-defined functions (UserFunction objects).
* It will never contain the same object more than once.
* @param globalFunctionLibrary the library containing all global functions
* @throws net.sf.saxon.trans.XPathException
* if cycles are found
*/
public void lookForCycles(Stack
© 2015 - 2025 Weber Informatics LLC | Privacy Policy