MCPcopy Create free account
hub / github.com/BaseXdb/basex / flattenEbv

Method flattenEbv

basex-core/src/main/java/org/basex/query/expr/Preds.java:240–299  ·  view source on GitHub ↗

Flattens predicates for boolean evaluation. Drops solitary context values, flattens nested predicates. @param root root expression @param ebv EBV check @param cc compilation context @return optimized or original expression @throws QueryException query exception

(final Expr root, final boolean ebv, final CompileContext cc)

Source from the content-addressed store, hash-verified

238 * @throws QueryException query exception
239 */
240 public final Expr flattenEbv(final Expr root, final boolean ebv, final CompileContext cc)
241 throws QueryException {
242
243 // only single predicate can be rewritten; root must yield nodes; no positional predicates
244 final SeqType rst = root.seqType();
245 final int el = exprs.length;
246 if(el == 0 || mayBePositional()) return this;
247
248 final Expr last = exprs[el - 1];
249 final QuerySupplier<Expr> createRoot = () ->
250 root instanceof final Path path ? path.removePredicate(cc) :
251 el > 1 ? Filter.get(cc, info, root, Arrays.copyOfRange(exprs, 0, el - 1)) : root;
252 final QueryFunction<Expr, Expr> createSimpleMap = rhs ->
253 SimpleMap.get(cc, info, createRoot.get(), rhs);
254 final QueryBiFunction<Expr, Boolean, Expr> createExpr = (rhs, compare) ->
255 rhs instanceof ContextValue ? createRoot.get() :
256 rhs instanceof Path ? Path.get(cc, info, createRoot.get(), rhs) :
257 compare ? createSimpleMap.apply(rhs) : this;
258
259 if(rst.type instanceof NodeType) {
260 // rewrite to path: root[path] → root/path
261 final Expr expr = createExpr.apply(last, false);
262 if(expr != this) return expr;
263 } else if(ebv) {
264 return this;
265 }
266
267 // rewrite to general comparison
268 // a[. = 'x'] → a = 'x'
269 // a[@id eq 'id1'] → a/@id = 'id1'
270 // a[text() = data(.)] → skip: right operand must not depend on context
271 // a[b eq ('a', 'b')] → skip: an error must be raised as right operand yields a sequence
272 if(last instanceof final Cmp cmp) {
273 final Expr op1 = cmp.exprs[0], op2 = cmp.exprs[1];
274 final SeqType st1 = op1.seqType(), st2 = op2.seqType();
275 final Type type1 = st1.type, type2 = st2.type;
276 if((cmp instanceof CmpG || cmp instanceof CmpV && st1.zeroOrOne() && st2.zeroOrOne() && (
277 type1 == type2 || type1.isStringOrUntyped() && type2.isStringOrUntyped()
278 )) && !op2.has(Flag.CTX)) {
279 final Expr expr = createExpr.apply(op1, true);
280 if(expr != this) return new CmpG(cmp.info, expr, op2, cmp.cmpOp()).optimize(cc);
281 }
282 }
283
284 // rewrite to contains text expression (right operand must not depend on context):
285 // a[. contains text 'x'] → a contains text 'x'
286 // a[text() contains text 'x'] → a/text() contains text 'x'
287 if(last instanceof final FTContains cmp) {
288 final FTExpr ftexpr = cmp.ftexpr;
289 if(!ftexpr.has(Flag.CTX)) {
290 final Expr expr = createExpr.apply(cmp.expr, true);
291 if(expr != this) return new FTContains(expr, ftexpr, cmp.info).optimize(cc);
292 }
293 }
294
295 // rewrite to simple map: $node[string()] → $node ! string()
296 if(rst.zeroOrOne()) return createSimpleMap.apply(last);
297

Callers 3

simplifyForMethod · 0.80
simplifyForMethod · 0.80
optMethod · 0.80

Calls 15

mayBePositionalMethod · 0.95
getMethod · 0.95
getMethod · 0.95
getMethod · 0.95
seqTypeMethod · 0.95
zeroOrOneMethod · 0.95
isStringOrUntypedMethod · 0.95
hasMethod · 0.95
hasMethod · 0.95
seqTypeMethod · 0.65
getMethod · 0.65
applyMethod · 0.65

Tested by

no test coverage detected