Simplifies the path expression. @param cc compilation context @return original or optimized expression @throws QueryException query exception
(final CompileContext cc)
| 302 | * @throws QueryException query exception |
| 303 | */ |
| 304 | private Expr simplify(final CompileContext cc) throws QueryException { |
| 305 | // root yields no result |
| 306 | if(root != null && root.seqType().zero()) return cc.emptySeq(this); |
| 307 | |
| 308 | // find empty results, remove redundant steps |
| 309 | final int sl = steps.length; |
| 310 | boolean removed = false; |
| 311 | final ExprList list = new ExprList(sl); |
| 312 | for(int s = 0; s < sl; s++) { |
| 313 | final Expr step = steps[s]; |
| 314 | final Expr prev = list.isEmpty() ? root != null ? root : cc.qc.focus.value : list.peek(); |
| 315 | if(prev != null) { |
| 316 | final SeqType seqType = prev.seqType(); |
| 317 | if(seqType.type instanceof NodeType && (step instanceof ContextValue || |
| 318 | step instanceof final Step stp && stp.remove(seqType))) { |
| 319 | removed = true; |
| 320 | continue; |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | // step is empty sequence. example: $doc/NON-EXISTING-STEP → $doc/() → () |
| 325 | final Expr expr = steps[s]; |
| 326 | if(expr == Empty.VALUE) return cc.emptySeq(this); |
| 327 | |
| 328 | // add step to list |
| 329 | list.add(expr); |
| 330 | |
| 331 | // ignore remaining steps if step yields no results |
| 332 | // example: A/void(.)/B → A/void(.) |
| 333 | if(expr.seqType().zero() && s + 1 < sl) { |
| 334 | cc.info(QueryText.OPTSIMPLE_X_X, (Supplier<?>) this::description, this); |
| 335 | break; |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | // self step was removed: ensure that result will be in distinct document order |
| 340 | if(removed && (list.isEmpty() || !(list.get(0).seqType().type instanceof NodeType))) { |
| 341 | if(root == null) root = ContextValue.get(cc, info); |
| 342 | if(!root.ddo() && !root.seqType().mayBeWrapped()) { |
| 343 | root = cc.replaceWith(root, cc.function(Function.DISTINCT_ORDERED_NODES, info, root)); |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | // no steps left: return root |
| 348 | steps = list.finish(); |
| 349 | return cc.replaceWith(this, steps.length == 0 ? root : this); |
| 350 | } |
| 351 | |
| 352 | /** |
| 353 | * Returns the path nodes that will result from this path. |
no test coverage detected