// Arthmentic Simplification: /* * +/- zero to a column, or multiply/divide a column by 1 */ internal bool IsArithIdentity(ConstExpr lce, ConstExpr rce) { ConstExpr ve = lce != null ? lce : rce; ColExpr ce = (children_[0] is ColExpr) ? (ColExpr)children_[0] : (children_[1] is ColExpr ? (ColExpr)children_[1] : null); if (ce == null) { return(false); } if (!(TypeBase.IsNumberType(ve.type_) && TypeBase.IsNumberType(ce.type_))) { return(false); } if ((op_ == "+" || op_ == "-") && ve.IsZero()) { return(true); } if ((op_ == "*" || op_ == "/") && ve.IsOne()) { return(true); } return(false); }
public override void Bind(BindContext context) { base.Bind(context); // derive return type Debug.Assert(lchild_().type_ != null && rchild_().type_ != null); switch (op_) { case "+": case "-": case "*": case "/": case "||": // notice that CoerseType() may change l/r underneath type_ = ColumnType.CoerseType(op_, lchild_(), rchild_()); break; case ">": case ">=": case "<": case "<=": if (TypeBase.IsNumberType(lchild_().type_)) { ColumnType.CoerseType(op_, lchild_(), rchild_()); } else if (TypeBase.OnlyOneIsStringType(lchild_().type_, rchild_().type_)) { throw new SemanticAnalyzeException("no implicit conversion of character type values"); } type_ = new BoolType(); break; case "=": case "<>": case "!=": if (TypeBase.IsNumberType(lchild_().type_)) { ColumnType.CoerseType(op_, lchild_(), rchild_()); } else if (TypeBase.OnlyOneIsStringType(lchild_().type_, rchild_().type_)) { throw new SemanticAnalyzeException("no implicit conversion of character type values"); } type_ = new BoolType(); break; case " and ": case " or ": case "like": case "not like": case "in": case "is": case "is not": type_ = new BoolType(); break; default: throw new NotImplementedException(); } }
public override Expr Normalize() { // all children get normalized first for (int i = 0; i < children_.Count; ++i) { Expr x = children_[i]; children_[i] = x.Normalize(); } Expr l = lchild_(); Expr r = rchild_(); ConstExpr lce = (l is ConstExpr) ? (ConstExpr)l : null; ConstExpr rce = (r is ConstExpr) ? (ConstExpr)r : null; switch (op_) { case "+": case "-": case "*": case "/": case ">": case ">=": case "<": case "<=": case "||": case "=": case "<>": case "!=": case " and ": case " or ": case "is": case "is not": if ((lce != null && lce.val_ is null) || (rce != null && rce.val_ is null)) { if (IsRelOp()) { // needs to be TRUE or FALSE if ((op_ == "is") || (op_ == "is not") || (lce != null && TypeBase.IsNumberType(l.type_)) || (rce != null && TypeBase.IsNumberType(r.type_))) { return(SimplifyRelop()); } } // NULL simplification: if operator is not relational, X op NULL is NULL if (lce != null && lce.val_ is null) { return(lce); } if (rce != null && rce.IsNull()) { return(rce); } } if (lce != null && rce != null) { // Simplify Constants: children are not non null constants, evaluate them. Value val = Exec(null, null); return(ConstExpr.MakeConst(val, type_, outputName_)); } if (lce != null && rce == null && isPlainSwappableConstOp()) { SwapSide(); } if ((lce != null || rce != null) && (IsArithIdentity(lce, rce))) { return(SimplifyArithmetic(lce, rce)); } if (IsLogicalOp()) { return(SimplifyLogic()); } if (IsRelOp()) { return(SimplifyRelop()); } // arithmetic operators? if (l is BinExpr le && le.children_[1].IsConst() && (rce != null) && isCommutativeConstOp() && le.isCommutativeConstOp() && TypeBase.SameArithType(l.type_, r.type_)) { /* * Here root is distributive operator (only * in this context) left is Commutative * operator, +, or * right is constant, furthermore, left's right is a constant * (becuase we swapped cosntant to be on the right). * if be == + and l == +: add left's right value to root's right value, * make left's left as left of root * * if be == * and l == +: create a expr node as left (x + 10), create (5 * 10) * as right, change operator to + * In either case left and right's children must be nulled out * and since we are going bottom up, this doesn't create any problem. * * Here is a pictorial description: * * root + * old left / \ old right new left / \ new right * / \ / \ * + 10 => * 50 * left of old left / \ / \ * / \ ROL LNL / \ RNL (right of New Left) * x 5 x 10 */ /* * Simple case: when current and left are same operators, distributive * opeartion and node creation is uncessary. */ if ((op_ == "+" && le.op_ == "+") || (op_ == "*" && le.op_ == "*")) { /* create new right node as constant. */ Expr tmpexp = Clone(); tmpexp.children_[0] = le.children_[1]; tmpexp.children_[1] = r; tmpexp.type_ = r.type_; Value val; bool wasConst = tmpexp.TryEvalConst(out val); Expr newr = ConstExpr.MakeConst(val, tmpexp.type_, r.outputName_); // new left is old left's left child // of left will be right of the root. children_[0] = l.children_[0]; // new right is the new constant node children_[1] = newr; } else if (op_ == "*" && le.rchild_() is ConstExpr lrc && (le.op_ == "+" || le.op_ == "-")) { /* * case of (a + const1) * const2 => (a * const2) + (const1 * const2)) * make a newe left node to house (a * const2) * * * + * / \ / \ * / \ / \ * + c2 => * c1 * c2 * / \ / \ * / \ / \ * X c1 X c2 * */ /* make a const expr node to evaluate const1 * const 2 */ Expr tmpexp = Clone(); tmpexp.children_[0] = lrc; // right of left is const tmpexp.children_[1] = r; // our right is const tmpexp.type_ = r.type_; Value val; tmpexp.TryEvalConst(out val); // set c2 as the value of right child of our left lrc.val_ = rce.val_; // val is c1 * c2, set it as the value of our right child rce.val_ = val; /* swap the operators */ string op = op_; op_ = le.op_; le.op_ = op; } /* we can't do any thing about + at the top and * as left child. */ } return(this); } return(this); }