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

net.sf.saxon.instruct.UserFunction Maven / Gradle / Ivy

Go to download

Saxon a complete and conformant implementation of the XSLT 2.0, XQuery 1.0, and XPath 2.0 Recommendations published on 23 January 2007 by W3C

The newest version!
package net.sf.saxon.instruct;

import net.sf.saxon.Controller;
import net.sf.saxon.trace.Location;
import net.sf.saxon.evpull.EventIterator;
import net.sf.saxon.expr.*;
import net.sf.saxon.om.*;
import net.sf.saxon.sort.SortExpression;
import net.sf.saxon.sort.TupleSorter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import net.sf.saxon.type.TypeHierarchy;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.Value;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

/**
 * This object represents the compiled form of a user-written function
 * (the source can be either an XSLT stylesheet function or an XQuery function).
 *
 * 

It is assumed that type-checking, of both the arguments and the results, * has been handled at compile time. That is, the expression supplied as the body * of the function must be wrapped in code to check or convert the result to the * required type, and calls on the function must be wrapped at compile time to check or * convert the supplied arguments. */ public class UserFunction extends Procedure { private StructuredQName functionName; private boolean memoFunction = false; private boolean tailCalls = false; // indicates that the function contains tail calls, not necessarily recursive ones. private boolean tailRecursive = false; // indicates that the function contains tail calls on itself private UserFunctionParameter[] parameterDefinitions; private SequenceType resultType; private int evaluationMode = ExpressionTool.UNDECIDED; private boolean isUpdating = false; /** * Create a user-defined function with no body (the body must be added later) */ public UserFunction() {} /** * Create a user-defined function * @param body the expression comprising the body of the function, which is evaluated to compute the result * of the function */ public UserFunction(Expression body) { setBody(body); } /** * Set the function name * @param name the function name */ public void setFunctionName(StructuredQName name) { functionName = name; } /** * Get the function name * @return the function name, as a StructuredQName */ public StructuredQName getFunctionName() { return functionName; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. * */ public StructuredQName getObjectName() { return functionName; } /** * Determine the preferred evaluation mode for this function */ public void computeEvaluationMode() { if (tailRecursive || memoFunction) { // If this function contains tail calls, we evaluate it eagerly, because // the caller needs to know whether a tail call was returned or not: if we // return a Closure, the tail call escapes into the wild and can reappear anywhere... // Eager evaluation also makes sense if it's a memo function. evaluationMode = ExpressionTool.eagerEvaluationMode(getBody()); } else { evaluationMode = ExpressionTool.lazyEvaluationMode(getBody()); } } /** * Set the definitions of the declared parameters for this function * @param params an array of parameter definitions */ public void setParameterDefinitions(UserFunctionParameter[] params) { parameterDefinitions = params; } /** * Get the definitions of the declared parameters for this function * @return an array of parameter definitions */ public UserFunctionParameter[] getParameterDefinitions() { return parameterDefinitions; } /** * Set the declared result type of the function * @param resultType the declared return type */ public void setResultType(SequenceType resultType) { this.resultType = resultType; } /** * Indicate whether the function contains a tail call * @param tailCalls true if the function contains a tail call (on any function) * @param recursiveTailCalls true if the function contains a tail call (on itself) */ public void setTailRecursive(boolean tailCalls, boolean recursiveTailCalls) { this.tailCalls = tailCalls; tailRecursive = recursiveTailCalls; } /** * Determine whether the function contains tail calls (on this or other functions) * @return true if the function contains tail calls */ public boolean containsTailCalls() { return tailCalls; } /** * Determine whether the function contains a tail call, calling itself * @return true if the function contains a directly-recursive tail call */ public boolean isTailRecursive() { return tailRecursive; } /** * Set whether this is an updating function (as defined in XQuery Update) * @param isUpdating true if this is an updating function */ public void setUpdating(boolean isUpdating) { this.isUpdating = isUpdating; } /** * Ask whether this is an updating function (as defined in XQuery Update) * @return true if this is an updating function */ public boolean isUpdating() { return isUpdating; } /** * Get the type of value returned by this function * @param th the type hierarchy cache * @return the declared result type, or the inferred result type * if this is more precise */ public SequenceType getResultType(TypeHierarchy th) { if (resultType == SequenceType.ANY_SEQUENCE) { // see if we can infer a more precise result type. We don't do this if the function contains // calls on further functions, to prevent infinite regress. if (!containsUserFunctionCalls(getBody())) { resultType = SequenceType.makeSequenceType( getBody().getItemType(th), getBody().getCardinality()); } } return resultType; } /** * Determine whether a given expression contains calls on user-defined functions * @param exp the expression to be tested * @return true if the expression contains calls to user functions. */ private static boolean containsUserFunctionCalls(Expression exp) { if (exp instanceof UserFunctionCall) { return true; } Iterator i = exp.iterateSubExpressions(); while (i.hasNext()) { Expression e = (Expression)i.next(); if (containsUserFunctionCalls(e)) { return true; } } return false; } /** * Get the required types of an argument to this function * @param n identifies the argument in question, starting at 0 * @return a SequenceType object, indicating the required type of the argument */ public SequenceType getArgumentType(int n) { return parameterDefinitions[n].getRequiredType(); } /** * Get the evaluation mode. The evaluation mode will be computed if this has not already been done * @return the computed evaluation mode */ public int getEvaluationMode() { if (evaluationMode == ExpressionTool.UNDECIDED) { computeEvaluationMode(); } return evaluationMode; } /** * Get the arity of this function * @return the number of arguments */ public int getNumberOfArguments() { return parameterDefinitions.length; } /** * Mark this function as a memo function (or not) * @param isMemo true if this is a memo function */ public void setMemoFunction(boolean isMemo) { memoFunction = isMemo; } /** * Ask whether this function is a memo function * @return true if this function is marked as a memo function */ public boolean isMemoFunction() { return memoFunction; } /** * Gather the direct contributing callees of this function. A callee is a function that this one * calls. A contributing callee is a function whose output is added directly to the output of this * function without further processing (other than by attaching it to a parent element or document * node). A direct contributing callee is a function that is called directly, rather than indirectly. * @param result the list into which the callees are gathered. */ public void gatherDirectContributingCallees(Set result) { Expression body = getBody(); gatherDirectContributingCallees(body, result); } private void gatherDirectContributingCallees(Expression exp, Set result) { Iterator kids = exp.iterateSubExpressions(); while (kids.hasNext()) { Expression kid = (Expression)kids.next(); if (kid instanceof UserFunctionCall) { result.add(((UserFunctionCall)kid).getFunction()); } else if (kid instanceof Assignation) { gatherDirectContributingCallees(((Assignation)kid).getAction(), result); // } else if (kid instanceof IfExpression) { // gatherDirectContributingCallees(((IfExpression)kid).getThenExpression(), result); // gatherDirectContributingCallees(((IfExpression)kid).getElseExpression(), result); } else if (kid instanceof Choose) { Expression[] actions = ((Choose)kid).getActions(); for (int c=0; c





© 2015 - 2024 Weber Informatics LLC | Privacy Policy