package client.net.sf.saxon.ce.expr.instruct;
import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.om.StandardNames;
import client.net.sf.saxon.ce.om.ValueRepresentation;
import client.net.sf.saxon.ce.trans.XPathException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
/**
* The compiled form of an xsl:param element within a template in an XSLT stylesheet.
*
* <p>The xsl:param element in XSLT has mandatory attribute name and optional attribute select. It can also
* be specified as required="yes" or required="no".</p>
*
* <p>This is used only for parameters to XSLT templates. For function calls, the caller of the function
* places supplied arguments onto the callee's stackframe and the callee does not need to do anything.
* Global parameters (XQuery external variables) are handled using {@link GlobalParam}.</p>
*
*/
public final class LocalParam extends GeneralVariable {
private int parameterId;
private Expression conversion = null;
private int conversionEvaluationMode = ExpressionTool.UNDECIDED;
/**
* Allocate a number which is essentially an alias for the parameter name,
* unique within a stylesheet
* @param id the parameter id
*/
public void setParameterId(int id) {
parameterId = id;
}
/**
* Get the parameter id, which is essentially an alias for the parameter name,
* unique within a stylesheet
* @return the parameter id
*/
public int getParameterId() {
return parameterId;
}
/**
* Define a conversion that is to be applied to the supplied parameter value.
* @param convertor The expression to be applied. This performs type checking,
* and the basic conversions implied by function calling rules, for example
* numeric promotion, atomization, and conversion of untyped atomic values to
* a required type. The conversion uses the actual parameter value as input,
* referencing it using a VariableReference.
*/
public void setConversion(Expression convertor) {
conversion = convertor;
if (convertor != null) {
conversionEvaluationMode = ExpressionTool.eagerEvaluationMode(conversion);
}
}
/**
* Get the name of this instruction for diagnostic and tracing purposes
*/
public int getInstructionNameCode() {
return StandardNames.XSL_PARAM;
}
/**
* 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)
*/
public Iterator<Expression> iterateSubExpressions() {
if (select != null && conversion != null) {
return Arrays.asList((new Expression[]{select, conversion})).iterator();
} else if (select != null) {
return monoIterator(select);
} else if (conversion != null) {
return monoIterator(conversion);
} else {
return Collections.EMPTY_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;
}
if (conversion == original) {
conversion = replacement;
found = true;
}
return found;
}
/**
* Process the local parameter declaration
*/
public TailCall processLeavingTail(XPathContext context) throws XPathException {
int wasSupplied = context.useLocalParameter(getVariableQName(), this, isTunnelParam());
switch (wasSupplied) {
case ParameterSet.SUPPLIED_AND_CHECKED:
// No action needed
break;
case ParameterSet.SUPPLIED:
// if a parameter was supplied by the caller, with no type-checking by the caller,
// then we may need to convert it to the type required
if (conversion != null) {
context.setLocalVariable(getSlotNumber(),
ExpressionTool.evaluate(conversion, conversionEvaluationMode, context, 10));
// We do an eager evaluation here for safety, because the result of the
// type conversion overwrites the slot where the actual supplied parameter
// is contained.
}
break;
// don't evaluate the default if a value has been supplied or if it has already been
// evaluated by virtue of a forwards reference
case ParameterSet.NOT_SUPPLIED:
if (isImplicitlyRequiredParam()) {
String name = "$" + getVariableQName().getDisplayName();
XPathException e = new XPathException("A value must be supplied for parameter "
+ name + " because " +
"the default value is not a valid instance of the required type");
e.setXPathContext(context);
e.setErrorCode("XTDE0610");
throw e;
} else if (isRequiredParam()) {
String name = "$" + getVariableQName().getDisplayName();
XPathException e = new XPathException("No value supplied for required parameter " + name);
e.setXPathContext(context);
e.setErrorCode("XTDE0700");
throw e;
}
context.setLocalVariable(getSlotNumber(), getSelectValue(context));
}
return null;
}
/**
* Evaluate the variable
*/
public ValueRepresentation evaluateVariable(XPathContext c) {
return c.evaluateLocalVariable(slotNumber);
}
}
// 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.