Optimizes the expression. @param cc compilation context @return optimized or original expression @throws QueryException query exception
(final CompileContext cc)
| 90 | * @throws QueryException query exception |
| 91 | */ |
| 92 | private Expr opt(final CompileContext cc) throws QueryException { |
| 93 | // choose static branch at compile time |
| 94 | if(cond instanceof Value) return expr(cc.qc); |
| 95 | |
| 96 | // if(...empty sequence...) then A else B → B |
| 97 | final Expr br1 = exprs[0], br2 = exprs[1]; |
| 98 | final SeqType ct = cond.seqType(); |
| 99 | final boolean ndt = cond.has(Flag.NDT); |
| 100 | if(ct.zero() && !ndt) return br2; |
| 101 | |
| 102 | // rewrite to otherwise: |
| 103 | // if(exists(VALUE)) then VALUE else DEFAULT → VALUE otherwise DEFAULT |
| 104 | // if(NODES) then NODES else DEFAULT → NODES otherwise DEFAULT |
| 105 | final Expr cmp = EXISTS.is(cond) ? cond.arg(0) : ct.type instanceof NodeType ? cond : null; |
| 106 | if(!ndt && cmp != null && cmp.equals(br1)) return new Otherwise(info, br1, br2).optimize(cc); |
| 107 | |
| 108 | // if(A) then B else B → void(A), B |
| 109 | if(br1.equals(br2)) return cc.voidAndReturn(cond, br1, info); |
| 110 | |
| 111 | // determine type |
| 112 | final SeqType st1 = br1.seqType(), st2 = br2.seqType(); |
| 113 | exprType.assign(st1.union(st2)).data(exprs); |
| 114 | |
| 115 | // logical rewritings |
| 116 | if(st1.eq(Types.BOOLEAN_O) && st2.eq(Types.BOOLEAN_O)) { |
| 117 | if(br1 == Bln.TRUE) return br2 == Bln.FALSE ? |
| 118 | // if(A) then true() else false() → boolean(A) |
| 119 | cc.function(BOOLEAN, info, cond) : |
| 120 | // if(A) then true() else C → A or C |
| 121 | new Or(info, cond, br2).optimize(cc); |
| 122 | if(br2 == Bln.TRUE) return br1 == Bln.FALSE ? |
| 123 | // if(A) then false() else true() → not(A) |
| 124 | cc.function(NOT, info, cond) : |
| 125 | // if(A) then B else true() → not(A) or B |
| 126 | new Or(info, cc.function(NOT, info, cond), br1).optimize(cc); |
| 127 | // if(A) then false() else C → not(A) and C |
| 128 | if(br1 == Bln.FALSE) return |
| 129 | new And(info, cc.function(NOT, info, cond), br2).optimize(cc); |
| 130 | // if(A) then B else false() → A and B |
| 131 | if(br2 == Bln.FALSE) return |
| 132 | new And(info, cond, br1).optimize(cc); |
| 133 | |
| 134 | if(contradict(br1, br2, false)) return new CmpG( |
| 135 | info, cc.function(BOOLEAN, info, cond), br1, CmpOp.EQ).optimize(cc); |
| 136 | if(contradict(br2, br1, false)) return new CmpG( |
| 137 | info, cc.function(BOOLEAN, info, cond), br2, CmpOp.NE).optimize(cc); |
| 138 | } |
| 139 | return this; |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * Swaps the arguments. |