@Override public Expr optimize(final QueryContext qc, final VarScope scp) throws QueryException { // number of predicates may change in loop for (int p = 0; p < preds.length; p++) { final Expr pred = preds[p]; if (pred instanceof CmpG || pred instanceof CmpV) { final Cmp cmp = (Cmp) pred; if (cmp.exprs[0].isFunction(Function.POSITION)) { final Expr e2 = cmp.exprs[1]; final SeqType st2 = e2.seqType(); // position() = last() -> last() // position() = $n (numeric) -> $n if (e2.isFunction(Function.LAST) || st2.one() && st2.type.isNumber()) { if (cmp instanceof CmpG && ((CmpG) cmp).op == OpG.EQ || cmp instanceof CmpV && ((CmpV) cmp).op == OpV.EQ) { qc.compInfo(OPTWRITE, pred); preds[p] = e2; } } } } else if (pred instanceof And) { if (!pred.has(Flag.FCS)) { // replace AND expression with predicates (don't swap position tests) qc.compInfo(OPTPRED, pred); final Expr[] and = ((Arr) pred).exprs; final int m = and.length - 1; final ExprList el = new ExprList(preds.length + m); for (final Expr e : Arrays.asList(preds).subList(0, p)) el.add(e); for (final Expr a : and) { // wrap test with boolean() if the result is numeric el.add(Function.BOOLEAN.get(null, info, a).optimizeEbv(qc, scp)); } for (final Expr e : Arrays.asList(preds).subList(p + 1, preds.length)) el.add(e); preds = el.finish(); } } else if (pred instanceof ANum) { final ANum it = (ANum) pred; final long i = it.itr(); if (i == it.dbl()) { preds[p] = Pos.get(i, info); } else { qc.compInfo(OPTREMOVE, this, pred); return Empty.SEQ; } } else if (pred.isValue()) { if (pred.ebv(qc, info).bool(info)) { qc.compInfo(OPTREMOVE, this, pred); preds = Array.delete(preds, p--); } else { // handle statically known predicates qc.compInfo(OPTREMOVE, this, pred); return Empty.SEQ; } } } return this; }
@Override public Expr copy(final QueryContext ctx, final VarScope scp, final IntObjMap<Var> vs) { final Expr[] copy = copyAll(ctx, scp, vs, expr); final int last = copy.length - 1; final Expr[] args = Arrays.copyOf(copy, last); final DynFuncCall call = new DynFuncCall(info, sc, updating, copy[last], args); if (inlinedFrom != null) call.inlinedFrom = inlinedFrom.clone(); return copyType(call); }
@Override public Expr optimize(final QueryContext ctx, final VarScope scp) throws QueryException { final int ar = expr.length - 1; final Expr f = expr[ar]; final Type t = f.type().type; if (t instanceof FuncType) { final FuncType ft = (FuncType) t; if (ft.args != null && ft.args.length != ar) throw INVARITY.get(info, f, ar); if (ft.ret != null) type = ft.ret; } if (f instanceof XQFunctionExpr) { // maps can only contain fully evaluated Values, so this is safe if (allAreValues() && f instanceof Map) return optPre(value(ctx), ctx); // try to inline the function if (!(f instanceof FuncItem && comesFrom((FuncItem) f)) && !updating) { final Expr[] args = Arrays.copyOf(expr, expr.length - 1); final Expr inl = ((XQFunctionExpr) f).inlineExpr(args, ctx, scp, info); if (inl != null) return inl; } } return this; }
@Override protected void rehash() { super.rehash(); funcs = Arrays.copyOf(funcs, size << 1); }
@Override public void checkUp() throws QueryException { checkNoneUp(Arrays.copyOf(expr, expr.length - 1)); }