/// <summary> /// Creates a unary expression with symbol scope, context, script refernce set. /// </summary> /// <param name="name"></param> /// <param name="token"></param> /// <returns></returns> public static Expr Binary(Expr left, Operator op, Expr right, TokenData token) { var exp = new BinaryExpr(); exp.Left = left; exp.Op = op; exp.Right = right; SetupContext(exp, token); return exp; }
/// <summary> /// Visits the binary expression tree /// </summary> /// <param name="exp"></param> public object VisitBinary(BinaryExpr exp) { _callBackOnNodeStart(exp); _callBackOnNodeStart(exp.Left); _callBackOnNodeStart(exp.Right); return null; }
/// <summary> /// Checks for division by zero. /// </summary> /// <param name="semActs"></param> /// <param name="exp"></param> private SemanticCheckResult CheckDivisionByZero(SemActs semActs, BinaryExpr exp) { if(exp.Op != Operator.Divide) return SemanticCheckResult.Valid; if (!(exp.Right.IsNodeType(NodeTypes.SysConstant))) return SemanticCheckResult.Valid; var val = (LObject)((ConstantExpr)exp.Right).Value; if (val.Type == LTypes.Number) { var d = ((LNumber)val).Value; if (d == 0) AddError("Division by zero", exp.Right); } return SemanticCheckResult.Valid; }
/// <summary> /// Evaluate * / + - % /// </summary> /// <returns></returns> public static object EvalBinary(BinaryExpr expr) { // Validate object result = 0; var node = expr; var op = expr.Op; var left = (LObject)expr.Left.Evaluate(); var right = (LObject)expr.Right.Evaluate(); // Case 1: Both numbers if (IsTypeMatch(LTypes.Number, left, right)) { result = EvalHelper.CalcNumbers(node, (LNumber)left, (LNumber)right, op); } // Case 2: Both times else if (IsTypeMatch(LTypes.Time, left, right)) { result = EvalHelper.CalcTimes(node, (LTime)left, (LTime)right, op); } // Case 3: Both dates else if (IsTypeMatch(LTypes.Date, left, right)) { result = EvalHelper.CalcDates(node, (LDate)left, (LDate)right, op); } // Case 4: Both strings. else if (IsTypeMatch(LTypes.String, left, right)) { var strleft = ((LString)left).Value; var strright = ((LString)right).Value; // Check string limit. Ctx.Limits.CheckStringLength(node, strleft, strright); result = new LString(strleft + strright); } // MIXED TYPES // TODO: Needs to be improved with new code for types. // Case 5 : Double and Bool else if (left.Type == LTypes.Number && right.Type == LTypes.Bool) { var r = ((LBool)right).Value; var rval = r ? 1 : 0; result = EvalHelper.CalcNumbers(node, (LNumber)left, new LNumber(rval), op); } // Bool Double else if (left.Type == LTypes.Bool && right.Type == LTypes.Number) { var l = ((LBool)left).Value; var lval = l ? 1 : 0; result = EvalHelper.CalcNumbers(node, new LNumber(lval), (LNumber)right, op); } // Append as strings. else if (left.Type == LTypes.String && right.Type == LTypes.Bool) { var st1 = ((LString)left).Value + ((LBool)right).Value.ToString().ToLower(); result = new LString(st1); } // Append as strings. else if (left.Type == LTypes.Bool && right.Type == LTypes.String) { var st2 = ((LBool)left).Value.ToString().ToLower() + ((LString)right).Value; result = new LString(st2); } // TODO: Need to handle LUnit and LVersion better //else if (left.Type == LTypes.Unit && right.Type == LTypes.Unit) else if (left.Type.Name == "LUnit" && right.Type.Name == "LUnit") { result = EvalHelper.CalcUnits(node, (LUnit)((LClass)left).Value, (LUnit)((LClass)right).Value, op, Ctx.Units); } else { var st3 = left.GetValue().ToString() + right.GetValue().ToString(); result = new LString(st3); } return result; }
/// <summary> /// Creates a unary expression with symbol scope, context, script refernce set. /// </summary> /// <param name="name"></param> /// <param name="token"></param> /// <returns></returns> public Expr ToBinaryExpr(Expr left, Operator op, Expr right, TokenData token) { var exp = new BinaryExpr(left, op, right); this.SetupContext(exp, token); return exp; }