Removed dynamic type checks from interpreter

This commit is contained in:
Brandon Dyck 2023-10-04 17:31:39 -06:00
parent 6e88a41b72
commit 021658695c
2 changed files with 21 additions and 58 deletions

View File

@ -350,45 +350,6 @@ public class Interpreter : AST.IExprVisitor<Env, object>
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 <true,false>.");
}
public object visitBinaryExpr(Env env, AST.Binary expr)
{
var left = evaluate(env, expr.Left);
@ -397,33 +358,24 @@ public class Interpreter : AST.IExprVisitor<Env, object>
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<Env, object>
}
}
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<Env, object>
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<Env, object>
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<Env, object>
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;
}

View File

@ -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