package client.net.sf.saxon.ce.style; import client.net.sf.saxon.ce.expr.Expression; import client.net.sf.saxon.ce.expr.Literal; import client.net.sf.saxon.ce.expr.StaticProperty; import client.net.sf.saxon.ce.expr.instruct.Executable; 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.LocalVariable; import client.net.sf.saxon.ce.pattern.NodeKindTest; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.type.TypeHierarchy; import client.net.sf.saxon.ce.value.SequenceType; /** * Handler for xsl:variable elements in stylesheet. <br> * The xsl:variable element has mandatory attribute name and optional attribute select */ public class XSLVariable extends XSLVariableDeclaration { private int state = 0; // 0 = before prepareAttributes() // 1 = during prepareAttributes() // 2 = after prepareAttributes() public void prepareAttributes() throws XPathException { if (state==2) return; if (state==1) { compileError("Circular reference to variable", "XTDE0640"); } state = 1; //System.err.println("Prepare attributes of $" + getVariableName()); super.prepareAttributes(); state = 2; } /** * Determine whether this node is an instruction. * @return true - it is an instruction (well, it can be, anyway) */ public boolean isInstruction() { return true; } /** * Get the static type of the variable. This is the declared type, unless the value * is statically known and constant, in which case it is the actual type of the value. */ public SequenceType getRequiredType() { // System.err.println("Get required type of $" + getVariableName()); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); SequenceType defaultType = (requiredType==null ? SequenceType.ANY_SEQUENCE : requiredType); if (requiredType != null) { return requiredType; } else if (select!=null) { if (Literal.isEmptySequence(select)) { // returning Type.EMPTY gives problems with static type checking return defaultType; } else { try { // try to infer the type from the select expression return SequenceType.makeSequenceType(select.getItemType(th), select.getCardinality()); } catch (Exception err) { // this may fail because the select expression references a variable or function // whose type is not yet known, because of forwards (perhaps recursive) references. return defaultType; } } } else if (hasChildNodes()) { return SequenceType.makeSequenceType(NodeKindTest.DOCUMENT, StaticProperty.EXACTLY_ONE); } else { // no select attribute or content: value is an empty string return SequenceType.SINGLE_STRING; } } /** * Compile: used only for global variables. * This method ensures space is available for local variables declared within * this global variable */ public Expression compile(Executable exec, Declaration decl) throws XPathException { if (references.isEmpty()) { redundant = true; } if (!redundant) { GeneralVariable inst; if (global) { inst = new GlobalVariable(); ((GlobalVariable)inst).setExecutable(getExecutable()); if (select != null) { select.setContainer(((GlobalVariable)inst)); } initializeInstruction(exec, decl, inst); inst.setVariableQName(getVariableQName()); inst.setSlotNumber(getSlotNumber()); inst.setRequiredType(getRequiredType()); fixupBinding(inst); inst.setContainer(((GlobalVariable)inst)); compiledVariable = inst; return inst; } else { throw new AssertionError("Local variable found when compiling a global variable"); } } return null; } public Expression compileLocalVariable(Executable exec, Declaration decl) throws XPathException { if (references.isEmpty()) { redundant = true; } if (!redundant) { GeneralVariable inst; if (global) { throw new AssertionError("Global variable found when compiling local variable"); } else { inst = new LocalVariable(); inst.setContainer(this); if (select != null) { select.setContainer(this); } initializeInstruction(exec, decl, inst); inst.setVariableQName(getVariableQName()); inst.setRequiredType(getRequiredType()); return inst; } } return null; } } // 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.