Literal EvaluateBinaryOp(BinaryOp op) { var left = Evaluate(op.Left); var right = Evaluate(op.Right); return BinaryEvaluator.Calculate(op, left, right); }
public static Literal Calculate(BinaryOp op, Literal left, Literal right) { var range = new CodeRange(left, right); object val = CalculateValue(op, left, right); var type = TypeEvaluator.GetType(left.ValueType, op, right.ValueType); return new Literal(range, type, val); }
public static LaxType GetType(LaxType left, BinaryOp op, LaxType right) { return new LaxType( GetTypes(left.Type, op, right.Type), GetUnit(left.Unit, op, right.Unit) ); }
/// <summary> /// return a new <seealso cref="Assignment"/> with Left and Right assigned. /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <returns></returns> public BinaryOp WithOperands(LaxExpression left, LaxExpression right) { var op = new BinaryOp(CodeRange, Operator); op.Left = left; op.Right = right; op.CodeRange = CodeRange.Expand2(left).Expand2(right); return op; }
//Although this could be infered from the object type in CalculateValue we implement it here for other runtimes. static DataType GetTypes(DataType left, BinaryOp op, DataType right) { if (left == DataType.Unit) return right; if (right == DataType.Unit) return left; string key = (left + " " + right).ToLowerInvariant(); switch (key) { case "double double": return DataType.Double; case "double int": return DataType.Double; case "int double": return DataType.Double; case "int int": return DataType.Int; case "boolean boolean": return DataType.Boolean; default: throw new SemanticError(op, "Not supported: " + key); } }
static LaxExpression EvaluateOp(BinaryOp op) { var left = Evaluate(op.Left); var right = Evaluate(op.Right); var result = new BinaryOp(op.CodeRange, op.Operator).WithOperands(left, right); result.ValueType = op.ValueType; if (result.Left.Type == ExprType.Literal && result.Right.Type == ExprType.Literal) { //Operation with two literals, precalculate var interpreter = new Interpreter(); var literal = interpreter.Evaluate(result); return literal; } //No change if (left == op.Left && right == op.Right) return op; //No change, no evaluation possible return result; }
public string FormatBinaryOp(BinaryOp bo) { string l = ExpressionParenLeft; string r = ExpressionParenRight; return l + FormatExpression(bo.Left) + " " + bo.Operator + " " + FormatExpression(bo.Right) + r; }
private static object CalculateValue(BinaryOp op, Literal left, Literal right) { if (op.Operator == "*") { if (left.ValueType.Type == DataType.Unit) return right.Value; if (right.ValueType.Type == DataType.Unit) return left.Value; } if (op.Operator == "/") { if (right.ValueType.Type == DataType.Unit) return left.Value; } string key = (left.ValueType.Type + " " + op.Operator + " " + right.ValueType.Type).ToLowerInvariant(); switch (key) { case "double + double": return (double)left.Value + (double)right.Value; case "double - double": return (double)left.Value - (double)right.Value; case "double * double": return (double)left.Value * (double)right.Value; case "double / double": return (double)left.Value / (double)right.Value; case "int + int": return (int)left.Value + (int)right.Value; case "int - int": return (int)left.Value - (int)right.Value; case "int * int": return (int)left.Value * (int)right.Value; case "int / int": return (int)left.Value / (int)right.Value; case "double + int": return (double)left.Value + (int)right.Value; case "int + double": return (int)left.Value + (double)right.Value; case "double - int": return (double)left.Value - (int)right.Value; case "int - double": return (int)left.Value - (double)right.Value; case "double * int": return (double)left.Value * (int)right.Value; case "int * double": return (int)left.Value * (double)right.Value; case "double / int": return (double)left.Value / (int)right.Value; case "int / double": return (int)left.Value / (double)right.Value; case "boolean and boolean": return (bool)left.Value && (bool)right.Value; case "boolean or boolean": return (bool)left.Value || (bool)right.Value; default: throw new SyntaxError(op.CodeRange, "Operator-type not implemented: " + key); } }
static Unit GetUnit(Unit left, BinaryOp op, Unit right) { switch (op.Operator) { case "+": case "-": case "and": case "or": if (left != right) throw new SemanticError(op, "Unit mismatch: " + left + op.Operator + right); return left; case "*": return left * right; case "/": return left / right; default: throw new NotImplementedException(op.Operator); } }
void EvalBinaryOperator(BinaryOp op) { Eval(op.Left); Debug.Assert(op.Left.ValueType != null); Eval(op.Right); Debug.Assert(op.Right.ValueType != null); var t = GetType(op.Left.ValueType, op, op.Right.ValueType); if (op.ValueType != null) { if (op.ValueType != t) throw new SemanticError(op, "Type mismatch"); } op.ValueType = t; }
/// <summary> /// Generate a BinaryOp that strongly connects a value with the unit following directly afterwards. /// </summary> public static BinaryOp UnitOp(CodeRange pos) { var bop = new BinaryOp("*", 18, Associate.LeftToRight); bop.CodeRange = pos; return bop; }