Skip to content

Commit

Permalink
also do map/array to function coercion if argument type is function(*)
Browse files Browse the repository at this point in the history
  • Loading branch information
benibela committed Jun 30, 2024
1 parent 6b3b03f commit 3353112
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 16 deletions.
2 changes: 2 additions & 0 deletions data/tests/xpath3_1_tests.pas
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ procedure unittests(testerrors: boolean);
t('for-each("a", map { "a": 123 } )', '123');
t('for-each(2, [ "1", 9 ])', '9');
f('for-each("2", [ "1", 9 ])', 'XPTY0004');
t('count(function-name([]))', '0');
t('function-arity([])', '1');

t('(map {}, array {}) ! (position(), . instance of map(*), . instance of map(string,string), '+
'. instance of array(*), . instance of array(string), ' +
Expand Down
1 change: 1 addition & 0 deletions data/xquery.pas
Original file line number Diff line number Diff line change
Expand Up @@ -3444,6 +3444,7 @@ type TXQGlobalTypes = record
function star(t: TXQTermSequenceType): TXQTermSequenceType;
function f(args: array of TXQTermSequenceType): TXQTermSequenceType;
public
functionFromArray, functionFromMap: array[0..1] of TXQTermSequenceType;
case boolean of
true: (
none,
Expand Down
5 changes: 5 additions & 0 deletions data/xquery_schemas.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,11 @@ begin
nodeMatching.namespaceURLOrPrefix := 'http://www.w3.org/2010/xslt-xquery-serialization'
end;
elementSerializationParamsOrEmpty := orEmpty(elementSerializationParams);

functionFromArray[0] := integer; //is that correct?
functionFromArray[1] := itemStar;
functionFromMap[0] := atomic;
functionFromMap[1] := itemStar;
end;

procedure TXQGlobalTypes.free;
Expand Down
45 changes: 29 additions & 16 deletions data/xquery_terms.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1217,21 +1217,39 @@ begin
exit(false);
end;

procedure dynamicCallForwardArguments(fresult: TXQBoxedFunction; const v: IXQValue; arguments: array of TXQTermSequenceType);
var i: SizeInt;
tempvar: TXQTermVariable;
begin
fresult.ownsTerms := true;
fresult.body := TXQTermDynamicFunctionCall.create(TXQTermConstant.Create(v));
setlength(fresult.parameters, length(arguments) - 1);
for i := 0 to high(fresult.parameters) do begin
tempvar := TXQTermVariable.create(IntToStr(i)+'.');
tempvar.index := high(fresult.parameters);
TXQTermDynamicFunctionCall(fresult.body).push(tempvar);
fresult.parameters[i].variable := TXQTermVariable(TXQTermDynamicFunctionCall(fresult.body).children[high(TXQTermDynamicFunctionCall(fresult.body).children)].clone);
fresult.parameters[i].seqtype := TXQTermSequenceType(arguments[i].clone);
end;
fresult.resulttype := TXQTermSequenceType(arguments[high(arguments)].clone);
end;

function TXQTermSequenceType.functionCoercion(const context: TXQStaticContext; const v: IXQValue): IXQValue;
var
fun: TXQBoxedFunction;
needCoercion: Boolean;
needCoercion, isWildcardFunction: Boolean;
i: SizeInt;
fresult: TXQBoxedFunction;
tempvar: TXQTermVariable;

begin
//function coercion f(v, w, ..)=>s passed to f(a, b, ..)=>r becomes f(a intersect v, b intersect w, ..)=>r intersect s
//if v.kind <> pvkFunction then raise EXQEvaluationException.Create('XPTY0004', 'Expected function, but got : '+result.toXQuery());

//note: function coercion is only used with strict type checking enabled
if length(arguments) = 0 then exit(v);
isWildcardFunction := length(arguments) = 0;
case v.kind of
pvkFunction: begin
if isWildcardFunction then exit(v);
fun := v.getDataFunction;
if (length(arguments) <> length(fun.parameters) + 1) then raise EXQEvaluationException.Create('XPTY0004', 'Invalid argument count');
needCoercion := false;
Expand All @@ -1252,29 +1270,24 @@ begin
copyAnnotations(fresult.annotations, fun.annotations);
fresult.context := fun.context;
fresult.context.sharedEvaluationContext := nil;
dynamicCallForwardArguments(fresult, v, arguments);
end;
pvkObject, pvkArray: begin
if (length(arguments) <> 1 + 1) then raise EXQEvaluationException.Create('XPTY0004', 'Invalid argument count');
if not (isWildcardFunction or (length(arguments) = 1 + 1)) then
raise EXQEvaluationException.Create('XPTY0004', 'Invalid argument count');
fresult := TXQBoxedFunction.create();
fresult.context.staticContext := context; //currently only used for strict type checking of array indices
if isWildcardFunction then begin
if v.kind = pvkArray then dynamicCallForwardArguments(fresult, v, globalTypes.functionFromArray)
else dynamicCallForwardArguments(fresult, v, globalTypes.functionFromMap);
end else dynamicCallForwardArguments(fresult, v, arguments);
end;
else begin
raiseInternalError(2019010223);
exit(xqvalue);
end;
end;
//see TXQTermDefineFunction.defineDynamicPartialApplication
fresult.context.staticContext := context; //currently only used for strict type checking of array indices
fresult.body := TXQTermDynamicFunctionCall.create(TXQTermConstant.Create(v));
setlength(fresult.parameters, length(arguments) - 1);
for i := 0 to high(fresult.parameters) do begin
tempvar := TXQTermVariable.create(IntToStr(i)+'.');
tempvar.index := high(fresult.parameters);
TXQTermDynamicFunctionCall(fresult.body).push(tempvar);
fresult.parameters[i].variable := TXQTermVariable(TXQTermDynamicFunctionCall(fresult.body).children[high(TXQTermDynamicFunctionCall(fresult.body).children)].clone);
fresult.parameters[i].seqtype := TXQTermSequenceType(arguments[i].clone);
end;
fresult.ownsTerms := true;
fresult.resulttype := TXQTermSequenceType(arguments[high(arguments)].clone);
result := xqvalue(fresult);
end;

Expand Down

0 comments on commit 3353112

Please sign in to comment.