Skip to content

Commit 31c66f5

Browse files
Merge branch 'qt2591'
2 parents d4cde3a + 610ba97 commit 31c66f5

2 files changed

Lines changed: 55 additions & 27 deletions

File tree

basex-core/src/main/java/org/basex/query/QueryParser.java

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2482,10 +2482,10 @@ private Expr step(final boolean error) throws QueryException {
24822482
/**
24832483
* Parses the "AxisStep" rule.
24842484
* @param error show error if nothing is found
2485-
* @return step or {@code null}
2485+
* @return step, lookup expression, or {@code null}
24862486
* @throws QueryException query exception
24872487
*/
2488-
private Step axisStep(final boolean error) throws QueryException {
2488+
private Expr axisStep(final boolean error) throws QueryException {
24892489
Axis axis = null;
24902490
ExprInfo test = null;
24912491
if(wsConsume("..")) {
@@ -2535,11 +2535,16 @@ private Step axisStep(final boolean error) throws QueryException {
25352535
checkPred(false);
25362536
}
25372537

2538-
// step with node test
2538+
// step with node test or selector
25392539
final InputInfo ii = info();
2540-
if(test instanceof final Test t) return new CachedStep(ii, axis, t, preds.finish());
2541-
// step with selector
2542-
return new SelectorStep(ii, axis, (Expr) test, preds.finish());
2540+
final Step step = test instanceof final Test t
2541+
? new CachedStep(ii, axis, t, preds.finish())
2542+
: new SelectorStep(ii, axis, (Expr) test, preds.finish());
2543+
2544+
// an axis step may be followed by lookups and further predicates (#2591)
2545+
if(!current('?')) return step;
2546+
final Expr lookup = lookup(Path.get(ii, null, step));
2547+
return lookup == null ? step : postfixOps(lookup, true);
25432548
}
25442549

25452550
/**
@@ -2647,29 +2652,40 @@ private Test simpleNodeTest(final Kind kind, final boolean all) throws QueryExce
26472652
* @throws QueryException query exception
26482653
*/
26492654
private Expr postfix() throws QueryException {
2650-
Expr expr = primary();
2651-
if(expr != null) {
2652-
while(true) {
2653-
if(wsConsume("[")) {
2654-
final ExprList el = new ExprList();
2655-
do {
2656-
add(el, expr());
2657-
wsCheck("]");
2658-
} while(wsConsume("["));
2659-
expr = new CachedFilter(info(), expr, el.finish());
2660-
} else if(consume("=?>")) {
2661-
expr = methodCall(expr);
2662-
} else if(current('(')) {
2663-
expr = Functions.dynamic(expr, argumentList(false, null));
2664-
} else if(current('?')) {
2665-
expr = lookup(expr);
2666-
if(expr == null) break;
2667-
} else {
2668-
break;
2669-
}
2655+
final Expr expr = primary();
2656+
return expr != null ? postfixOps(expr, false) : null;
2657+
}
2658+
2659+
/**
2660+
* Parses the postfix operators that may follow a primary expression or an axis step.
2661+
* @param expr input expression
2662+
* @param axis parse the tail of an axis step (only predicates and lookups are allowed)
2663+
* @return resulting expression
2664+
* @throws QueryException query exception
2665+
*/
2666+
private Expr postfixOps(final Expr expr, final boolean axis) throws QueryException {
2667+
Expr result = expr;
2668+
while(true) {
2669+
if(wsConsume("[")) {
2670+
final ExprList el = new ExprList();
2671+
do {
2672+
add(el, expr());
2673+
wsCheck("]");
2674+
} while(wsConsume("["));
2675+
result = new CachedFilter(info(), result, el.finish());
2676+
} else if(!axis && consume("=?>")) {
2677+
result = methodCall(result);
2678+
} else if(!axis && current('(')) {
2679+
result = Functions.dynamic(result, argumentList(false, null));
2680+
} else if(current('?')) {
2681+
final Expr lookup = lookup(result);
2682+
if(lookup == null) break;
2683+
result = lookup;
2684+
} else {
2685+
break;
26702686
}
26712687
}
2672-
return expr;
2688+
return result;
26732689
}
26742690

26752691
/**

basex-core/src/test/java/org/basex/query/expr/LookupTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ public final class LookupTest extends SandboxTest {
7272
query("array:for-each([], function($i) { string($i) })!?([])", "");
7373
}
7474

75+
/** Lookup directly following an axis step (#2591). */
76+
@Test public void step() {
77+
query("{ 'a': 1, 'b': 2 } ! self::jnode()?b", 2);
78+
query("{ 'a': 1, 'b': 2 } ! self::jnode()?*", "1\n2");
79+
query("{ 'a': { 'b': 5 } } ! self::jnode()?a?b", 5);
80+
// predicate before and after the lookup
81+
query("{ 'a': 1 } ! self::jnode()[1]?a", 1);
82+
query("{ 'a': (1, 2, 3) } ! self::jnode()?a[. > 1]", "2\n3");
83+
// one lookup per context item
84+
query("({ 'k': 7 }, { 'k': 8 }) ! self::jnode()?k", "7\n8");
85+
}
86+
7587
/** Test. */
7688
@Test public void error() {
7789
error("1?a", LOOKUP_X);

0 commit comments

Comments
 (0)