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);
|
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;
|
||||||
}
|
}
|
||||||
|
2
TODO.txt
2
TODO.txt
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user