Tries to merge paths. @param cc compilation context @return merged expression or null @throws QueryException query exception
(final CompileContext cc)
| 107 | * @throws QueryException query exception |
| 108 | */ |
| 109 | private Expr mergePaths(final CompileContext cc) throws QueryException { |
| 110 | Expr root = null; |
| 111 | Axis axis = null; |
| 112 | final int sl = exprs.length; |
| 113 | final ArrayList<Step> steps = new ArrayList<>(sl); |
| 114 | |
| 115 | // collect common root, common axis, and individual steps |
| 116 | for(final Expr expr : exprs) { |
| 117 | if(!(expr instanceof final Path path)) return null; |
| 118 | if(path.steps.length != 1 || !(path.steps[0] instanceof final Step step)) return null; |
| 119 | if(steps.isEmpty()) { |
| 120 | root = path.root; |
| 121 | axis = step.axis; |
| 122 | if(root != null && root.has(Flag.CNS, Flag.NDT)) return null; |
| 123 | } else if(!Objects.equals(root, path.root) || axis != step.axis) { |
| 124 | // further operands: abort if root or axis differs |
| 125 | return null; |
| 126 | } |
| 127 | // do not merge paths with positional predicates |
| 128 | if(step.mayBePositional()) return null; |
| 129 | steps.add(step); |
| 130 | } |
| 131 | |
| 132 | // try to merge tests (precondition: predicates are identical) |
| 133 | Expr[] preds = null; |
| 134 | final ArrayList<Test> tests = new ArrayList<>(sl); |
| 135 | for(int s = 0; s < sl; s++) { |
| 136 | final Step step = steps.get(s); |
| 137 | if(preds == null) { |
| 138 | preds = step.exprs; |
| 139 | } else if(!Arrays.equals(preds, step.exprs)) { |
| 140 | preds = null; |
| 141 | break; |
| 142 | } |
| 143 | tests.add(step.test); |
| 144 | } |
| 145 | |
| 146 | Test test = null; |
| 147 | if(preds != null) { |
| 148 | if(this instanceof Union) { |
| 149 | // a union b → (a|b) |
| 150 | test = Test.get(tests); |
| 151 | } else if(this instanceof Intersect) { |
| 152 | // * intersect a → a, a intersect b → () |
| 153 | for(final Test t : tests) { |
| 154 | if(test == null || t.instanceOf(test)) { |
| 155 | test = t; |
| 156 | } else if(test.intersect(t) == null) { |
| 157 | return Empty.VALUE; |
| 158 | } |
| 159 | } |
| 160 | } else { |
| 161 | // a except a → (), a except * → () |
| 162 | for(final Test t : tests) { |
| 163 | if(test == null) { |
| 164 | test = t; |
| 165 | } else if(test.instanceOf(t)) { |
| 166 | return Empty.VALUE; |
no test coverage detected