From 021658695cd24a596116515053896bc32eddad73 Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Wed, 4 Oct 2023 17:31:39 -0600 Subject: [PATCH] Removed dynamic type checks from interpreter --- Interpreter.cs | 77 +++++++++++++------------------------------------- TODO.txt | 2 +- 2 files changed, 21 insertions(+), 58 deletions(-) diff --git a/Interpreter.cs b/Interpreter.cs index 0a0766d..813ea3f 100644 --- a/Interpreter.cs +++ b/Interpreter.cs @@ -350,45 +350,6 @@ public class Interpreter : AST.IExprVisitor return expr.accept(env, this); } - private List checkListOperand(Token op, Object operand) - { - if (operand is List l) return l; - throw new RuntimeError(op, "Operand must be a record."); - } - - private Record checkRecordOperand(Token op, Object operand) - { - if (operand is Record r) return r; - throw new RuntimeError(op, "Operand must be a record."); - } - - private double checkNumberOperand(Token op, Object operand) - { - if (operand is double d) return d; - throw new RuntimeError(op, "Operand must be a number."); - } - - private void checkNumberOperands(Token op, object left, object right) - { - if (left is double && right is double) return; - throw new RuntimeError(op, "Operands must be numbers."); - } - - private void checkStringOperands(Token op, object left, object right) - { - if (left is string && right is string) return; - throw new RuntimeError(op, "Operands must be strings."); - } - - private Variant checkBoolOperand(Token op, object operand) - { - if (operand is Variant v) - { - if (v == Variant.True || v == Variant.False) return v; - } - throw new RuntimeError(op, "Operand must be ."); - } - public object visitBinaryExpr(Env env, AST.Binary expr) { var left = evaluate(env, expr.Left); @@ -397,33 +358,24 @@ public class Interpreter : AST.IExprVisitor switch (expr.Op.Type) { case TokenType.Minus: - checkNumberOperands(expr.Op, left, right); return (double)left - (double)right; case TokenType.Plus: - checkNumberOperands(expr.Op, left, right); return (double)left + (double)right; case TokenType.Slash: - checkNumberOperands(expr.Op, left, right); return (double)left / (double)right; case TokenType.Asterisk: - checkNumberOperands(expr.Op, left, right); return (double)left * (double)right; case TokenType.PlusPlus: - checkStringOperands(expr.Op, left, right); return (string)left + (string)right; case TokenType.Greater: - checkNumberOperands(expr.Op, left, right); return Variant.FromBool((double)left > (double)right); case TokenType.GreaterEqual: - checkNumberOperands(expr.Op, left, right); return Variant.FromBool((double)left >= (double)right); case TokenType.Less: - checkNumberOperands(expr.Op, left, right); return Variant.FromBool((double)left < (double)right); case TokenType.LessEqual: - checkNumberOperands(expr.Op, left, right); return Variant.FromBool((double)left <= (double)right); case TokenType.BangEqual: @@ -480,11 +432,24 @@ public class Interpreter : AST.IExprVisitor } } + private bool variantToBool(object obj) + { + var v = (Variant)obj; + if (v == Variant.True) + { + return true; + } + if (v == Variant.False) + { + return false; + } + throw new InvalidCastException(); + } + public object visitIfExpr(Env env, AST.If expr) { var cond = evaluate(env, expr.Condition); - var vb = checkBoolOperand(expr.Condition.Start, cond); - if (vb == Variant.True) + if (variantToBool(cond)) { return evaluate(env, expr.Then); } @@ -496,8 +461,8 @@ public class Interpreter : AST.IExprVisitor public object visitIndexerExpr(Env env, AST.Indexer expr) { - var left = checkListOperand(expr.Left.Start, evaluate(env, expr.Left)); - var index = checkNumberOperand(expr.Index.Start, evaluate(env, expr.Index)); + var left = (List)evaluate(env, expr.Left); + var index = (double)evaluate(env, expr.Index); try { var item = left[index]; @@ -614,11 +579,10 @@ public class Interpreter : AST.IExprVisitor public object visitSelectorExpr(Env env, AST.Selector expr) { - var left = evaluate(env, expr.Left); - var r = checkRecordOperand(expr.Left.Start, left); + var left = (Record)evaluate(env, expr.Left); try { - return r.Get((string)expr.FieldName.Literal!); + return left.Get((string)expr.FieldName.Literal!); } catch { @@ -638,10 +602,9 @@ public class Interpreter : AST.IExprVisitor switch (expr.Op.Type) { case TokenType.Minus: - checkNumberOperand(expr.Op, right); return -(double)right; case TokenType.Bang: - if (checkBoolOperand(expr.Op, right) == Variant.True) + if (variantToBool(right)) { return Variant.False; } diff --git a/TODO.txt b/TODO.txt index 98e8986..4b5eee8 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,5 @@ +Why doesn't `true! get a parse error? Move let-expr resolvability check to Resolver -Remove dynamic type checks (checkXXX methods) from interpreter Use numerical indices in resolutions Statically resolve global references Capitalize stuff to match common C# style