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

net.sf.saxon.functions.SystemFunctionCall Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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.functions;


import net.sf.saxon.expr.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.AnyItemType;
import net.sf.saxon.type.FunctionItemType;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.TypeHierarchy;
import net.sf.saxon.value.Cardinality;
import net.sf.saxon.value.SequenceType;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
* Abstract superclass for calls to functions in the standard function library
*/

public abstract class SystemFunctionCall extends FunctionCall implements Callable {

    public Callable getConvertingCallable() {
        final Callable raw = this;
        return new Callable() {
            public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
                Sequence[] convertedArgs = new Sequence[arguments.length];
                for (int i=0; i 0 &&
                !Cardinality.allowsMany(getRequiredType(0).getCardinality());
        int methods = super.getImplementationMethod();
        if (feedable) {
            methods |= Expression.ITEM_FEED_METHOD;
        }
        return methods;
    }

    public NodeInfo getDefaultArgumentNode(XPathContext context, Sequence[] arguments, String funcName) throws XPathException{
        if (arguments.length == 0) {
            Item item = context.getContextItem();
            if (item == null) {
                throw new XPathException("Context item for "+funcName+" is absent", "XPDY0002");
            } else if (!(item instanceof NodeInfo)) {
                throw new XPathException("Context item for "+funcName+" must be a node", "XPTY0004");
            } else {
                return (NodeInfo)item;
            }
        } else {
            return (NodeInfo)arguments[0].head();
        }
    }

    /**
     * Bind aspects of the static context on which the particular function depends
     * @param env the static context of the function call
     * @throws XPathException if execution with this static context will inevitably fail
     */

    public void bindStaticContext(StaticContext env) throws XPathException {
        // default: no action
    }

    /**
    * Method called during static type checking
    */

    public void checkArguments(/*@NotNull*/ ExpressionVisitor visitor) throws XPathException {
        checkArgumentCount(details.minArguments, details.maxArguments);
        for (int i=0; i
     * 

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 XPathException if an error is discovered during this phase * (typically a type error) */ /*@NotNull*/ public Expression optimize(/*@NotNull*/ ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException { Expression sf = super.optimize(visitor, contextItemType); if (sf == this && argument.length <= details.resultIfEmpty.length) { // the condition eliminates concat, which is a special case. for (int i=0; i iterateSubExpressionInfo() { List list = new ArrayList(argument.length); for (int i=0; i 0) { return argument[0].getItemType(th); } else { return AnyItemType.getInstance(); // if there is no first argument, an error will be reported } } else if ((details.properties & StandardFunction.AS_PRIM_ARG0) != 0) { if (argument.length > 0) { return argument[0].getItemType(th).getPrimitiveItemType(); } else { return AnyItemType.getInstance(); // if there is no first argument, an error will be reported } } else { return type; } } /** * Determine the cardinality of the function. */ public int computeCardinality() { if (details==null) { //System.err.println("**** No details for " + getClass() + " at " + this); return StaticProperty.ALLOWS_ZERO_OR_MORE; } return details.cardinality; } /** * Determine the special properties of this expression. The general rule * is that a system function call is non-creative if its return type is * atomic, or if all its arguments are non-creative. This is overridden * for the generate-id() function, which is considered creative if * its operand is creative (because the result depends on the * identity of the operand) */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); if (details == null) { return p; } if (details.itemType.isPlainType() || (details.properties & StandardFunction.AS_ARG0) != 0 || (details.properties & StandardFunction.AS_PRIM_ARG0) != 0) { return p | StaticProperty.NON_CREATIVE; } for (Expression anArgument : argument) { if ((anArgument.getSpecialProperties() & StaticProperty.NON_CREATIVE) == 0) { // the argument is creative return p; } } return p | StaticProperty.NON_CREATIVE; } /** * Set "." as the default value for the first and only argument. Called from subclasses. * @param visitor the expression visitor */ protected final void useContextItemAsDefault(/*@NotNull*/ ExpressionVisitor visitor) { if (argument.length==0) { argument = new Expression[1]; argument[0] = new ContextItemExpression(); details = StandardFunction.getFunction(getFunctionName().getLocalPart(), 1); ExpressionTool.copyLocationInfo(this, argument[0]); visitor.resetStaticProperties(); } // Note that the extra argument is added before type-checking takes place. The // type-checking will add any necessary checks to ensure that the context item // is a node, in cases where this is required. } /** * Add an implicit argument referring to the context document. Called by functions such as * id() and key() that take the context document as an implicit argument * @param pos the position of the argument whose default value is ".", zero-based * @param augmentedName the name to be used for the function call with its extra argument. * There are some cases where user function calls cannot supply the argument directly (notably * unparsed-entity-uri() and unparsed-entity-public-id()) and in these cases a synthesized * function name is used for the new function call. * @throws net.sf.saxon.trans.XPathException if a static error is found */ protected final void addContextDocumentArgument(int pos, String augmentedName) throws XPathException { if (argument.length > pos) { return; // this can happen during optimization, if the extra argument is already present } if (argument.length != pos) { throw new XPathException("Too few arguments in call to " + augmentedName + "() function"); } Expression[] newArgs = new Expression[pos+1]; System.arraycopy(argument, 0, newArgs, 0, argument.length); RootExpression rootExpression = new RootExpression(); ExpressionTool.copyLocationInfo(this, rootExpression); newArgs[pos] = rootExpression; argument = newArgs; setDetails(StandardFunction.getFunction(augmentedName, newArgs.length)); } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodes the node in the PathMap representing the focus at the point where this expression * is called. Set to null if this expression appears at the top level. * @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 */ /*@Nullable*/ public PathMap.PathMapNodeSet addDocToPathMap(/*@NotNull*/ PathMap pathMap, PathMap.PathMapNodeSet pathMapNodes) { argument[0].addToPathMap(pathMap, pathMapNodes); return new PathMap.PathMapNodeSet(pathMap.makeNewRoot(this)); } /** * Helper method for subclasses: get the context item if it is a node, throwing appropriate errors * if not * @param context the XPath dynamic context * @return the context item if it exists and is a node * @throws XPathException if there is no context item or if the context item is not a node */ protected NodeInfo getContextNode(XPathContext context) throws XPathException { Item item = context.getContextItem(); if (item == null) { XPathException err = new XPathException("Context item for " + getFunctionName() + "() is absent", "XPDY0002"); err.maybeSetContext(context); err.setLocator(this); throw err; } else if (!(item instanceof NodeInfo)) { XPathException err = new XPathException("Context item for " + getFunctionName() +"() is not a node", "XPTY0004"); err.maybeSetContext(context); err.setLocator(this); throw err; } else { return (NodeInfo)item; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy