Skip to content

Commit 0f8652c

Browse files
Merge branch 'main' of github.com:BaseXdb/basex
2 parents 9ce1901 + 70fe459 commit 0f8652c

4 files changed

Lines changed: 97 additions & 3 deletions

File tree

basex-core/src/main/java/org/basex/query/func/Function.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,9 @@ ITEM_ZM, flag(HOF)),
525525
PARSE_XML_FRAGMENT(FnParseXmlFragment::new, "parse-xml-fragment(value[,options])",
526526
params(ANY_ATOMIC_TYPE_ZO, MAP_ZO), DOCUMENT_NODE_ZO, flag(CNS)),
527527
/** XQuery function. */
528+
PARTIAL_APPLY(FnPartialApply::new, "partial-apply(function,arguments)",
529+
params(FUNCTION_O, MAP_O), FUNCTION_O, flag(HOF)),
530+
/** XQuery function. */
528531
PARTITION(FnPartition::new, "partition(input,split-when)",
529532
params(ITEM_ZM, FuncType.get(BOOLEAN_ZO, ITEM_ZM, ITEM_O, INTEGER_O).seqType()),
530533
ARRAY_ZM, flag(HOF)),

basex-core/src/main/java/org/basex/query/func/fn/FnApply.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ protected Expr opt(final CompileContext cc) throws QueryException {
7373
protected final Value apply(final FItem func, final ValueList args, final QueryContext qc)
7474
throws QueryException {
7575
final long ar = func.arity(), as = args.size();
76-
if(ar != as) throw APPLY_X_X.get(info, arguments(as), func, args);
76+
if(ar > as) throw APPLY_X_X.get(info, arguments(as), func, args);
7777
return func.invoke(qc, info, args.finish());
7878
}
7979

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.basex.query.func.fn;
2+
3+
import static org.basex.query.value.type.SeqType.*;
4+
5+
import java.util.*;
6+
7+
import org.basex.query.*;
8+
import org.basex.query.expr.*;
9+
import org.basex.query.func.*;
10+
import org.basex.query.util.list.*;
11+
import org.basex.query.value.*;
12+
import org.basex.query.value.item.*;
13+
import org.basex.query.value.map.*;
14+
import org.basex.query.value.seq.*;
15+
import org.basex.query.value.type.*;
16+
import org.basex.query.var.*;
17+
18+
/**
19+
* Function implementation.
20+
*
21+
* @author BaseX Team, BSD License
22+
* @author Gunther Rademacher
23+
*/
24+
public class FnPartialApply extends StandardFunc {
25+
/** The type of parameter "arguments". */
26+
private static final SeqType ARGS_TYPE = MapType.get(AtomType.POSITIVE_INTEGER,
27+
ITEM_ZM).seqType();
28+
/** The name of parameter "arguments". */
29+
private static final QNm ARGS_NAME = new QNm("arguments");
30+
31+
@Override
32+
public Value value(final QueryContext qc) throws QueryException {
33+
final FItem function = toFunction(arg(0), qc);
34+
final XQMap arguments = toMap(ARGS_TYPE.coerce(arg(1).value(qc), ARGS_NAME, qc, null, info),
35+
qc);
36+
final int arity = function.arity();
37+
if(arity == 0 || arguments == XQMap.empty()) return function;
38+
39+
final FuncType ft = function.funcType();
40+
final Expr[] funcArgs = new Expr[arity];
41+
Arrays.fill(funcArgs, Empty.UNDEFINED);
42+
int placeholders = arity;
43+
for(final Item key : arguments.keys()) {
44+
final long index = toLong(key);
45+
if(index <= arity) {
46+
final int i = (int) index - 1;
47+
funcArgs[i] = ft.argTypes[i].coerce(arguments.get(key), function.paramName(i), qc, null,
48+
info);
49+
--placeholders;
50+
}
51+
}
52+
if(placeholders == arity) return function;
53+
54+
final DynFuncCall funcCall;
55+
final Var[] params = new Var[placeholders];
56+
final SeqType[] argTypes = new SeqType[placeholders];
57+
if(placeholders == 0) {
58+
funcCall = new DynFuncCall(info, function, funcArgs);
59+
} else {
60+
final VarScope vs = new VarScope();
61+
final Expr[] args = new Expr[placeholders];
62+
int p = 0;
63+
for(int i = 0; i < arity; ++i) {
64+
if(funcArgs[i] == Empty.UNDEFINED) {
65+
final Var var = vs.addNew(function.paramName(i), ft.argTypes[i], qc, info);
66+
params[p] = var;
67+
args[p++] = new VarRef(info, var);
68+
}
69+
}
70+
funcCall = new DynFuncCall(info,
71+
new PartFunc(info, ExprList.concat(funcArgs, function), placeholders, null), args);
72+
}
73+
return new FuncItem(info, funcCall, params, AnnList.EMPTY, FuncType.get(ft.declType, argTypes),
74+
params.length, null);
75+
}
76+
77+
@Override
78+
public int hofIndex() {
79+
return 0;
80+
}
81+
}

basex-core/src/test/java/org/basex/query/func/FnModuleTest.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public final class FnModuleTest extends SandboxTest {
180180
query("for $a in 2 to 3 "
181181
+ "let $f := function-lookup(xs:QName('fn:concat'), $a) "
182182
+ "return " + func.args(" $f", " array { 1 to $a }"), "12\n123");
183-
error(func.args(" false#0", " ['x']"), APPLY_X_X);
183+
query(func.args(" false#0", " ['x']"), false);
184184
error(func.args(" string-length#1", " [ ('a', 'b') ]"), INVCONVERT_X_X_X);
185185

186186
// no pre-evaluation (higher-order arguments), but type adjustment
@@ -194,7 +194,8 @@ public final class FnModuleTest extends SandboxTest {
194194

195195
// code coverage tests
196196
query("string-length(" + func.args(" reverse#1", " ['a']") + ")", 1);
197-
error(func.args(" true#0", " [1]"), APPLY_X_X);
197+
query(func.args(" true#0", " [1]"), true);
198+
error(func.args(" concat#2", " ['x']"), APPLY_X_X);
198199
error(func.args(" put#2", " [<_/>, '']"), FUNCUP_X);
199200
}
200201

@@ -2350,6 +2351,15 @@ public final class FnModuleTest extends SandboxTest {
23502351
+ "\u20AC</x><y>\u20AF</y>", "ISO-8859-7")), "<x>\u20AC</x><y>\u20AF</y>");
23512352
}
23522353

2354+
/** Test method. */
2355+
@Test public void partialApply() {
2356+
final Function func = PARTIAL_APPLY;
2357+
2358+
query("let $f := " + func.args(" dateTime#2", " {2: xs:time('00:00:00')}") + " return $f("
2359+
+ "xs:date('2025-03-01'))", "2025-03-01T00:00:00");
2360+
error(func.args(" string-length#1", " {1: 42}"), INVCONVERT_X_X_X);
2361+
}
2362+
23532363
/** Test method. */
23542364
@Test public void partition() {
23552365
final Function func = PARTITION;

0 commit comments

Comments
 (0)