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); 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) public object visitBinaryExpr(Env env, AST.Binary expr)
{ {
var left = evaluate(env, expr.Left); var left = evaluate(env, expr.Left);
@ -397,33 +358,24 @@ public class Interpreter : AST.IExprVisitor<Env, object>
switch (expr.Op.Type) switch (expr.Op.Type)
{ {
case TokenType.Minus: case TokenType.Minus:
checkNumberOperands(expr.Op, left, right);
return (double)left - (double)right; return (double)left - (double)right;
case TokenType.Plus: case TokenType.Plus:
checkNumberOperands(expr.Op, left, right);
return (double)left + (double)right; return (double)left + (double)right;
case TokenType.Slash: case TokenType.Slash:
checkNumberOperands(expr.Op, left, right);
return (double)left / (double)right; return (double)left / (double)right;
case TokenType.Asterisk: case TokenType.Asterisk:
checkNumberOperands(expr.Op, left, right);
return (double)left * (double)right; return (double)left * (double)right;
case TokenType.PlusPlus: case TokenType.PlusPlus:
checkStringOperands(expr.Op, left, right);
return (string)left + (string)right; return (string)left + (string)right;
case TokenType.Greater: case TokenType.Greater:
checkNumberOperands(expr.Op, left, right);
return Variant.FromBool((double)left > (double)right); return Variant.FromBool((double)left > (double)right);
case TokenType.GreaterEqual: case TokenType.GreaterEqual:
checkNumberOperands(expr.Op, left, right);
return Variant.FromBool((double)left >= (double)right); return Variant.FromBool((double)left >= (double)right);
case TokenType.Less: case TokenType.Less:
checkNumberOperands(expr.Op, left, right);
return Variant.FromBool((double)left < (double)right); return Variant.FromBool((double)left < (double)right);
case TokenType.LessEqual: case TokenType.LessEqual:
checkNumberOperands(expr.Op, left, right);
return Variant.FromBool((double)left <= (double)right); return Variant.FromBool((double)left <= (double)right);
case TokenType.BangEqual: 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) public object visitIfExpr(Env env, AST.If expr)
{ {
var cond = evaluate(env, expr.Condition); var cond = evaluate(env, expr.Condition);
var vb = checkBoolOperand(expr.Condition.Start, cond); if (variantToBool(cond))
if (vb == Variant.True)
{ {
return evaluate(env, expr.Then); return evaluate(env, expr.Then);
} }
@ -496,8 +461,8 @@ public class Interpreter : AST.IExprVisitor<Env, object>
public object visitIndexerExpr(Env env, AST.Indexer expr) public object visitIndexerExpr(Env env, AST.Indexer expr)
{ {
var left = checkListOperand(expr.Left.Start, evaluate(env, expr.Left)); var left = (List)evaluate(env, expr.Left);
var index = checkNumberOperand(expr.Index.Start, evaluate(env, expr.Index)); var index = (double)evaluate(env, expr.Index);
try try
{ {
var item = left[index]; var item = left[index];
@ -614,11 +579,10 @@ public class Interpreter : AST.IExprVisitor<Env, object>
public object visitSelectorExpr(Env env, AST.Selector expr) public object visitSelectorExpr(Env env, AST.Selector expr)
{ {
var left = evaluate(env, expr.Left); var left = (Record)evaluate(env, expr.Left);
var r = checkRecordOperand(expr.Left.Start, left);
try try
{ {
return r.Get((string)expr.FieldName.Literal!); return left.Get((string)expr.FieldName.Literal!);
} }
catch catch
{ {
@ -638,10 +602,9 @@ public class Interpreter : AST.IExprVisitor<Env, object>
switch (expr.Op.Type) switch (expr.Op.Type)
{ {
case TokenType.Minus: case TokenType.Minus:
checkNumberOperand(expr.Op, right);
return -(double)right; return -(double)right;
case TokenType.Bang: case TokenType.Bang:
if (checkBoolOperand(expr.Op, right) == Variant.True) if (variantToBool(right))
{ {
return Variant.False; return Variant.False;
} }

View File

@ -1,5 +1,5 @@
Why doesn't `true! get a parse error?
Move let-expr resolvability check to Resolver Move let-expr resolvability check to Resolver
Remove dynamic type checks (checkXXX methods) from interpreter
Use numerical indices in resolutions Use numerical indices in resolutions
Statically resolve global references Statically resolve global references
Capitalize stuff to match common C# style Capitalize stuff to match common C# style