package client.net.sf.saxon.ce.style;
import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.expr.instruct.GeneralVariable;
import client.net.sf.saxon.ce.expr.instruct.GlobalVariable;
import client.net.sf.saxon.ce.expr.instruct.SlotManager;
import client.net.sf.saxon.ce.pattern.AnyNodeTest;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.type.TypeHierarchy;
import client.net.sf.saxon.ce.value.SequenceType;
import client.net.sf.saxon.ce.value.Value;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Generic class for xsl:variable and xsl:param elements. <br>
*/
public abstract class XSLVariableDeclaration
extends XSLGeneralVariable
implements VariableDeclaration, StylesheetProcedure {
// The slot number for the variable is allocated at this level (a) for global variables, and
// (b) for local parameters. For local variables, slot numbers are allocated only after an entire
// template or function has been compiled.
private int slotNumber = -9876; // initial value designed solely to show up when debugging
// List of VariableReference objects that reference this XSLVariableDeclaration
protected List references = new ArrayList(10);
/**
* Ask whether this node is a declaration, that is, a permitted child of xsl:stylesheet
* (including xsl:include and xsl:import).
* @return true for this element
*/
@Override
public boolean isDeclaration() {
return true;
}
/**
* 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;
}
/**
* Get the slot number allocated to this variable (its position in the stackframe)
* @return the allocated slot number
*/
public int getSlotNumber() {
return slotNumber;
}
/**
* Allocate a slot number to this variable
* @param slot the position of the variable on the local stack frame
*/
public void setSlotNumber(int slot) {
slotNumber = slot;
}
/**
* Get the static type of the variable.
* @return the static type declared for the variable
*/
public abstract SequenceType getRequiredType();
/**
* Method called by VariableReference to register the variable reference for
* subsequent fixup
*/
public void registerReference(VariableReference ref) {
references.add(ref);
}
/**
* Determine whether this node is an instruction.
* @return true - it is an instruction (well, it can be, anyway)
*/
public boolean isInstruction() {
return true;
}
/**
* Notify all references to this variable of the data type
*/
public void fixupReferences() throws XPathException {
final SequenceType type = getRequiredType();
final TypeHierarchy th = getConfiguration().getTypeHierarchy();
final Iterator iter = references.iterator();
while (iter.hasNext()) {
Value constantValue = null;
int properties = 0;
if (this instanceof XSLVariable) {
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();
}
}
((VariableReference)iter.next()).setStaticType(type, constantValue, properties);
}
super.fixupReferences();
}
/**
* Check that the variable is not already declared, and allocate a slot number
* @param decl
*/
public void validate(Declaration decl) throws XPathException {
super.validate(decl);
if (global) {
if (!redundant) {
slotNumber = getExecutable().getGlobalVariableMap().allocateSlotNumber(getVariableQName());
}
}
}
/**
* 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) {
Iterator iter = references.iterator();
while (iter.hasNext()) {
((VariableReference)iter.next()).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
}
protected void index(Declaration decl, PrincipalStylesheetModule top) throws XPathException {
top.indexVariableDeclaration(decl);
}
/**
* Optimize the stylesheet construct
* @param declaration
*/
public void optimize(Declaration declaration) throws XPathException {
if (global && !redundant && select!=null) {
Expression exp2 = select;
ExpressionVisitor visitor = makeExpressionVisitor();
Optimizer opt = getConfiguration().getOptimizer();
try {
if (opt.getOptimizationLevel() != Optimizer.NO_OPTIMIZATION) {
exp2 = exp2.optimize(visitor, AnyNodeTest.getInstance());
}
} catch (XPathException err) {
err.maybeSetLocation(this);
compileError(err);
}
// Try to extract new global variables from the body of the variable declaration
// (but don't extract the whole body!)
// if (opt.getOptimizationLevel() != Optimizer.NO_OPTIMIZATION) {
// exp2 = opt.promoteExpressionsToGlobal(exp2, visitor, true);
// }
// dropped because it doesn't seem to do much good - just splits up an expression
// into lots of small global variables.
allocateSlots(exp2);
if (slotManager != null && slotManager.getNumberOfVariables() > 0) {
((GlobalVariable)compiledVariable).setContainsLocals(slotManager);
}
if (exp2 != select) {
select = exp2;
compiledVariable.setSelectExpression(select);
}
}
}
/**
* Get the compiled variable
* @return the compiled variable if it has been compiled, or null otherwise
*/
public GeneralVariable getCompiledVariable() {
return compiledVariable;
}
}
// 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.