Removed dynamic type checks from interpreter
This commit is contained in:
parent
6e88a41b72
commit
021658695c
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user