net.sf.saxon.style.XSLFunction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of saxon-he Show documentation
Show all versions of saxon-he Show documentation
An OSGi bundle for Saxon-HE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 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.Configuration;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.instruct.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.SaxonErrorCode;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.Whitespace;
import java.util.ArrayList;
import java.util.List;
/**
* Handler for xsl:function elements in stylesheet (XSLT 2.0).
* Attributes:
* name gives the name of the function
* saxon:memo-function=yes|no indicates whether it acts as a memo function.
*/
public class XSLFunction extends StyleElement implements StylesheetProcedure {
/*@Nullable*/ private String nameAtt = null;
private String asAtt = null;
private String overrideAtt = null;
private SequenceType resultType;
private String functionName;
private SlotManager stackFrameMap;
private boolean memoFunction = false;
private boolean override = true;
private int numberOfArguments = -1; // -1 means not yet known
private UserFunction compiledFunction;
// List of UserFunctionCall objects that reference this XSLFunction
List references = new ArrayList(10);
/**
* Method called by UserFunctionCall to register the function call for
* subsequent fixup.
* @param ref the UserFunctionCall to be registered
*/
public void registerReference(UserFunctionReference ref) {
references.add(ref);
}
/**
* 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;
}
public void prepareAttributes() throws XPathException {
AttributeCollection atts = getAttributeList();
overrideAtt = "yes";
for (int a=0; a 0, tailCalls > 1);
compiledFunction.setBody(new TailCallLoop(compiledFunction));
}
// Generate byte code if appropriate
if (getConfiguration().isGenerateByteCode(Configuration.XSLT)) {
try {
Expression cbody = opt.compileToByteCode(compiledFunction.getBody(), nameAtt,
Expression.PROCESS_METHOD | Expression.ITERATE_METHOD);
if (cbody != null) {
compiledFunction.setBody(cbody);
}
} catch (Exception e) {
System.err.println("Failed while compiling function " + nameAtt);
e.printStackTrace();
throw new XPathException(e);
}
}
compiledFunction.computeEvaluationMode();
if (isExplaining()) {
exp2.explain(getConfiguration().getStandardErrorOutput());
}
}
/**
* Fixup all function references.
* @param compiledFunction the Instruction representing this function in the compiled code
* @throws XPathException if an error occurs.
*/
private void fixupInstruction(UserFunction compiledFunction)
throws XPathException {
ExpressionVisitor visitor = makeExpressionVisitor();
try {
for (UserFunctionReference reference : references) {
reference.setFunction(compiledFunction);
if (reference instanceof UserFunctionCall) {
UserFunctionCall call = (UserFunctionCall)reference;
call.checkFunctionCall(compiledFunction, visitor);
call.computeArgumentEvaluationModes();
}
}
} catch (XPathException err) {
compileError(err);
}
}
/**
* Get associated Procedure (for details of stack frame).
* @return the associated Procedure object
*/
public SlotManager getSlotManager() {
return stackFrameMap;
}
/**
* Get the type of value returned by this function
* @return the declared result type, or the inferred result type
* if this is more precise
*/
public SequenceType getResultType() {
if (resultType == null) {
// may be handling a forwards reference - see hof-038
String asAtt = getAttributeValue("", "as");
if (asAtt != null) {
try {
resultType = makeSequenceType(asAtt);
} catch (XPathException err) {
// the error will be reported when we get round to processing the function declaration
}
}
}
return resultType == null ? SequenceType.ANY_SEQUENCE : resultType;
}
/**
* Get the number of arguments declared by this function (that is, its arity).
* @return the arity of the function
*/
public int getNumberOfArguments() {
if (numberOfArguments == -1) {
numberOfArguments = 0;
AxisIterator kids = iterateAxis(AxisInfo.CHILD);
while (true) {
Item child = kids.next();
if (child instanceof XSLLocalParam) {
numberOfArguments++;
} else {
return numberOfArguments;
}
}
}
return numberOfArguments;
}
/**
* Set the definitions of the parameters in the compiled function, as an array.
* @param fn the compiled object representing the user-written function
*/
public void setParameterDefinitions(UserFunction fn) {
UserFunctionParameter[] params = new UserFunctionParameter[getNumberOfArguments()];
fn.setParameterDefinitions(params);
int count = 0;
AxisIterator kids = iterateAxis(AxisInfo.CHILD);
while (true) {
NodeInfo node = kids.next();
if (node == null) {
return;
}
if (node instanceof XSLLocalParam) {
UserFunctionParameter param = new UserFunctionParameter();
params[count++] = param;
param.setRequiredType(((XSLLocalParam)node).getRequiredType());
param.setVariableQName(((XSLLocalParam)node).getVariableQName());
param.setSlotNumber(((XSLLocalParam)node).getSlotNumber());
((XSLLocalParam)node).getSourceBinding().fixupBinding(param);
int refs = ExpressionTool.getReferenceCount(fn.getBody(), param, false);
param.setReferenceCount(refs);
}
}
}
/**
* Get the argument types
* @return the declared types of the arguments
*/
public SequenceType[] getArgumentTypes() {
SequenceType[] types = new SequenceType[getNumberOfArguments()];
int count = 0;
AxisIterator kids = iterateAxis(AxisInfo.CHILD);
while (true) {
NodeInfo node = kids.next();
if (node == null) {
return types;
}
if (node instanceof XSLLocalParam) {
types[count++] = (((XSLLocalParam)node).getRequiredType());
}
}
}
/**
* Get the compiled function
* @return the object representing the compiled user-written function
*/
public UserFunction getCompiledFunction() {
return compiledFunction;
}
/**
* Get the type of construct. This will be a constant in
* class {@link net.sf.saxon.trace.Location}. This method is part of the
* {@link net.sf.saxon.trace.InstructionInfo} interface
*/
public int getConstructType() {
return StandardNames.XSL_FUNCTION;
}
}