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

net.sf.saxon.style.XSLLocalParam Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 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.DefaultedArgumentExpression;
import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.Literal;
import net.sf.saxon.expr.SuppliedParameterReference;
import net.sf.saxon.expr.instruct.LocalParam;
import net.sf.saxon.expr.instruct.SlotManager;
import net.sf.saxon.expr.instruct.UserFunction;
import net.sf.saxon.expr.instruct.UserFunctionParameter;
import net.sf.saxon.expr.parser.RoleDiagnostic;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.FunctionStreamability;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.util.Navigator;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.Whitespace;

import java.util.EnumSet;
import java.util.function.Supplier;

/**
 * An xsl:param element representing a local parameter (template or function parameter) in the stylesheet. 
* The xsl:param element has mandatory attribute name and optional attributes * select, required, as, ... */ public class XSLLocalParam extends XSLGeneralVariable { @SuppressWarnings("FieldMayBeFinal") private EnumSet permittedAttributes = EnumSet.of( SourceBinding.BindingProperty.TUNNEL, SourceBinding.BindingProperty.REQUIRED, SourceBinding.BindingProperty.SELECT, SourceBinding.BindingProperty.AS); /*@Nullable*/ Expression conversion = null; private int slotNumber = -9876; // initial value designed solely to show up when debugging private LocalParam compiledParam; private boolean prepared = false; /** * Ask whether this element contains a binding for a variable with a given name; and if it does, * return the source binding information * * @param name the variable name * @return the binding information if this element binds a variable of this name; otherwise null */ @Override public SourceBinding getBindingInformation(StructuredQName name) { if (name.equals(sourceBinding.getVariableQName())) { return sourceBinding; } else { return null; } } /** * Get the slot number allocated to this variable (its position in the stackframe) * * @return the allocated slot number */ public int getSlotNumber() { return slotNumber; } @Override protected void prepareAttributes() { if (!prepared) { prepared = true; sourceBinding.setProperty(SourceBinding.BindingProperty.PARAM, true); if (getParent() instanceof XSLFunction) { sourceBinding.setProperty(SourceBinding.BindingProperty.REQUIRED, true); if (getCompilation().getCompilerInfo().getXsltVersion() != 40) { permittedAttributes.remove(SourceBinding.BindingProperty.SELECT); sourceBinding.setProperty(SourceBinding.BindingProperty.DISALLOWS_CONTENT, true); } } sourceBinding.prepareAttributes(permittedAttributes); if (sourceBinding.hasProperty(SourceBinding.BindingProperty.TUNNEL) && !(getParent() instanceof XSLTemplate)) { compileError("For attribute 'tunnel' within an " + getParent().getDisplayName() + " parameter, the only permitted value is 'no'", "XTSE0020"); } if (getParent() instanceof XSLFunction) { int pos = getParameterPosition(); if (getCompilation().getCompilerInfo().getXsltVersion() >= 40) { UserFunction uf = ((XSLFunction)getParent()).getCompiledFunction(); if (pos < uf.getParameterDefinitions().length) { // (if not, something is wrong; it will be reported later) UserFunctionParameter ufp = new UserFunctionParameter(); uf.getParameterDefinitions()[pos] = ufp; ufp.setRequiredType(getRequiredType()); ufp.setVariableQName(getVariableQName()); ufp.setSlotNumber(getSlotNumber()); ufp.setRequired(isRequiredParam()); if (pos == 0 && uf.getDeclaredStreamability() != FunctionStreamability.UNCLASSIFIED) { ufp.setFunctionStreamability(uf.getDeclaredStreamability()); } Expression defaultVal = sourceBinding.getSelectExpression(); if (defaultVal == null && !sourceBinding.hasProperty(SourceBinding.BindingProperty.REQUIRED)) { defaultVal = new DefaultedArgumentExpression(); } ufp.setDefaultValueExpression(defaultVal); } } else { if (!sourceBinding.hasProperty(SourceBinding.BindingProperty.REQUIRED)) { compileError("For attribute 'required' within an " + getParent().getDisplayName() + " parameter, the only permitted value is 'yes'", "XTSE0020"); } } } } } private int getParameterPosition() { return Navigator.getNumberSimple(this, null) - 1; } public Supplier getDefaultValueExpressionSupplier() { if (!prepared) { prepareAttributes(); } return () -> { Expression select = sourceBinding.getSelectExpression(); return select == null ? Literal.makeEmptySequence() : select; }; } public void prepareTemplateSignatureAttributes() throws XPathException { if (!prepared) { sourceBinding.setProperty(SourceBinding.BindingProperty.PARAM, true); sourceBinding.prepareTemplateSignatureAttributes(); } } @Override public void validate(ComponentDeclaration decl) throws XPathException { StructuredQName name = sourceBinding.getVariableQName(); NodeInfo parent = getParent(); boolean isFunction = getParent() instanceof XSLFunction; if (!((parent instanceof StyleElement) && ((StyleElement) parent).mayContainParam())) { compileError("xsl:param must be immediately within a template, function or stylesheet", "XTSE0010"); } if (hasChildNodes() && isFunction && getCompilation().getCompilerInfo().getXsltVersion() != 40) { compileError("Function parameters cannot have a default value", "XTSE0760"); } // it must be a text node; allow it if all whitespace SequenceTool.supply(iterateAxis(AxisInfo.PRECEDING_SIBLING), (ItemConsumer) node -> { if (node instanceof XSLLocalParam) { if (name.equals(((XSLLocalParam) node).sourceBinding.getVariableQName())) { compileError("The name of the parameter (" + name + ") is not unique", "XTSE0580"); } if (isFunction && isRequiredParam() && !((XSLLocalParam) node).isRequiredParam()) { compileError("Parameter " + name + " is required, but an earlier parameter " + ((XSLLocalParam) node).sourceBinding.getVariableQName() + " is optional", "XTSE0761"); } } else if (node instanceof StyleElement && ((StyleElement) node).getFingerprint() != StandardNames.XSL_CONTEXT_ITEM) { compileError("xsl:param must not be preceded by other instructions", "XTSE0010"); } else { // it must be a text node; allow it if all whitespace if (!Whitespace.isAllWhite(node.getUnicodeStringValue())) { compileError("xsl:param must not be preceded by text", "XTSE0010"); } } }); SlotManager p = getContainingSlotManager(); if (p == null) { compileError("Local variable must be declared within a template or function", "XTSE0010"); } else { slotNumber = p.allocateSlotNumber(name); } if (sourceBinding.hasProperty(SourceBinding.BindingProperty.REQUIRED)) { if (sourceBinding.getSelectExpression() != null) { // NB, we do this test before setting the default select attribute compileError("The select attribute must be omitted when required='yes'", "XTSE0760"); } if (hasChildNodes()) { compileError("A parameter specifying required='yes' must have empty content", "XTSE0760"); } } super.validate(decl); } public boolean isTunnelParam() { return sourceBinding.hasProperty(SourceBinding.BindingProperty.TUNNEL); } public boolean isRequiredParam() { return sourceBinding.hasProperty(SourceBinding.BindingProperty.REQUIRED); } /** * Ask whether variables declared in an "uncle" element are visible. * @return false if this xsl:param is a child of xsl:function (new rule in 4.0 draft) */ protected boolean seesAvuncularVariables() { return !(getParent() instanceof XSLFunction); } @Override public void fixupReferences() throws XPathException { sourceBinding.fixupReferences(null); super.fixupReferences(); } @Override public Expression compile(Compilation exec, ComponentDeclaration decl) throws XPathException { // if (!"iterate".equals(getParent().getLocalPart()) && // sourceBinding.getReferences().size() == 0 && !sourceBinding.hasProperty(SourceBinding.REQUIRED)) { // return null; // } if (getParent() instanceof XSLFunction) { if (getCompilation().getCompilerInfo().getXsltVersion() >= 40 && !isRequiredParam()) { sourceBinding.handleSequenceConstructor(exec, decl); Expression selectExpression = sourceBinding.getSelectExpression(); if (selectExpression == null) { selectExpression = Literal.makeEmptySequence(); } int pos = getParameterPosition(); ((XSLFunction)getParent()).getCompiledFunction().getParameterDefinitions()[pos] .setDefaultValueExpression(selectExpression); } return null; } else { SequenceType declaredType = getRequiredType(); StructuredQName name = sourceBinding.getVariableQName(); int slot = getSlotNumber(); if (declaredType != null) { SuppliedParameterReference pref = new SuppliedParameterReference(slot); pref.setRetainedStaticContext(makeRetainedStaticContext()); pref.setLocation(allocateLocation()); Supplier role = () -> new RoleDiagnostic(RoleDiagnostic.PARAM, name.getDisplayName(), 0, "XTTE0590"); conversion = exec.getConfiguration().getTypeChecker(false).staticTypeCheck( pref, declaredType, role, makeExpressionVisitor()); } sourceBinding.handleSequenceConstructor(exec, decl); LocalParam binding = new LocalParam(); binding.setSelectExpression(sourceBinding.getSelectExpression()); binding.setConversion(conversion); binding.setVariableQName(name); binding.setSlotNumber(slot); binding.setRequiredType(getRequiredType()); binding.setRequiredParam(sourceBinding.hasProperty( SourceBinding.BindingProperty.REQUIRED)); binding.setImplicitlyRequiredParam( sourceBinding.hasProperty(SourceBinding.BindingProperty.IMPLICITLY_REQUIRED)); binding.setTunnel(sourceBinding.hasProperty(SourceBinding.BindingProperty.TUNNEL)); sourceBinding.fixupBinding(binding); return compiledParam = binding; } } public LocalParam getCompiledParam() { return compiledParam; } /** * Get the static type of the parameter. This is the declared type, because we cannot know * the actual value in advance. * @return the declared type (or @code {item()*} if no type is declared) */ public SequenceType getRequiredType() { SequenceType declaredType = sourceBinding.getDeclaredType(); if (declaredType != null) { return declaredType; } else { return SequenceType.ANY_SEQUENCE; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy