public void TestBinaryOpExp(BinaryOperatorAstNode expect, BinaryOperatorAstNode actual, string traceMessage) { Assert.AreEqual(expect.Operator, actual.Operator, traceMessage + " -> Operator"); TestGeneral(expect.Left, actual.Left, traceMessage + " -> Left"); TestGeneral(expect.Right, actual.Right, traceMessage + " -> Right"); }
public void Visit(BinaryOperatorAstNode visitable) { Visit(visitable.Left); var leftType = _exprType; Visit(visitable.Right); var op = visitable.Operator; if (leftType != _exprType) { throw new WrongTypeException( $"Cannot apply operator {op} on different types(left: {leftType}, right:{_exprType})"); } }
public void Visit(BinaryOperatorAstNode visitable) { if (!LanguageInformation.BinaryOperator.Contains(visitable.Operator)) { throw new Exception("Unknown binary operator: " + visitable.Operator); } Visit(visitable.Left); Visit(visitable.Right); switch (visitable.Operator) { case "+": Gen.Emit(OpCodes.Add); break; case "-": Gen.Emit(OpCodes.Sub); break; case "*": Gen.Emit(OpCodes.Mul); break; case "/": Gen.Emit(OpCodes.Div); break; case "%": var lc0Less = Gen.DefineLabel(); var loadVar = Gen.DefineLabel(); var lc0 = Gen.DeclareLocal(typeof(long)); var lc1 = Gen.DeclareLocal(typeof(long)); Gen.Emit(OpCodes.Stloc_0); Gen.Emit(OpCodes.Stloc_1); Gen.MarkLabel(loadVar); Gen.Emit(OpCodes.Ldloc_0); // lc0 == a Gen.Emit(OpCodes.Ldloc_1); // lc1 == b Gen.Emit(OpCodes.Blt, lc0Less); // if lc0 < lc1, goto lc0Less Gen.Emit(OpCodes.Ldloc_0); Gen.Emit(OpCodes.Ldloc_1); Gen.Emit(OpCodes.Sub); Gen.Emit(OpCodes.Stloc_0); // lc0 = lc0 - lc1 Gen.Emit(OpCodes.Jmp, loadVar); // goto loadVar Gen.MarkLabel(lc0Less); Gen.Emit(OpCodes.Ldloc_0); break; case "and": Gen.Emit(OpCodes.And); break; case "or": Gen.Emit(OpCodes.Or); break; case "=": break; // TODO: implement set local var case "<": Gen.Emit(OpCodes.Clt); break; case "==": Gen.Emit(OpCodes.Ceq); break; case ">": Gen.Emit(OpCodes.Cgt); break; case "<=": Gen.DeclareLocal(typeof(int)); Gen.DeclareLocal(typeof(int)); var lt = Gen.DefineLabel(); var finish = Gen.DefineLabel(); Gen.Emit(OpCodes.Stloc_0); Gen.Emit(OpCodes.Stloc_1); Gen.Emit(OpCodes.Ldloc_0); // lc0 == a Gen.Emit(OpCodes.Ldloc_1); // lc1 == b Gen.Emit(OpCodes.Ble, lt); // if lc0 <= lc1, goto lt Gen.Emit(OpCodes.Ldc_I4_0); // else push 0, goto finish Gen.Emit(OpCodes.Jmp, finish); Gen.MarkLabel(lt); // lt: push 1 Gen.Emit(OpCodes.Ldc_I4_1); Gen.MarkLabel(finish); // finish: break; case ">=": Gen.DeclareLocal(typeof(int)); Gen.DeclareLocal(typeof(int)); var gt = Gen.DefineLabel(); finish = Gen.DefineLabel(); Gen.Emit(OpCodes.Stloc_0); Gen.Emit(OpCodes.Stloc_1); Gen.Emit(OpCodes.Ldloc_0); // lc0 == a Gen.Emit(OpCodes.Ldloc_1); // lc1 == b Gen.Emit(OpCodes.Bge, gt); // if lc0 >= lc1, goto gt Gen.Emit(OpCodes.Ldc_I4_0); // else push 0, goto finish Gen.Emit(OpCodes.Jmp, finish); Gen.MarkLabel(gt); // gt: push 1 Gen.Emit(OpCodes.Ldc_I4_1); Gen.MarkLabel(finish); // finish: break; } }