(final CompileContext cc)
| 38 | } |
| 39 | |
| 40 | @Override |
| 41 | public Expr optimize(final CompileContext cc) throws QueryException { |
| 42 | exprs = simplifyAll(Simplify.NUMBER, cc); |
| 43 | if(values(false, cc)) return cc.preEval(this); |
| 44 | |
| 45 | // move values to second position |
| 46 | // 1 + position() → position() + 1 |
| 47 | Expr expr1 = exprs[0], expr2 = exprs[1]; |
| 48 | if((calc == Calc.ADD || calc == Calc.MULTIPLY) && expr1 instanceof Value && |
| 49 | !(expr2 instanceof Value)) { |
| 50 | cc.info(OPTSWAP_X, this); |
| 51 | exprs[0] = expr2; |
| 52 | exprs[1] = expr1; |
| 53 | expr1 = exprs[0]; |
| 54 | expr2 = exprs[1]; |
| 55 | } |
| 56 | |
| 57 | final SeqType st1 = expr1.seqType(), st2 = expr2.seqType(); |
| 58 | final Type type1 = st1.type, type2 = st2.type; |
| 59 | final boolean numbers = type1.isNumberOrUntyped() && type2.isNumberOrUntyped(); |
| 60 | |
| 61 | final Type type = calc.type(type1, type2); |
| 62 | final boolean noArrays = !st1.mayBeWrapped() && !st2.mayBeWrapped(); |
| 63 | final boolean oneOrMore = noArrays && st1.oneOrMore() && st2.oneOrMore(); |
| 64 | exprType.assign(type, oneOrMore ? Occ.EXACTLY_ONE : Occ.ZERO_OR_ONE); |
| 65 | |
| 66 | Expr expr = emptyExpr(); |
| 67 | // 0 - $x → -$x |
| 68 | if(expr == this && expr1 == Itr.ZERO && calc == Calc.SUBTRACT) { |
| 69 | expr = new Unary(info, expr2, true).optimize(cc); |
| 70 | } |
| 71 | // count($n/@*) + count($n/*) → count(($n/@*, $n/*)) |
| 72 | if(expr == this && Function.COUNT.is(expr1) && calc == Calc.ADD && Function.COUNT.is(expr2)) { |
| 73 | expr = cc.function(Function.COUNT, info, List.get(cc, info, expr1.arg(0), expr2.arg(0))); |
| 74 | } |
| 75 | if(expr == this && numbers && noArrays && st1.one() && st2.one()) { |
| 76 | // example: number($a) + 0 → number($a) |
| 77 | final Expr ex = calc.optimize(expr1, expr2, info, cc); |
| 78 | if(ex != null) { |
| 79 | expr = ex; |
| 80 | } else if(expr1 instanceof final Arith arth1) { |
| 81 | final Calc acalc = arth1.calc; |
| 82 | final boolean add = acalc.oneOf(Calc.ADD, Calc.MULTIPLY); |
| 83 | final boolean sub = acalc.oneOf(Calc.SUBTRACT, Calc.DIVIDE); |
| 84 | final boolean inverse = acalc == calc.invert(); |
| 85 | final Expr arg1 = arth1.arg(0), arg2 = arth1.arg(1); |
| 86 | |
| 87 | if(arg2 instanceof ANum && expr2 instanceof ANum && (acalc == calc || inverse)) { |
| 88 | // (E - 3) + 2 → E - (3 - 2) |
| 89 | // (E * 3 div 2 → E * (3 div 2) |
| 90 | final Calc ncalc = add ? calc : sub ? calc.invert() : null; |
| 91 | if(ncalc != null) expr = new Arith(info, arg1, |
| 92 | new Arith(info, arg2, expr2, ncalc).optimize(cc), acalc).optimize(cc); |
| 93 | } else if(inverse) { |
| 94 | // E + NUMBER - NUMBER → E |
| 95 | // NUMBER * E div NUMBER → E |
| 96 | expr = arg2.equals(expr2) ? arg1 : arg1.equals(expr2) && add ? arg2 : this; |
| 97 | if(expr != this) expr = new Cast(info, expr, Types.NUMERIC_O).optimize(cc); |
nothing calls this directly
no test coverage detected