
net.sf.saxon.style.SourceBinding 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.style;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.instruct.DocumentInstr;
import net.sf.saxon.expr.instruct.Executable;
import net.sf.saxon.expr.instruct.GeneralVariable;
import net.sf.saxon.expr.instruct.SlotManager;
import net.sf.saxon.expr.parser.RoleLocator;
import net.sf.saxon.expr.parser.TypeChecker;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.*;
import net.sf.saxon.pattern.NodeKindTest;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.Type;
import net.sf.saxon.type.TypeHierarchy;
import net.sf.saxon.value.*;
import net.sf.saxon.value.StringValue;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class for xsl:variable and xsl:param elements.
*/
public class SourceBinding {
private StyleElement sourceElement;
private StructuredQName name;
private Expression select = null;
private SequenceType declaredType = null;
private SequenceType inferredType = null;
protected String constantText = null;
protected SlotManager slotManager = null; // used only for global variable declarations
protected GeneralVariable compiledVariable = null;
private boolean textonly;
private int properties;
public static final int PRIVATE = 1;
public static final int GLOBAL = 2;
public static final int PARAM = 4;
public static final int TUNNEL = 8;
public static final int REQUIRED = 16;
public static final int IMPLICITLY_REQUIRED = 32;
public static final int ASSIGNABLE = 64;
public static final int SELECT = 128;
public static final int AS = 256;
public static final int DISALLOWS_CONTENT = 512;
public static final int GROUP = 1024;
public static final int STATIC = 2048;
// List of VariableReference objects that reference this XSLVariableDeclaration
private List references = new ArrayList(10);
public SourceBinding(StyleElement sourceElement) {
this.sourceElement = sourceElement;
}
public void prepareAttributes(int permittedAttributes) throws XPathException {
AttributeCollection atts = sourceElement.getAttributeList();
String selectAtt = null;
String asAtt = null;
String requiredAtt = null;
String tunnelAtt = null;
String assignableAtt = null;
String staticAtt = null;
for (int a=0; a getReferences() {
return references;
}
/**
* Get the SlotManager associated with this stylesheet construct. The SlotManager contains the
* information needed to manage the local stack frames used by run-time instances of the code.
* @return the associated SlotManager object
*/
public SlotManager getSlotManager() {
return slotManager;
}
/**
* If the element contains a sequence constructor, convert this to an expression and assign it to the
* select attribute
* @param exec the executable
* @param decl the declaration being compiled
* @throws XPathException if a static error is found, for example a type error
*/
public void handleSequenceConstructor(Executable exec, Declaration decl) throws XPathException {
// handle the "temporary tree" case by creating a Document sub-instruction
// to construct and return a document node.
if (sourceElement.hasChildNodes()) {
if (declaredType==null) {
DocumentInstr doc = new DocumentInstr(textonly, constantText, sourceElement.getBaseURI());
Expression b = sourceElement.compileSequenceConstructor(
exec, decl, sourceElement.iterateAxis(AxisInfo.CHILD), true);
if (b == null) {
b = Literal.makeEmptySequence();
}
doc.setContentExpression(b);
select = doc;
} else {
select = sourceElement.compileSequenceConstructor(
exec, decl, sourceElement.iterateAxis(AxisInfo.CHILD), true);
if (select == null) {
select = Literal.makeEmptySequence();
}
try {
assert select != null;
select.setContainer(sourceElement);
RoleLocator role =
new RoleLocator(RoleLocator.VARIABLE, name.getDisplayName(), 0);
role.setErrorCode("XTTE0570");
//role.setSourceLocator(new ExpressionLocation(this));
select = sourceElement.makeExpressionVisitor().simplify(select);
select = TypeChecker.staticTypeCheck(select, declaredType, false, role, sourceElement.makeExpressionVisitor());
} catch (XPathException err) {
err.setLocator(sourceElement);
sourceElement.compileError(err);
select = new ErrorExpression(err);
}
}
}
}
/**
* Get the type actually declared for the attribute
* @return the type appearing in the "as" attribute, or null if the attribute was absent
*/
public SequenceType getDeclaredType() {
if (declaredType == null) {
// may be handling a forwards reference - see hof-038
String asAtt = sourceElement.getAttributeValue("", "as");
if (asAtt == null) {
return null;
} else {
try {
declaredType = sourceElement.makeSequenceType(asAtt);
} catch (XPathException err) {
// the error will be reported when we get round to processing the function declaration
}
}
}
return declaredType;
}
/**
* Get the select expression actually appearing in the variable declaration
* @return the select expression as it appears, or null if it is absent
*/
public Expression getSelectExpression() {
return select;
}
/**
* Get the best available static type of the variable.
* @param useContentRules set to true if the standard rules for xsl:variable and similar elements apply,
* whereby the element's contained sequence constructor substitutes for the select attribute
* @return the static type declared for the variable, or inferred from its initialization
*/
public SequenceType getInferredType(boolean useContentRules) {
if (inferredType != null) {
return inferredType;
}
if (hasProperty(PARAM) || hasProperty(ASSIGNABLE)) {
return (inferredType = (declaredType == null ? SequenceType.ANY_SEQUENCE : declaredType));
}
if (select != null) {
TypeHierarchy th = sourceElement.getConfiguration().getTypeHierarchy();
if (Literal.isEmptySequence(select)) {
// returning Type.EMPTY gives problems with static type checking
return (inferredType = (declaredType == null ? SequenceType.ANY_SEQUENCE : declaredType));
}
ItemType actual = select.getItemType(th);
int card = select.getCardinality();
if (declaredType != null) {
if (!th.isSubType(actual, declaredType.getPrimaryType())) {
actual = declaredType.getPrimaryType();
}
if (!Cardinality.subsumes(declaredType.getCardinality(), card)) {
card = declaredType.getCardinality();
}
}
inferredType = SequenceType.makeSequenceType(actual, card);
return inferredType;
}
if (useContentRules) {
if (sourceElement.hasChildNodes()) {
if (declaredType == null) {
return SequenceType.makeSequenceType(NodeKindTest.DOCUMENT, StaticProperty.EXACTLY_ONE);
} else {
return declaredType;
}
} else {
if (declaredType == null) {
// no select attribute or content: value is an empty string
return SequenceType.SINGLE_STRING;
} else {
return declaredType;
}
}
}
return declaredType;
}
/**
* Method called by VariableReference to register the variable reference for
* subsequent fixup
* @param ref the variable reference being registered
*/
public void registerReference(BindingReference ref) {
references.add(ref);
}
/**
* Notify all references to this variable of the data type
*/
public void fixupReferences() throws XPathException {
final SequenceType type = getInferredType(true);
final TypeHierarchy th = sourceElement.getConfiguration().getTypeHierarchy();
GroundedValue constantValue = null;
int properties = 0;
if (!hasProperty(ASSIGNABLE) && !hasProperty(PARAM)) {
if (select instanceof Literal) {
// 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(th), type.getPrimaryType());
if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY) {
constantValue = ((Literal) select).getValue();
}
}
if (select != null) {
properties = select.getSpecialProperties();
}
}
for (BindingReference reference : references) {
reference.setStaticType(type, constantValue, properties);
}
}
/**
* Notify all variable references of the Binding instruction
* @param binding the Binding that represents this variable declaration in the executable code tree
*/
protected void fixupBinding(Binding binding) {
for (BindingReference reference : references) {
(reference).fixup(binding);
}
}
/**
* Set the number of references to this variable. This code is invoked only for a global variable,
* and only if there is at least one reference.
* @param var the variable
*/
protected void setReferenceCount(GeneralVariable var) {
var.setReferenceCount(10); // TODO: temporary
}
/**
* Get the compiled variable
* @return the compiled variable if it has been compiled, or null otherwise
*/
/*@Nullable*/ public GeneralVariable getCompiledVariable() {
return compiledVariable;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy