All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.expr.instruct.LocalParamSetter Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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.expr.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.ErrorType;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.value.SequenceType;

/**
 * The compiled form of an xsl:param element within a template in an XSLT stylesheet. An xsl:param
 * element used as a template parameter is compiled into two objects: a LocalParam which represents the
 * parameter definition and the Binding for the value, and a LocalParamSetter which is an Instruction
 * to set a default value for the parameter if none has been supplied.
 * 

*

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".

*

*

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 net.sf.saxon.expr.instruct.GlobalParam}.

*

*

The LocalParam class is also used to represent parameters with the saxon:iterate instruction

*/ public final class LocalParamSetter extends Instruction { /*@NotNull*/ private LocalParam binding; public LocalParamSetter(/*@NotNull*/ LocalParam binding) { this.binding = binding; adoptOperands(); } private void adoptOperands() { if (binding != null) { Expression select = binding.getSelectExpression(); if (select != null) { select.setParentExpression(this); } Expression conversion = binding.getConversion(); if (conversion != null) { conversion.setParentExpression(this); } } } /** * Get the LocalParam element representing the binding for this parameter * * @return the binding element */ /*@NotNull*/ public LocalParam getBinding() { return binding; } /** * Get the item type of the items returned by evaluating this instruction * * @return the static item type of the instruction */ /*@NotNull*/ @Override public ItemType getItemType() { return ErrorType.getInstance(); } /** * Get the cardinality of the sequence returned by evaluating this instruction * * @return the static cardinality */ @Override public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return a set of flags indicating static properties of this expression */ @Override public int computeSpecialProperties() { return StaticProperty.HAS_SIDE_EFFECTS; } /** * Determine whether this instruction creates new nodes. * This implementation returns a default value of false * * @return true if the instruction creates new nodes (or if it can't be proved that it doesn't) */ @Override public boolean createsNewNodes() { return false; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * * * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression * rewriting */ /*@NotNull*/ @Override public Expression simplify() throws XPathException { Expression select = binding.getSelectExpression(); if (select != null) { Expression s2 = select.simplify(); binding.setSelectExpression(s2); adoptOperands(); } return this; } /** * Perform type checking of an expression and its subexpressions. This is the second phase of * static optimization. *

*

This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

*

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables may not be accurately known if they have not been explicitly declared.

*

*

If the implementation returns a value other than "this", then it is required to ensure that * the location information in the returned expression have been set up correctly. * It should not rely on the caller to do this, although for historical reasons many callers do so.

* * param visitor an expression visitor * @param contextInfo * @return the original expression, rewritten to perform necessary run-time type checks, * and to perform other type-related optimizations * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ /*@NotNull*/ @Override public Expression typeCheck(ExpressionVisitor visitor, ContextItemStaticInfo contextInfo) throws XPathException { Expression select = binding.getSelectExpression(); if (select != null) { binding.setSelectExpression(select.typeCheck(visitor, contextInfo)); } binding.checkAgainstRequiredType(visitor); adoptOperands(); return this; } /** * Perform optimisation of an expression and its subexpressions. This is the third and final * phase of static optimization. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ /*@NotNull*/ @Override public Expression optimize(ExpressionVisitor visitor, ContextItemStaticInfo contextItemType) throws XPathException { Expression select = binding.getSelectExpression(); if (select != null) { binding.setSelectExpression(select.optimize(visitor, contextItemType)); adoptOperands(); binding.computeEvaluationMode(); } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression * @param rebindings if a local variable is encountered whose binding is present in this * map, then the binding will be replaced with a new binding. */ /*@NotNull*/ @Override public Expression copy(RebindingMap rebindings) { LocalParam newBinding = binding.copy(rebindings); LocalParamSetter exp = new LocalParamSetter(newBinding); rebindings.put(binding, newBinding); ExpressionTool.copyLocationInfo(this, exp); return exp; } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_PARAM; } @Override public Iterable operands() { return binding.operands(this); } @Override public void adoptChildExpression(Expression child) { // no action (because of the unusual structure of this expression) } /** * Process the local parameter declaration */ public TailCall processLeavingTail(XPathContext context) throws XPathException { int slotNumber = binding.getSlotNumber(); int wasSupplied = context.useLocalParameter(binding.getVariableQName(), slotNumber, binding.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 Expression conversion = binding.getConversion(); int conversionEvaluationMode = binding.getConversionEvaluationMode(); if (conversion != null) { context.setLocalVariable(slotNumber, 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 (binding.isImplicitlyRequiredParam()) { String name = "$" + binding.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("XTDE0700"); throw e; } else if (binding.isRequiredParam()) { String name = "$" + binding.getVariableQName().getDisplayName(); XPathException e = new XPathException("No value supplied for required parameter " + name); e.setXPathContext(context); e.setErrorCode("XTDE0700"); throw e; } context.setLocalVariable(slotNumber, binding.getSelectValue(context)); } return null; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void export(ExpressionPresenter out) throws XPathException { out.startElement("param", this); out.emitAttribute("name", binding.getVariableQName()); out.emitAttribute("slot", "" + binding.getSlotNumber()); String flags = getFlags(); if (!flags.isEmpty()) { out.emitAttribute("flags", flags); } // if (binding.isTunnelParam()) { // out.emitAttribute("tunnel", "1"); // } if (binding.getRequiredType() != SequenceType.ANY_SEQUENCE) { out.emitAttribute("as", binding.getRequiredType().toString()); } if (binding.getSelectExpression() != null) { out.setChildRole("select"); binding.getSelectExpression().export(out); } Expression conversion = binding.getConversion(); if (conversion != null) { out.setChildRole("conversion"); conversion.export(out); } out.endElement(); } private String getFlags() { String flags = ""; if (binding.isTunnelParam()) { flags += "t"; } if (binding.isRequiredParam()) { flags += "r"; } if (binding.isImplicitlyRequiredParam()) { flags += "i"; } return flags; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy