net.sf.saxon.functions.StandardFunction 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.Expression;
import net.sf.saxon.expr.StaticProperty;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.pattern.NodeKindTest;
import net.sf.saxon.type.*;
import net.sf.saxon.value.*;
import net.sf.saxon.value.StringValue;
import java.util.HashMap;
/**
* This class contains static data tables defining the properties of standard functions. "Standard functions"
* here means the XPath 2.0 functions, the XSLT 2.0 functions, and a few selected extension functions
* which need special recognition.
*/
public abstract class StandardFunction {
public static Sequence EMPTY = EmptySequence.getInstance();
/**
* Categories of functions, bit significant
*/
public static final int CORE = 1;
public static final int XSLT = 2;
public static final int USE_WHEN = 4;
public static final int XQUPDATE = 8;
public static final int XPATH30 = 16;
public static final int INTERNAL = 32;
public static final int XSLT30 = 64;
/**
* Local names used for cardinality values
*/
public static final int ONE = StaticProperty.ALLOWS_ONE;
public static final int OPT = StaticProperty.ALLOWS_ZERO_OR_ONE;
public static final int STAR = StaticProperty.ALLOWS_ZERO_OR_MORE;
public static final int PLUS = StaticProperty.ALLOWS_ONE_OR_MORE;
/**
* Classification of function arguments for serialization purposes; note that values must not conflict
* with bit settings used for cardinalities
*/
public static final int LOOK = 1 << 24; // = syntactic context INSPECTION
public static final int TAKE = 1 << 25; // = syntactic context NODE-VALUE (implicit when type is atomic)
public static final int GIVE = 1 << 26; // = syntactic context INHERIT (node is included in function result)
public static final int WALK = 1 << 27; // = syntactic context NAVIGATE (function navigates from this node)
/**
* This class is never instantiated
*/
private StandardFunction() {
}
/**
* Register a system function in the table of function details.
*
* @param name the function name
* @param implementationClass the class used to implement the function
* @param opcode identifies the function when a single class implements several functions
* @param minArguments the minimum number of arguments required
* @param maxArguments the maximum number of arguments allowed
* @param itemType the item type of the result of the function
* @param cardinality the cardinality of the result of the function
* @param applicability the host languages (and versions thereof) in which this function is available
* @param properties
* @return the entry describing the function. The entry is incomplete, it does not yet contain information
* about the function arguments.
*/
/*@NotNull*/
public static Entry register(String name,
Class implementationClass,
int opcode,
int minArguments,
int maxArguments,
ItemType itemType,
int cardinality,
int applicability,
int properties) {
Entry e = makeEntry(name, implementationClass, opcode, minArguments, maxArguments,
itemType, cardinality, applicability, properties);
functionTable.put(name, e);
return e;
}
/**
* Make a table entry describing the signature of a function, with a reference to the implementation class.
*
* @param name the function name
* @param implementationClass the class used to implement the function
* @param opcode identifies the function when a single class implements several functions
* @param minArguments the minimum number of arguments required
* @param maxArguments the maximum number of arguments allowed
* @param itemType the item type of the result of the function
* @param cardinality the cardinality of the result of the function
* @param applicability the host languages (and versions of) in which this function is available
* @return the entry describing the function. The entry is incomplete, it does not yet contain information
* about the function arguments.
*/
public static Entry makeEntry(String name, Class implementationClass, int opcode,
int minArguments, int maxArguments,
ItemType itemType, int cardinality, int applicability, int properties) {
Entry e = new Entry();
int hash = name.indexOf('#');
if (hash < 0) {
e.name = name;
} else {
e.name = name.substring(0, hash);
}
e.implementationClass = implementationClass;
e.opcode = opcode;
e.minArguments = minArguments;
e.maxArguments = maxArguments;
e.itemType = itemType;
e.cardinality = cardinality;
e.applicability = applicability;
e.properties = properties;
if (maxArguments > 100) {
// special case for concat()
e.argumentTypes = new SequenceType[1];
e.resultIfEmpty = new AtomicValue[1];
e.syntacticContext = new int[1];
} else {
e.argumentTypes = new SequenceType[maxArguments];
e.resultIfEmpty = new Sequence[maxArguments];
e.syntacticContext = new int[maxArguments];
}
return e;
}
private static HashMap functionTable = new HashMap(200);
public static final int AS_ARG0 = 1; // Result has same type as first argument
public static final int AS_PRIM_ARG0 = 2; // Result has same primitive type as first argument
public static final int FOCUS = 4; // Depends on focus
public static final int BASE = 8; // Depends on base URI
public static final int NS = 16; // Depends on namespace context
public static final int DCOLL = 32; // Depends on default collation
public static final int DEPENDS_ON_STATIC_CONTEXT = BASE | NS | DCOLL;
static {
Entry e;
register("abs", Abs.class, 0, 1, 1, BuiltInAtomicType.NUMERIC, OPT, CORE, AS_PRIM_ARG0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, EMPTY);
register("adjust-date-to-timezone", Adjust.class, 0, 1, 2, BuiltInAtomicType.DATE, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, EMPTY)
.arg(1, BuiltInAtomicType.DAY_TIME_DURATION, OPT, null);
register("adjust-dateTime-to-timezone", Adjust.class, 0, 1, 2, BuiltInAtomicType.DATE_TIME, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY)
.arg(1, BuiltInAtomicType.DAY_TIME_DURATION, OPT, null);
register("adjust-time-to-timezone", Adjust.class, 0, 1, 2, BuiltInAtomicType.TIME, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.TIME, OPT, EMPTY)
.arg(1, BuiltInAtomicType.DAY_TIME_DURATION, OPT, null);
register("avg", Average.class, 0, 1, 1, BuiltInAtomicType.ANY_ATOMIC, OPT, CORE, 0)
// can't say "same as first argument" because the avg of a set of integers is decimal
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY);
register("base-uri", BaseURI.class, 0, 0, 1, BuiltInAtomicType.ANY_URI, OPT, CORE, BASE)
.arg(0, Type.NODE_TYPE, OPT | LOOK, EMPTY);
register("boolean", BooleanFn.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | LOOK, null);
register("ceiling", Ceiling.class, 0, 1, 1, BuiltInAtomicType.NUMERIC, OPT, CORE, AS_PRIM_ARG0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, EMPTY);
register("codepoint-equal", CodepointEqual.class, 0, 2, 2, BuiltInAtomicType.BOOLEAN, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY)
.arg(1, BuiltInAtomicType.STRING, OPT, EMPTY);
register("codepoints-to-string", CodepointsToString.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.INTEGER, STAR, null);
register("collection", Collection.class, 0, 0, 1, Type.NODE_TYPE, STAR, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null);
register("compare#2", Compare.class, 0, 2, 2, BuiltInAtomicType.INTEGER, OPT, CORE, DCOLL)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY)
.arg(1, BuiltInAtomicType.STRING, OPT, EMPTY);
register("compare#3", Compare.class, 0, 3, 3, BuiltInAtomicType.INTEGER, OPT, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY)
.arg(1, BuiltInAtomicType.STRING, OPT, EMPTY)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("concat", Concat.class, 0, 2, Integer.MAX_VALUE, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, OPT, null);
// Note, this has a variable number of arguments so it is treated specially
register("contains#2", Contains.class, 0, 2, 2, BuiltInAtomicType.BOOLEAN, ONE, CORE, DCOLL)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, BooleanValue.TRUE);
register("contains#3", Contains.class, 0, 3, 3, BuiltInAtomicType.BOOLEAN, ONE, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, BooleanValue.TRUE)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("count", Count.class, 0, 1, 1, BuiltInAtomicType.INTEGER, ONE, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | LOOK, Int64Value.ZERO);
register("current", Current.class, 0, 0, 0, Type.ITEM_TYPE, ONE, XSLT, 0);
register("current-date", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.DATE, ONE, CORE, 0);
register("current-dateTime", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.DATE_TIME, ONE, CORE, 0);
register("current-time", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.TIME, ONE, CORE, 0);
register("current-group", CurrentGroup.class, 0, 0, 0, Type.ITEM_TYPE, STAR, XSLT, 0);
register("current-grouping-key", CurrentGroupingKey.class, 0, 0, 0, BuiltInAtomicType.ANY_ATOMIC, STAR, XSLT, 0);
register("data#0", Data.class, 0, 0, 0, BuiltInAtomicType.ANY_ATOMIC, STAR, XPATH30, FOCUS);
register("data#1", Data.class, 0, 1, 1, BuiltInAtomicType.ANY_ATOMIC, STAR, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | TAKE, EMPTY);
register("dateTime", DateTimeConstructor.class, 0, 2, 2, BuiltInAtomicType.DATE_TIME, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, EMPTY)
.arg(1, BuiltInAtomicType.TIME, OPT, EMPTY);
register("day-from-date", Component.class, (Component.DAY << 16) + StandardNames.XS_DATE, 1, 1, BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, EMPTY);
register("day-from-dateTime", Component.class, (Component.DAY << 16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("days-from-duration", Component.class, (Component.DAY << 16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DURATION, OPT, EMPTY);
register("deep-equal#2", DeepEqual.class, 0, 2, 3, BuiltInAtomicType.BOOLEAN, ONE, CORE, DCOLL)
.arg(0, Type.ITEM_TYPE, STAR, null)
.arg(1, Type.ITEM_TYPE, STAR, null);
register("deep-equal#3", DeepEqual.class, 0, 2, 3, BuiltInAtomicType.BOOLEAN, ONE, CORE, BASE)
.arg(0, Type.ITEM_TYPE, STAR, null)
.arg(1, Type.ITEM_TYPE, STAR, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("default-collation", DefaultCollation.class, 0, 0, 0, BuiltInAtomicType.STRING, ONE, CORE, DCOLL);
register("distinct-values#1", DistinctValues.class, 0, 1, 2, BuiltInAtomicType.ANY_ATOMIC, STAR, CORE, DCOLL)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY);
register("distinct-values#2", DistinctValues.class, 0, 1, 2, BuiltInAtomicType.ANY_ATOMIC, STAR, CORE, BASE)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("doc", Doc.class, 0, 1, 1, NodeKindTest.DOCUMENT, OPT, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY);
register("doc-available", DocAvailable.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, BooleanValue.FALSE);
register("document", DocumentFn.class, 0, 1, 2, Type.NODE_TYPE, STAR, XSLT, BASE)
.arg(0, Type.ITEM_TYPE, STAR, null)
.arg(1, Type.NODE_TYPE, ONE, null);
register("document-uri#0", DocumentUriFn.class, 0, 0, 0, BuiltInAtomicType.ANY_URI, OPT, XPATH30, FOCUS);
register("document-uri#1", DocumentUriFn.class, 0, 1, 1, BuiltInAtomicType.ANY_URI, OPT, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, EMPTY);
register("empty", Empty.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | LOOK, BooleanValue.TRUE);
register("ends-with#2", EndsWith.class, 0, 2, 2, BuiltInAtomicType.BOOLEAN, ONE, CORE, DCOLL)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, BooleanValue.TRUE);
register("ends-with#3", EndsWith.class, 0, 3, 3, BuiltInAtomicType.BOOLEAN, ONE, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, BooleanValue.TRUE)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("element-available", ElementAvailable.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, XSLT | USE_WHEN, NS)
.arg(0, BuiltInAtomicType.STRING, ONE, null);
register("element-with-id#1", Id.class, Id.ELEMENT_WITH_ID, 1, 1, NodeKindTest.ELEMENT, STAR, CORE, FOCUS)
.arg(0, BuiltInAtomicType.STRING, STAR, EMPTY);
register("element-with-id#2", Id.class, Id.ELEMENT_WITH_ID, 2, 2, NodeKindTest.ELEMENT, STAR, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, STAR, EMPTY)
.arg(1, Type.NODE_TYPE, ONE, null);
register("encode-for-uri", EscapeURI.class, EscapeURI.ENCODE_FOR_URI, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING);
register("escape-html-uri", EscapeURI.class, EscapeURI.HTML_URI, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING);
register("error", Error.class, 0, 0, 3, Type.ITEM_TYPE, OPT, CORE, 0)
// The return type is chosen so that use of the error() function will never give a static type error,
// on the basis that item()? overlaps every other type, and it's almost impossible to make any
// unwarranted inferences from it, except perhaps count(error()) lt 2.
.arg(0, BuiltInAtomicType.QNAME, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, Type.ITEM_TYPE, STAR, null);
register("exactly-one", TreatFn.class, ONE, 1, 1, Type.ITEM_TYPE, ONE, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, ONE | GIVE, null);
// because we don't do draconian static type checking, we can do the work in the argument type checking code
register("false", False.class, 0, 0, 0, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0);
register("exists", Exists.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | LOOK, BooleanValue.FALSE);
register("floor", Floor.class, 0, 1, 1, BuiltInAtomicType.NUMERIC, OPT, CORE, AS_PRIM_ARG0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, EMPTY);
register("format-date", FormatDate.class, StandardNames.XS_DATE, 2, 5, BuiltInAtomicType.STRING,
OPT, XSLT | XPATH30, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, OPT, null)
.arg(3, BuiltInAtomicType.STRING, OPT, null)
.arg(4, BuiltInAtomicType.STRING, OPT, null);
register("format-dateTime", FormatDate.class, StandardNames.XS_DATE_TIME, 2, 5, BuiltInAtomicType.STRING,
OPT, XSLT | XPATH30, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, OPT, null)
.arg(3, BuiltInAtomicType.STRING, OPT, null)
.arg(4, BuiltInAtomicType.STRING, OPT, null);
register("format-number#2", FormatNumber.class, 0, 2, 2, BuiltInAtomicType.STRING, ONE, XSLT | XPATH30, 0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("format-number#3", FormatNumber.class, 0, 3, 3, BuiltInAtomicType.STRING, ONE, XSLT | XPATH30, NS)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, OPT, null);
register("format-time", FormatDate.class, StandardNames.XS_TIME, 2, 5, BuiltInAtomicType.STRING,
OPT, XSLT | XPATH30, 0)
.arg(0, BuiltInAtomicType.TIME, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, OPT, null)
.arg(3, BuiltInAtomicType.STRING, OPT, null)
.arg(4, BuiltInAtomicType.STRING, OPT, null);
register("function-available", FunctionAvailable.class, 0, 1, 2, BuiltInAtomicType.BOOLEAN, ONE, XSLT | USE_WHEN, NS)
.arg(0, BuiltInAtomicType.STRING, ONE, null)
.arg(1, BuiltInAtomicType.INTEGER, ONE, null);
register("generate-id#0", GenerateId.class, 0, 0, 0, BuiltInAtomicType.STRING, ONE, XSLT | XPATH30, FOCUS);
register("generate-id#1", GenerateId.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, XSLT | XPATH30, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, StringValue.EMPTY_STRING);
register("hours-from-dateTime", Component.class, (Component.HOURS << 16) + StandardNames.XS_DATE_TIME, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("hours-from-duration", Component.class, (Component.HOURS << 16) + StandardNames.XS_DURATION, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DURATION, OPT, EMPTY);
register("hours-from-time", Component.class, (Component.HOURS << 16) + StandardNames.XS_TIME, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.TIME, OPT, EMPTY);
register("id#1", Id.class, Id.ID, 1, 1, NodeKindTest.ELEMENT, STAR, CORE, FOCUS)
.arg(0, BuiltInAtomicType.STRING, STAR, EMPTY);
register("id#2", Id.class, Id.ID, 2, 2, NodeKindTest.ELEMENT, STAR, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, STAR, EMPTY)
.arg(1, Type.NODE_TYPE, ONE, null);
register("idref#1", Idref.class, 0, 1, 1, Type.NODE_TYPE, STAR, CORE, FOCUS)
.arg(0, BuiltInAtomicType.STRING, STAR, EMPTY);
register("idref#2", Idref.class, 0, 2, 2, Type.NODE_TYPE, STAR, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, STAR, EMPTY)
.arg(1, Type.NODE_TYPE, ONE, null);
register("implicit-timezone", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.DAY_TIME_DURATION, ONE, CORE, 0);
register("in-scope-prefixes", InScopePrefixes.class, 0, 1, 1, BuiltInAtomicType.STRING, STAR, CORE, 0)
.arg(0, NodeKindTest.ELEMENT, ONE | LOOK, null);
register("index-of#2", IndexOf.class, 0, 2, 2, BuiltInAtomicType.INTEGER, STAR, CORE, DCOLL)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY)
.arg(1, BuiltInAtomicType.ANY_ATOMIC, ONE, null);
register("index-of#3", IndexOf.class, 0, 3, 3, BuiltInAtomicType.INTEGER, STAR, CORE, BASE)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY)
.arg(1, BuiltInAtomicType.ANY_ATOMIC, ONE, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("insert-before", Insert.class, 0, 3, 3, Type.ITEM_TYPE, STAR, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | GIVE, null)
.arg(1, BuiltInAtomicType.INTEGER, ONE, null)
.arg(2, Type.ITEM_TYPE, STAR | GIVE, null);
register("iri-to-uri", EscapeURI.class, EscapeURI.IRI_TO_URI, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING);
register("key#2", KeyFn.class, 0, 2, 2, Type.NODE_TYPE, STAR, XSLT, FOCUS | NS)
.arg(0, BuiltInAtomicType.STRING, ONE, null)
.arg(1, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY);
register("key#3", KeyFn.class, 0, 3, 3, Type.NODE_TYPE, STAR, XSLT, NS)
.arg(0, BuiltInAtomicType.STRING, ONE, null)
.arg(1, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY)
.arg(2, Type.NODE_TYPE, ONE, null);
register("lang#1", Lang.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, CORE, FOCUS)
.arg(0, BuiltInAtomicType.STRING, OPT, null);
register("lang#2", Lang.class, 0, 2, 2, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, Type.NODE_TYPE, ONE | LOOK, null);
register("last", Last.class, 0, 0, 0, BuiltInAtomicType.INTEGER, ONE, CORE, FOCUS);
register("local-name#0", LocalNameFn.class, 0, 0, 0, BuiltInAtomicType.STRING, ONE, CORE, FOCUS);
register("local-name#1", LocalNameFn.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, StringValue.EMPTY_STRING);
register("local-name-from-QName", Component.class, (Component.LOCALNAME << 16) + StandardNames.XS_QNAME, 1, 1,
BuiltInAtomicType.NCNAME, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.QNAME, OPT, EMPTY);
register("lower-case", LowerCase.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING);
register("matches", Matches.class, 0, 2, 3, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("max#1", Max.class, Minimax.MAX, 1, 1, BuiltInAtomicType.ANY_ATOMIC, OPT, CORE, DCOLL)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY);
register("max#2", Max.class, Minimax.MAX, 2, 2, BuiltInAtomicType.ANY_ATOMIC, OPT, CORE, BASE)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("min#1", Min.class, Minimax.MIN, 1, 1, BuiltInAtomicType.ANY_ATOMIC, OPT, CORE, DCOLL)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY);
register("min#2", Min.class, Minimax.MIN, 2, 2, BuiltInAtomicType.ANY_ATOMIC, OPT, CORE, BASE)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, EMPTY)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("minutes-from-dateTime", Component.class, (Component.MINUTES << 16) + StandardNames.XS_DATE_TIME, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("minutes-from-duration", Component.class, (Component.MINUTES << 16) + StandardNames.XS_DURATION, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DURATION, OPT, EMPTY);
register("minutes-from-time", Component.class, (Component.MINUTES << 16) + StandardNames.XS_TIME, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.TIME, OPT, EMPTY);
register("month-from-date", Component.class, (Component.MONTH << 16) + StandardNames.XS_DATE, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, EMPTY);
register("month-from-dateTime", Component.class, (Component.MONTH << 16) + StandardNames.XS_DATE_TIME, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("months-from-duration", Component.class, (Component.MONTH << 16) + StandardNames.XS_DURATION, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DURATION, OPT, EMPTY);
register("name#0", NameFn.class, 0, 0, 0, BuiltInAtomicType.STRING, ONE, CORE, FOCUS);
register("name#1", NameFn.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, StringValue.EMPTY_STRING);
register("namespace-uri#0", NamespaceUriFn.class, 0, 0, 0, BuiltInAtomicType.ANY_URI, ONE, CORE, FOCUS);
register("namespace-uri#1", NamespaceUriFn.class, 0, 1, 1, BuiltInAtomicType.ANY_URI, ONE, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, StringValue.EMPTY_STRING);
register("namespace-uri-for-prefix", NamespaceForPrefix.class, 0, 2, 2, BuiltInAtomicType.ANY_URI, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, NodeKindTest.ELEMENT, ONE | LOOK, null);
register("namespace-uri-from-QName", Component.class, (Component.NAMESPACE << 16) + StandardNames.XS_QNAME, 1, 1, BuiltInAtomicType.ANY_URI, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.QNAME, OPT, EMPTY);
register("nilled#0", Nilled.class, 0, 0, 0, BuiltInAtomicType.BOOLEAN, OPT, XPATH30, FOCUS);
register("nilled#1", Nilled.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, OPT, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, EMPTY);
register("node-name#0", NodeNameFn.class, 0, 0, 0, BuiltInAtomicType.QNAME, OPT, XPATH30, FOCUS);
register("node-name#1", NodeNameFn.class, 0, 1, 1, BuiltInAtomicType.QNAME, OPT, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | LOOK, EMPTY);
register("not", NotFn.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | LOOK, BooleanValue.TRUE);
register("normalize-space#0", NormalizeSpace_0.class, 0, 0, 0, BuiltInAtomicType.STRING, ONE, CORE, FOCUS);
register("normalize-space#1", NormalizeSpace_1.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null);
register("normalize-unicode", NormalizeUnicode.class, 0, 1, 2, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("number#0", NumberFn.class, 0, 0, 0, BuiltInAtomicType.DOUBLE, ONE, CORE, FOCUS);
register("number#1", NumberFn.class, 0, 1, 1, BuiltInAtomicType.DOUBLE, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, OPT, DoubleValue.NaN);
register("one-or-more", TreatFn.class, PLUS, 1, 1, Type.ITEM_TYPE, PLUS, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, PLUS | GIVE, null);
// because we don't do draconian static type checking, we can do the work in the argument type checking code
register("position", Position.class, 0, 0, 0, BuiltInAtomicType.INTEGER, ONE, CORE, FOCUS);
register("prefix-from-QName", Component.class, (Component.PREFIX << 16) + StandardNames.XS_QNAME, 1, 1, BuiltInAtomicType.NCNAME, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.QNAME, OPT, EMPTY);
register("put", Put.class, 0, 2, 2, AnyItemType.getInstance(), OPT, XQUPDATE, 0)
.arg(0, Type.NODE_TYPE, ONE, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("QName", QNameFn.class, 0, 2, 2, BuiltInAtomicType.QNAME, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("regex-group", RegexGroup.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, XSLT, 0)
.arg(0, BuiltInAtomicType.INTEGER, ONE, null);
register("remove", Remove.class, 0, 2, 2, Type.ITEM_TYPE, STAR, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, STAR | GIVE, EMPTY)
.arg(1, BuiltInAtomicType.INTEGER, ONE, null);
register("replace", Replace.class, 0, 3, 4, BuiltInAtomicType.STRING,
ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null)
.arg(3, BuiltInAtomicType.STRING, ONE, null);
register("resolve-QName", ResolveQName.class, 0, 2, 2, BuiltInAtomicType.QNAME, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY)
.arg(1, NodeKindTest.ELEMENT, ONE | LOOK, null);
register("resolve-uri#1", ResolveURI.class, 0, 1, 1, BuiltInAtomicType.ANY_URI, OPT, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null);
register("resolve-uri#2", ResolveURI.class, 0, 2, 2, BuiltInAtomicType.ANY_URI, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("reverse", Reverse.class, 0, 1, 1, Type.ITEM_TYPE, STAR, CORE, 0)
.arg(0, Type.ITEM_TYPE, STAR | GIVE, EMPTY);
register("root#0", Root.class, 0, 0, 0, Type.NODE_TYPE, OPT, CORE, FOCUS);
register("root#1", Root.class, 0, 1, 1, Type.NODE_TYPE, OPT, CORE, 0)
.arg(0, Type.NODE_TYPE, OPT | WALK, EMPTY);
register("round#1", Round.class, 0, 1, 1, BuiltInAtomicType.NUMERIC, OPT, CORE, AS_PRIM_ARG0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, EMPTY);
register("round#2", Round.class, 0, 2, 2, BuiltInAtomicType.NUMERIC, OPT, XPATH30, AS_PRIM_ARG0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, EMPTY)
.arg(1, BuiltInAtomicType.INTEGER, ONE, null);
register("round-half-to-even", RoundHalfToEven.class, 0, 1, 2, BuiltInAtomicType.NUMERIC, OPT, CORE, AS_PRIM_ARG0)
.arg(0, BuiltInAtomicType.NUMERIC, OPT, EMPTY)
.arg(1, BuiltInAtomicType.INTEGER, ONE, null);
register("seconds-from-dateTime", Component.class, (Component.SECONDS << 16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.DECIMAL, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("seconds-from-duration", Component.class, (Component.SECONDS << 16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.DECIMAL, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DURATION, OPT, EMPTY);
register("seconds-from-time", Component.class, (Component.SECONDS << 16) + StandardNames.XS_TIME, 1, 1, BuiltInAtomicType.DECIMAL, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.TIME, OPT, EMPTY);
register("starts-with#2", StartsWith.class, 0, 2, 2, BuiltInAtomicType.BOOLEAN, ONE, CORE, DCOLL)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, BooleanValue.TRUE);
register("starts-with#3", StartsWith.class, 0, 3, 3, BuiltInAtomicType.BOOLEAN, ONE, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, BooleanValue.TRUE)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("static-base-uri", StaticBaseURI.class, 0, 0, 0, BuiltInAtomicType.ANY_URI, OPT, CORE, BASE);
register("string#0", StringFn.class, 0, 0, 0, BuiltInAtomicType.STRING, ONE, CORE, FOCUS);
register("string#1", StringFn.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, Type.ITEM_TYPE, OPT | TAKE, StringValue.EMPTY_STRING);
register("string-length#0", StringLength.class, 0, 0, 0, BuiltInAtomicType.INTEGER, ONE, CORE, FOCUS);
register("string-length#1", StringLength.class, 0, 1, 1, BuiltInAtomicType.INTEGER, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, null);
register("string-join#1", StringJoin.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, XPATH30, 0)
.arg(0, BuiltInAtomicType.STRING, STAR, StringValue.EMPTY_STRING);
register("string-join#2", StringJoin.class, 0, 2, 2, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, STAR, StringValue.EMPTY_STRING)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("string-to-codepoints", StringToCodepoints.class, 0, 1, 1, BuiltInAtomicType.INTEGER, STAR, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY);
register("subsequence", Subsequence.class, 0, 2, 3, Type.ITEM_TYPE, STAR, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, STAR | GIVE, EMPTY)
.arg(1, BuiltInAtomicType.NUMERIC, ONE, null)
.arg(2, BuiltInAtomicType.NUMERIC, ONE, null);
register("substring", Substring.class, 0, 2, 3, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING)
.arg(1, BuiltInAtomicType.NUMERIC, ONE, null)
.arg(2, BuiltInAtomicType.NUMERIC, ONE, null);
register("substring-after#2", SubstringAfter.class, 0, 2, 2, BuiltInAtomicType.STRING, ONE, CORE, DCOLL)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, null);
register("substring-after#3", SubstringAfter.class, 0, 3, 3, BuiltInAtomicType.STRING, ONE, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("substring-before#2", SubstringBefore.class, 0, 2, 2, BuiltInAtomicType.STRING, ONE, CORE, DCOLL)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING);
register("substring-before#3", SubstringBefore.class, 0, 3, 3, BuiltInAtomicType.STRING, ONE, CORE, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("sum", Sum.class, 0, 1, 2, BuiltInAtomicType.ANY_ATOMIC, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.ANY_ATOMIC, STAR, null)
.arg(1, BuiltInAtomicType.ANY_ATOMIC, OPT, null);
register("system-property", SystemProperty.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, XSLT | USE_WHEN, NS)
.arg(0, BuiltInAtomicType.STRING, ONE, null);
register("timezone-from-date", Component.class, (Component.TIMEZONE << 16) + StandardNames.XS_DATE, 1, 1, BuiltInAtomicType.DAY_TIME_DURATION, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, EMPTY);
register("timezone-from-dateTime", Component.class, (Component.TIMEZONE << 16) + StandardNames.XS_DATE_TIME, 1, 1,
BuiltInAtomicType.DAY_TIME_DURATION, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("timezone-from-time", Component.class, (Component.TIMEZONE << 16) + StandardNames.XS_TIME, 1, 1,
BuiltInAtomicType.DAY_TIME_DURATION, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.TIME, OPT, EMPTY);
register("trace", Trace.class, 0, 2, 2, Type.ITEM_TYPE, STAR, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, STAR, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
// register("true", BooleanFn.class, BooleanFn.TRUE, 0, 0, BuiltInAtomicType.BOOLEAN,
// UNIT, CORE)
register("translate", Translate.class, 0, 3, 3, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("true", True.class, 0, 0, 0, BuiltInAtomicType.BOOLEAN, ONE, CORE, 0);
register("tokenize", Tokenize.class, 0, 2, 3, BuiltInAtomicType.STRING, STAR, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, EMPTY)
.arg(1, BuiltInAtomicType.STRING, ONE, null)
.arg(2, BuiltInAtomicType.STRING, ONE, null);
register("type-available", TypeAvailable.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, ONE, XSLT | USE_WHEN, NS)
.arg(0, BuiltInAtomicType.STRING, ONE, null);
register("unordered", Unordered.class, 0, 1, 1, Type.ITEM_TYPE, STAR, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, STAR | GIVE, EMPTY);
register("upper-case", UpperCase.class, 0, 1, 1, BuiltInAtomicType.STRING, ONE, CORE, 0)
.arg(0, BuiltInAtomicType.STRING, OPT, StringValue.EMPTY_STRING);
register("unparsed-entity-uri", UnparsedEntity.class, UnparsedEntity.URI, 1, 1, BuiltInAtomicType.ANY_URI, ONE, XSLT, FOCUS)
.arg(0, BuiltInAtomicType.STRING, ONE, null);
// internal version of unparsed-entity-uri with second argument representing the current document
register("unparsed-entity-uri_9999_", UnparsedEntity.class, UnparsedEntity.URI, 2, 2,
BuiltInAtomicType.STRING, ONE, INTERNAL, 0)
.arg(0, BuiltInAtomicType.STRING, ONE, null)
.arg(1, Type.NODE_TYPE, ONE, null);
// it must actually be a document node, but there's a non-standard error code
register("unparsed-entity-public-id", UnparsedEntity.class, UnparsedEntity.PUBLIC_ID, 1, 1, BuiltInAtomicType.STRING, ONE, XSLT, FOCUS)
.arg(0, BuiltInAtomicType.STRING, ONE, null);
// internal version of unparsed-entity-public-id with second argument representing the current document
register("unparsed-entity-public-id_9999_", UnparsedEntity.class, UnparsedEntity.PUBLIC_ID, 2, 2,
BuiltInAtomicType.STRING, ONE, INTERNAL, 0)
.arg(0, BuiltInAtomicType.STRING, ONE, null)
.arg(1, Type.NODE_TYPE, ONE, null);
// it must actually be a document node, but there's a non-standard error code
register("unparsed-text", UnparsedText.class, 0, 1, 2,
BuiltInAtomicType.STRING, OPT, XSLT | XPATH30, BASE)
.arg(0, BuiltInAtomicType.STRING, OPT, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("unparsed-text-available", UnparsedTextAvailable.class, 0, 1, 2,
BuiltInAtomicType.BOOLEAN, ONE, XSLT | XPATH30, BASE)
.arg(0, BuiltInAtomicType.STRING, ONE, null)
.arg(1, BuiltInAtomicType.STRING, ONE, null);
register("year-from-date", Component.class, (Component.YEAR << 16) + StandardNames.XS_DATE, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE, OPT, EMPTY);
register("year-from-dateTime", Component.class, (Component.YEAR << 16) + StandardNames.XS_DATE_TIME, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DATE_TIME, OPT, EMPTY);
register("years-from-duration", Component.class, (Component.YEAR << 16) + StandardNames.XS_DURATION, 1, 1,
BuiltInAtomicType.INTEGER, OPT, CORE, 0)
.arg(0, BuiltInAtomicType.DURATION, OPT, EMPTY);
register("zero-or-one", TreatFn.class, OPT, 1, 1, Type.ITEM_TYPE, OPT, CORE, AS_ARG0)
.arg(0, Type.ITEM_TYPE, OPT | GIVE, null);
// because we don't do draconian static type checking, we can do the work in the argument type checking code
}
/**
* Get the table entry for the function with a given name
*
* @param name the name of the function. This may be an unprefixed local-name for functions in the
* system namespace, or may use the conventional prefix "saxon:" in the case of Saxon extension functions
* that are specially recognized
* @param arity the number of arguments of the function, or -1 if any arity will do
* @return if the function name is known, an Entry containing information about the function. Otherwise,
* null
*/
public static Entry getFunction(String name, int arity) {
if (arity == -1) {
for (int i = 0; i < 10; i++) {
Entry e = getFunction(name, i);
if (e != null) {
return e;
}
}
return null;
}
// try first for an entry of the form name#arity
Entry e = functionTable.get(name + '#' + arity);
if (e != null) {
return e;
}
// try for a generic entry
e = functionTable.get(name);
if (e != null && e.minArguments <= arity && e.maxArguments >= arity) {
return e;
}
return null;
}
/**
* An entry in the table describing the properties of a function
*/
public static class Entry implements java.io.Serializable {
/**
* The name of the function: a local name in the case of functions in the standard library, or a
* name with the conventional prefix "saxon:" in the case of Saxon extension functions
*/
public String name;
/**
* The class containing the implementation of this function (always a subclass of SystemFunction)
*/
public Class implementationClass;
/**
* Some classes support more than one function. In these cases the particular function is defined
* by an integer opcode, whose meaning is local to the implementation class.
*/
public int opcode;
/**
* The minimum number of arguments required
*/
public int minArguments;
/**
* The maximum number of arguments permitted
*/
public int maxArguments;
/**
* The item type of the result of the function
*/
public ItemType itemType;
/**
* The cardinality of the result of the function
*/
public int cardinality;
/**
* Flags indicating which host languages the function is applicable to
*/
public int applicability;
/**
* The syntactic context of each argument for the purposes of streamability analysis
*/
public int[] syntacticContext;
/**
* An array holding the types of the arguments to the function
*/
public SequenceType[] argumentTypes;
/**
* An array holding, for each declared argument, the value that is to be returned if an empty sequence
* as the value of this argument allows the result to be determined irrespective of the values of the
* other arguments; null if there is no such calculation possible
*/
public Sequence[] resultIfEmpty;
/**
* Any additional properties. Currently one bit is defined: SAME_AS_FIRST_ARGUMENT indicates that
* the result type is the same as the type of the first argument
*/
public int properties;
/**
* Add information to a function entry about the argument types of the function
*
* @param a the position of the argument, counting from zero
* @param type the item type of the argument
* @param options the cardinality and usage of the argument
* @param resultIfEmpty the value returned by the function if an empty sequence appears as the value
* of this argument, in the case when this result is unaffected by any other arguments. Supply null
* if this does not apply.
* @return this entry (to allow chaining)
*/
public Entry arg(int a, ItemType type, int options, /*@Nullable*/ Sequence resultIfEmpty) {
int cardinality = options & StaticProperty.CARDINALITY_MASK;
int syntacticContext = Expression.NAVIGATION_CONTEXT;
if ((options & TAKE) != 0) {
syntacticContext = Expression.NODE_VALUE_CONTEXT;
} else if ((options & GIVE) != 0) {
syntacticContext = Expression.INHERITED_CONTEXT;
} else if ((options & LOOK) != 0) {
syntacticContext = Expression.INSPECTION_CONTEXT;
} else if (type instanceof AtomicType) {
syntacticContext = Expression.NODE_VALUE_CONTEXT;
}
try {
this.argumentTypes[a] = SequenceType.makeSequenceType(type, cardinality);
this.resultIfEmpty[a] = resultIfEmpty;
this.syntacticContext[a] = syntacticContext;
} catch (ArrayIndexOutOfBoundsException err) {
System.err.println("Internal Saxon error: Can't set argument " + a + " of " + name);
}
return this;
}
}
}