Merges adjacent steps. @param curr current step @param next next step @param prev previous step (can be null) @param cc compilation context @return merged expression or null @throws QueryException query exception
(final Step curr, final Expr next, final Expr prev,
final CompileContext cc)
| 1040 | * @throws QueryException query exception |
| 1041 | */ |
| 1042 | private static Expr mergeStep(final Step curr, final Expr next, final Expr prev, |
| 1043 | final CompileContext cc) throws QueryException { |
| 1044 | |
| 1045 | // do not merge if current step contains positional predicates |
| 1046 | if(curr.mayBePositional()) return null; |
| 1047 | |
| 1048 | // merge self steps: child::*/self::a → child::a |
| 1049 | final Step nxt = next instanceof final Step stp ? stp : null; |
| 1050 | if(nxt != null && nxt.axis == SELF && !nxt.mayBePositional()) { |
| 1051 | final Test test = curr.test.intersect(nxt.test); |
| 1052 | return test == null ? null : |
| 1053 | Step.get(cc, prev, curr.info(), curr.axis, test, ExprList.concat(curr.exprs, nxt.exprs)); |
| 1054 | } |
| 1055 | |
| 1056 | // merge descendant-or-self step |
| 1057 | if(curr.axis != DESCENDANT_OR_SELF || curr.exprs.length > 0 || |
| 1058 | !curr.test.kind.oneOf(Kind.NODE, Kind.JNODE, Kind.GNODE)) return null; |
| 1059 | |
| 1060 | // examples: |
| 1061 | // - descendant-or-self::node()/* → descendant::* |
| 1062 | // - descendant-or-self::node()/descendant::* → descendant::* |
| 1063 | // - descendant-or-self::node()/descendant-or-self::* → descendant-or-self::* |
| 1064 | final Axis merged = mergedAxis(nxt); |
| 1065 | if(merged != null) return Step.get(cc, prev, nxt.info(), merged, nxt.test, nxt.exprs); |
| 1066 | |
| 1067 | // function for merging steps inside union expressions |
| 1068 | final QueryFunction<Expr, Expr> rewrite = expr -> { |
| 1069 | if(expr instanceof Union) { |
| 1070 | final Axis axis = commonAxis(expr.args()); |
| 1071 | if(axis != null) { |
| 1072 | for(final Expr path : expr.args()) { |
| 1073 | final Path p = (Path) path; |
| 1074 | final Step s = (Step) p.steps[0]; |
| 1075 | p.steps[0] = Step.get(cc, prev, s.info(), axis, s.test, s.exprs); |
| 1076 | } |
| 1077 | return expr.optimize(cc); |
| 1078 | } |
| 1079 | } |
| 1080 | return null; |
| 1081 | }; |
| 1082 | // descendant-or-self::node()/(* | text()) → (descendant::text() | (descendant::*) |
| 1083 | if(next instanceof Union) return rewrite.apply(next); |
| 1084 | |
| 1085 | // descendant-or-self::node()/(text()|*)[..] → (descendant::text() | descendant::*)[..] |
| 1086 | if(next instanceof final Filter filter && !filter.mayBePositional()) { |
| 1087 | final Expr expr = rewrite.apply(filter.root); |
| 1088 | if(expr != null) return Filter.get(cc, filter.info(), expr, filter.exprs); |
| 1089 | } |
| 1090 | return null; |
| 1091 | } |
| 1092 | |
| 1093 | /** |
| 1094 | * Returns a merged axis for a step preceded by a descendant-or-self step. |
no test coverage detected