Skip to content

Commit

Permalink
fix contextSequence for higher order functions; close eXist-db#1960
Browse files Browse the repository at this point in the history
  • Loading branch information
tuurma committed Feb 11, 2019
1 parent 51eb5e2 commit ddf4b3b
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 17 deletions.
32 changes: 16 additions & 16 deletions src/org/exist/xquery/functions/fn/FunHigherOrderFun.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
ref.analyze(cachedContextInfo);
for (final SequenceIterator i = args[1].iterate(); i.hasNext(); ) {
final Item item = i.nextItem();
final Sequence r = ref.evalFunction(contextSequence, null, new Sequence[]{item.toSequence()});
final Sequence r = ref.evalFunction(null, null, new Sequence[]{item.toSequence()});
result.addAll(r);
}
}
Expand All @@ -154,7 +154,7 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
ref.analyze(cachedContextInfo);
for (final SequenceIterator i = args[0].iterate(); i.hasNext(); ) {
final Item item = i.nextItem();
final Sequence r = ref.evalFunction(contextSequence, null, new Sequence[]{item.toSequence()});
final Sequence r = ref.evalFunction(null, null, new Sequence[]{item.toSequence()});
result.addAll(r);
}
}
Expand All @@ -174,7 +174,7 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
ref.analyze(cachedContextInfo);
for (final SequenceIterator i = seq.iterate(); i.hasNext(); ) {
final Item item = i.nextItem();
final Sequence r = ref.evalFunction(contextSequence, null, new Sequence[]{item.toSequence()});
final Sequence r = ref.evalFunction(null, null, new Sequence[]{item.toSequence()});
if (r.effectiveBooleanValue()) {
result.add(item);
}
Expand All @@ -185,19 +185,19 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
ref.analyze(cachedContextInfo);
final Sequence seq = args[0];
final Sequence zero = args[1];
result = foldLeft(ref, zero, seq.iterate(), contextSequence);
result = foldLeft(ref, zero, seq.iterate());
}
} else if (isCalledAs("fold-right")) {
try (final FunctionReference ref = (FunctionReference) args[2].itemAt(0)) {
ref.analyze(cachedContextInfo);
final Sequence zero = args[1];
final Sequence seq = args[0];
if (seq instanceof ValueSequence) {
result = foldRightNonRecursive(ref, zero, ((ValueSequence) seq).iterateInReverse(), contextSequence);
result = foldRightNonRecursive(ref, zero, ((ValueSequence) seq).iterateInReverse());
} else if (seq instanceof RangeSequence) {
result = foldRightNonRecursive(ref, zero, ((RangeSequence) seq).iterateInReverse(), contextSequence);
result = foldRightNonRecursive(ref, zero, ((RangeSequence) seq).iterateInReverse());
} else {
result = foldRight(ref, zero, seq, contextSequence);
result = foldRight(ref, zero, seq);
}
}
} else if (isCalledAs("map-pairs")) {
Expand All @@ -206,7 +206,7 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
final SequenceIterator i1 = args[1].iterate();
final SequenceIterator i2 = args[2].iterate();
while (i1.hasNext() && i2.hasNext()) {
final Sequence r = ref.evalFunction(contextSequence, null,
final Sequence r = ref.evalFunction(null, null,
new Sequence[]{i1.nextItem().toSequence(), i2.nextItem().toSequence()});
result.addAll(r);
}
Expand All @@ -217,7 +217,7 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
final SequenceIterator i1 = args[0].iterate();
final SequenceIterator i2 = args[1].iterate();
while (i1.hasNext() && i2.hasNext()) {
final Sequence r = ref.evalFunction(contextSequence, null,
final Sequence r = ref.evalFunction(null, null,
new Sequence[]{i1.nextItem().toSequence(), i2.nextItem().toSequence()});
result.addAll(r);
}
Expand All @@ -237,12 +237,12 @@ public Sequence eval(Sequence[] args, Sequence contextSequence)
return result;
}

private Sequence foldLeft(final FunctionReference ref, Sequence accum, final SequenceIterator seq, final Sequence contextSequence) throws XPathException {
private Sequence foldLeft(final FunctionReference ref, Sequence accum, final SequenceIterator seq) throws XPathException {
final Sequence refArgs[] = new Sequence[2];
while(seq.hasNext()) {
refArgs[0] = accum;
refArgs[1] = seq.nextItem().toSequence();
accum = ref.evalFunction(contextSequence, null, refArgs);
accum = ref.evalFunction(null, null, refArgs);
}
return accum;
}
Expand All @@ -253,22 +253,22 @@ private Sequence foldLeft(final FunctionReference ref, Sequence accum, final Seq
*
* @param seq An iterator which moves from right to left
*/
private Sequence foldRightNonRecursive(final FunctionReference ref, Sequence accum, final SequenceIterator seq, final Sequence contextSequence) throws XPathException {
private Sequence foldRightNonRecursive(final FunctionReference ref, Sequence accum, final SequenceIterator seq) throws XPathException {
final Sequence refArgs[] = new Sequence[2];
while (seq.hasNext()) {
refArgs[0] = seq.nextItem().toSequence();
refArgs[1] = accum;
accum = ref.evalFunction(contextSequence, null, refArgs);
accum = ref.evalFunction(null, null, refArgs);
}
return accum;
}

private Sequence foldRight(final FunctionReference ref, final Sequence zero, final Sequence seq, final Sequence contextSequence) throws XPathException {
private Sequence foldRight(final FunctionReference ref, final Sequence zero, final Sequence seq) throws XPathException {
if (seq.isEmpty()) {
return zero;
}
final Sequence head = seq.itemAt(0).toSequence();
final Sequence tailResult = foldRight(ref, zero, seq.tail(), contextSequence);
return ref.evalFunction(contextSequence, null, new Sequence[] { head, tailResult });
final Sequence tailResult = foldRight(ref, zero, seq.tail());
return ref.evalFunction(null, null, new Sequence[] { head, tailResult });
}
}
110 changes: 109 additions & 1 deletion test/src/xquery/xquery3/arrowop.xql
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,116 @@ declare function ao:B($x) {
string-length($x)
};

declare
%private
function ao:wrap-with-explicit-type-conversion ($item as item()) as item() {
<wrap>{xs:string($item)}</wrap>
};

declare
%test:assertEquals(10)
function ao:function-declared-later() {
ao:A("hello")
};
};

(:~
the tests below (`ao:wrap-*`) were added because of
https://github.com/exist-db/exist/issues/1960
~:)
declare
%private
function ao:wrap ($item as item()) as item() {
<wrap>{$item}</wrap>
};

declare
%private
function ao:first-element-text ($s as node()*) as text() {
$s[1]/text()
};

declare
%test:assertEquals("1")
function ao:wrap-atomic-sequence () {
(1, 2, 3)
=> for-each(ao:wrap#1)
=> ao:first-element-text()
};

declare
%test:assertEquals("1")
function ao:wrap-atomic-sequence-with-explicit-type-conversion () {
(1, 2, 3)
=> for-each(ao:wrap-with-explicit-type-conversion#1)
=> ao:first-element-text()
};

declare
%private
function ao:get-i-elements ($i as item()) { $i//i };

(:~
must be 3 not 9
closes https://github.com/exist-db/exist/issues/1960
~:)
declare
%test:assertEquals(3)
function ao:wrap-element-sequence () {
let $xml := <root><i/><i/><i/></root>
return $xml/node()
=> for-each(ao:wrap#1)
=> for-each(ao:get-i-elements#1)
=> count()
};

(:~
must not fail with duplicate attribute exception err:XQDY0025
closes https://github.com/exist-db/exist/issues/1960
~:)
declare
%test:assertEquals('1')
function ao:wrap-attribute-from-sequence () {
(<item n="1"/>, <item n="2"/>, <item n="3"/>)
=> for-each(function ($item as item()) as element(a) { <a>{$item/@n}</a> })
=> (function($sequence) {
$sequence[1]/@n/string()
})()
};

declare
%test:assertError('XPDY0002')
function ao:filter-with-contextitem () {
(<item n="1"/>, <item n="2"/>, <item n="3"/>)
=> filter(function ($item as item()) { . })
=> count()
};

declare
%test:assertEquals('abcd')
function ao:fold-left-with-contextitem () {
(<a/>,<b/>,<c/>,<d/>)
=> fold-left('', function ($r, $a) { $r || xs:string(node-name($a)) })
};

declare
%test:assertEquals('dcba')
function ao:fold-right-with-contextitem () {
(<a/>,<b/>,<c/>,<d/>)
=> fold-right('', function ($a, $r) { $r || xs:string(node-name($a)) })
};

declare
%test:assertEquals('dcba')
function ao:fold-right-with-contextitem () {
('a','b','c','d')
=> fold-right('', function ($a, $r) { $r || $a })
};

declare
%test:assertEquals('aabbaabb')
function ao:for-each-pair-with-contextitem () {
(<a/>,<b/>,<a/>,<b/>)
=> for-each-pair((<a/>,<b/>,<a/>,<b/>), function ($a, $b) { node-name($a) || node-name($b) })
=> string-join()
};

0 comments on commit ddf4b3b

Please sign in to comment.