net.sf.saxon.functions.hof.PartialApply 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
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2020 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.hof;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.om.Function;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SequenceTool;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.transpile.CSharpSuppressWarnings;
import net.sf.saxon.type.AnyFunctionType;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.SpecificFunctionType;
import net.sf.saxon.value.SequenceType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* This expression class implements the operation of currying (or performing partial application) of a function.
* That is, it takes a function and a set of argument bindings as input, and produces a new function as output.
*/
public class PartialApply extends Expression {
private final Operand baseOp;
private final Operand[] boundArgumentsOp; // contains null where the question marks appear
/**
* Create a partial function application expression
*
* @param base the expression that returns the function to be called
* @param boundArguments an array in which each element is either an expression to be bound to the corresponding
* argument, or null to represent a placeholder ("?" in the source syntax)
*/
public PartialApply(Expression base, Expression[] boundArguments) {
baseOp = new Operand(this, base, OperandRole.INSPECT);
adoptChildExpression(base);
boundArgumentsOp = new Operand[boundArguments.length];
for (int i=0; i operands() {
List operanda = new ArrayList(boundArgumentsOp.length + 1);
operanda.add(baseOp);
for (Operand o : boundArgumentsOp) {
if (o != null) {
operanda.add(o);
}
}
return operanda;
}
public int getNumberOfArguments() {
return boundArgumentsOp.length;
}
public Expression getArgument(int n) {
Operand o = boundArgumentsOp[n];
return o==null ? null : o.getChildExpression();
}
@Override
public int getImplementationMethod() {
return EVALUATE_METHOD;
}
/**
* Is this expression the same as another expression?
*
* @param other the expression to be compared with this one
* @return true if the two expressions are statically equivalent
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof PartialApply)) {
return false;
} else {
PartialApply pa2 = (PartialApply)other;
if (!getBaseExpression().isEqual(pa2.getBaseExpression())) {
return false;
}
if (boundArgumentsOp.length != pa2.boundArgumentsOp.length) {
return false;
}
for (int i=0; iThe toString() method for an expression attempts to give a representation of the expression
* in an XPath-like form.
* For subclasses of Expression that represent XPath expressions, the result should always be a string that
* parses as an XPath 3.0 expression. The expression produced should be equivalent to the original making certain
* assumptions about the static context. In general the expansion will make no assumptions about namespace bindings,
* except that (a) the prefix "xs" is used to refer to the XML Schema namespace, and (b) the default funcion namespace
* is assumed to be the "fn" namespace.
* In the case of XSLT instructions and XQuery expressions, the toString() method gives an abstracted view of the syntax
* that is not designed in general to be parseable.
*
* @return a representation of the expression as a string
*/
@Override
@CSharpSuppressWarnings("UnsafeIteratorConversion")
public String toString() {
StringBuilder buff = new StringBuilder(64);
boolean par = getBaseExpression().operands().iterator().hasNext();
if (par) {
buff.append("(" + getBaseExpression().toString() + ")");
} else {
buff.append(getBaseExpression().toString());
}
buff.append("(");
for (int i = 0; i < boundArgumentsOp.length; i++) {
if (boundArgumentsOp[i] == null) {
buff.append("?");
} else {
buff.append(boundArgumentsOp[i].getChildExpression().toString());
}
if (i != boundArgumentsOp.length - 1) {
buff.append(", ");
}
}
buff.append(")");
return buff.toString();
}
/**
* Evaluate this expression at run-time
*
* @param context The XPath dynamic evaluation context
* @return the result of the function, or null to represent an empty sequence
* @throws net.sf.saxon.trans.XPathException
* if a dynamic error occurs during evaluation of the function.
*/
@Override
public Function evaluateItem(XPathContext context) throws XPathException {
Function f = (Function) getBaseExpression().evaluateItem(context);
assert f != null;
Sequence[] values = new Sequence[boundArgumentsOp.length];
for (int i = 0; i < boundArgumentsOp.length; i++) {
if (boundArgumentsOp[i] == null) {
values[i] = null;
} else {
values[i] = SequenceTool.toGroundedValue(boundArgumentsOp[i].getChildExpression().iterate(context));
}
}
return new CurriedFunction(f, values);
}
/**
* Get a name identifying the kind of expression, in terms meaningful to a user.
*
* @return a name identifying the kind of expression, in terms meaningful to a user.
* The name will always be in the form of a lexical XML QName, and should match the name used
* in export() output displaying the expression.
*/
@Override
public String getExpressionName() {
return "partialApply";
}
}
// Copyright (c) 2011-2022 Saxonica Limited