/** * Mark tail-recursive calls on stylesheet functions. This marks the function call as tailRecursive if * if is a call to the containing function, and in this case it also returns "true" to the caller to indicate * that a tail call was found. */ public int markTailFunctionCalls(StructuredQName qName, int arity) { tailCall = true; return (getFunctionName().equals(qName) && arity == getNumberOfArguments() ? 2 : 1); }
/** * Bind a function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * * @param functionName The name of the function to be called * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. * @param env the static evaluation context * @param reasons If no matching function is found by the function library, it may add * a diagnostic explanation to this list explaining why none of the available * functions could be used. * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name and arity. */ public Expression bind(SymbolicName.F functionName, Expression[] staticArgs, StaticContext env, List<String> reasons) { UserFunction fn = functions.get(functionName); if (fn == null) { return null; } UserFunctionCall fc = new UserFunctionCall(); fc.setFunctionName(functionName.getComponentName()); fc.setArguments(staticArgs); fc.setFunction(fn); fc.setStaticType(fn.getResultType()); return fc; }
/** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * <p>The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.</p> * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addExternalFunctionCallToPathMap(pathMap, pathMapNodeSet); }
/** * Fix up references to this function * @param env the static context */ public void fixupReferences(StaticContext env) throws XPathException { Iterator iter = references.iterator(); while (iter.hasNext()) { UserFunctionCall ufc = (UserFunctionCall)iter.next(); ufc.setFunction(compiledFunction); ufc.computeArgumentEvaluationModes(); } }
/** * Mark tail-recursive calls on stylesheet functions. This marks the function call as tailRecursive if * if is a call to the containing function, and in this case it also returns "true" to the caller to indicate * that a tail call was found. */ public int markTailFunctionCalls(StructuredQName qName, int arity) { tailCall = getFunctionName().equals(qName) && arity == getArity() ? SELF_TAIL_CALL : FOREIGN_TAIL_CALL; return tailCall; }
final UserFunctionCall fc = new UserFunctionCall(); fc.setFunctionName(functionName.getComponentName()); fc.setArguments(staticArgs); fc.setFunction(fn); final ExpressionVisitor visitor = ExpressionVisitor.make(env); psm.addFixupAction(() -> { if (fc.getFunction() == null) { Component target = psm.getComponent(fc.getSymbolicName()); UserFunction fn1 = (UserFunction) target.getActor(); if (fn1 != null) { fc.allocateArgumentEvaluators(); fc.setStaticType(fn1.getResultType()); } else { XPathException err = new XPathException("There is no available function named " + fc.getDisplayName() + " with " + fc.getArity() + " arguments", "XPST0017"); err.setLocator(fc.getLocation()); throw err;
/** * Copy an expression. This makes a deep copy. * * @param rebindings variable bindings that need to be changed * @return the copy of the original expression */ /*@NotNull*/ public Expression copy(RebindingMap rebindings) { if (function == null) { // not bound yet, we have no way to register the new copy with the XSLFunction throw new UnsupportedOperationException("UserFunctionCall.copy()"); } UserFunctionCall ufc = new UserFunctionCall(); ufc.setFunction(function); ufc.setStaticType(staticType); int numArgs = getArity(); Expression[] a2 = new Expression[numArgs]; for (int i = 0; i < numArgs; i++) { a2[i] = getArg(i).copy(rebindings); } ufc.setArguments(a2); ExpressionTool.copyLocationInfo(this, ufc); return ufc; }
/** * Process the function call in push mode * * @param context the XPath dynamic context * @throws XPathException if a dynamic error occurs */ public void process(XPathContext context) throws XPathException { Sequence<?>[] actualArgs = evaluateArguments(context); if (isTailCall()) { requestTailCall(context, actualArgs); return; } if (bindingSlot >= 0) { Component target = getTargetComponent(context); UserFunction targetFunction = (UserFunction) target.getActor(); if (target.getVisibility() == Visibility.ABSTRACT) { throw new XPathException("Cannot call a function defined with visibility=abstract", "XTDE3052"); } XPathContextMajor c2 = targetFunction.makeNewContext(context, this); c2.setCurrentComponent(target); c2.setOrigin(this); targetFunction.process(actualArgs, c2); } else { XPathContextMajor c2 = function.makeNewContext(context, this); c2.setOrigin(this); function.process(actualArgs, c2); } }
return null; UserFunctionCall ufc = new UserFunctionCall(); ufc.setFunctionName(functionName); ufc.setArguments(arguments); unboundFunctionCalls.add(ufc); correspondingStaticContext.add(env);
/** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { if (function == null) { // not bound yet, we have no way to register the new copy with the XSLFunction throw new UnsupportedOperationException("copy"); } UserFunctionCall ufc = new UserFunctionCall(); ufc.setFunction(function); ufc.setStaticType(staticType); Expression[] a2 = new Expression[argument.length]; for (int i=0; i<argument.length; i++) { a2[i] = argument[i].copy(); } ufc.argument = a2; if (argumentEvaluationModes != null) { int[] am2 = new int[argumentEvaluationModes.length]; System.arraycopy(argumentEvaluationModes, 0, am2, 0, am2.length); ufc.argumentEvaluationModes = am2; } return ufc; }
final StructuredQName q = ufc.getFunctionName(); final int arity = ufc.getNumberOfArguments(); XQueryFunction fd = lib.getDeclaration(q, ufc.getArguments()); if (fd != null) { fd.registerReference(ufc); ufc.setStaticType(fd.getResultType()); ufc.setConfirmed(true);
return null; UserFunctionCall fc = new UserFunctionCall(); fn.registerReference(fc); fc.setFunctionName(functionName); fc.setArguments(staticArgs); fc.setConfirmed(true); return fc;
final StructuredQName q = ufc.getFunctionName(); final int arity = ufc.getArity(); ufc.setStaticType(fd.getResultType()); } else { StringBuilder sb = new StringBuilder("Cannot find a " + arity + XPathException err = new XPathException(sb.toString(), "XPST0017", ufc.getLocation()); err.setIsStaticError(true); throw err;
public Sequence<?>[] evaluateArguments(XPathContext c) throws XPathException { return evaluateArguments(c, false); }
/** * Get diagnostic information about this expression */ public InstructionInfo getInstructionInfo() { InstructionDetails details = new InstructionDetails(); details.setConstructType(Location.FUNCTION_CALL); details.setLineNumber(getLineNumber()); details.setSystemId(getSystemId()); details.setObjectName(getFunctionName()); details.setProperty("expression", this); details.setProperty("target", function); return details; }
/** * 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 { Iterator iter = references.iterator(); while (iter.hasNext()) { UserFunctionCall call = ((UserFunctionCall)iter.next()); call.setFunction(compiledFunction); call.checkFunctionCall(compiledFunction, visitor); call.computeArgumentEvaluationModes(); } } catch (XPathException err) { compileError(err); } }
/** * 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("ufCall", this); if (getFunctionName() != null) { out.emitAttribute("name", getFunctionName()); out.emitAttribute("tailCall", tailCall == NOT_TAIL_CALL ? "false" : tailCall == SELF_TAIL_CALL ? "self" : "foreign"); } out.emitAttribute("bSlot", "" + getBindingSlot()); if (argumentEvaluators != null && getArity() > 0) { FastStringBuffer fsb = new FastStringBuffer(FastStringBuffer.C64); for (Evaluator e : argumentEvaluators) { fsb.append(e.getCode() + " "); } out.emitAttribute("eval", Whitespace.trim(fsb)); } for (Operand o : operands()) { o.getChildExpression().export(out); } if (getFunctionName() == null) { out.setChildRole("inline"); function.getBody().export(out); out.endElement(); } out.endElement(); }
/** * Call the function, returning the value as an item. This method will be used * only when the cardinality is zero or one. If the function is tail recursive, * it returns an Object representing the arguments to the next (recursive) call */ public Item evaluateItem(XPathContext c) throws XPathException { return callFunction(c).head(); }
logger.trace("iterateParams; switching to UDF: {}", ufc.getFunctionName()); ex = ufc.getFunction().getBody();
/** * Gather a list of all the user-defined functions which a given expression calls directly * @param e the expression being tested * @param list a list of the functions that are called. The items in this list must * be objects of class {@link UserFunction} */ public static void gatherCalledFunctions(Expression e, List list) { if (e instanceof UserFunctionCall) { UserFunction function = ((UserFunctionCall)e).getFunction(); if (!list.contains(function)) { list.add(function); } } else { for (Iterator children = e.iterateSubExpressions(); children.hasNext();) { Expression child = (Expression)children.next(); gatherCalledFunctions(child, list); } } }