net.sf.saxon.functions.SystemFunctionCall 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.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;
}
}
}