Evaluating Expressions 7
This commit is contained in:
parent
d937226553
commit
f4338ba51f
6 changed files with 182 additions and 63 deletions
108
src/jlox/interpreter.d
Normal file
108
src/jlox/interpreter.d
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
module jlox.interpreter;
|
||||
|
||||
import std.conv;
|
||||
import std.stdio;
|
||||
import std.format : format;
|
||||
import std.functional : ctEval;
|
||||
|
||||
import taggedalgebraic;
|
||||
|
||||
import jlox.expr;
|
||||
import jlox.token;
|
||||
import jlox.tokentype;
|
||||
import jlox.token : TValue;
|
||||
import jlox.main;
|
||||
|
||||
class RuntimeError : Exception{
|
||||
const Token token;
|
||||
this(Token token, string message){
|
||||
super(message);
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
class Interpreter : Expr.Visitor!TValue{
|
||||
void interpret(Expr expression) {
|
||||
try {
|
||||
TValue value = evaluate(expression);
|
||||
writeln(value);
|
||||
} catch(RuntimeError error){
|
||||
Lox.runtimeError(error);
|
||||
}
|
||||
}
|
||||
private TValue evaluate(Expr expr){
|
||||
return expr.accept(this);
|
||||
}
|
||||
private bool isTruthy(TValue val){
|
||||
switch(val.kind){
|
||||
case TValue.Kind.nil:
|
||||
return false;
|
||||
case TValue.Kind.bln:
|
||||
return val.blnValue;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private bool isEqual(TValue a, TValue b){
|
||||
return a == b;
|
||||
}
|
||||
private void checkNumberOperand(Token operator, TValue operand){
|
||||
if(operand.kind == TValue.Kind.dbl)
|
||||
return;
|
||||
throw new RuntimeError(operator, "Operand must be a number.");
|
||||
}
|
||||
TValue visit(Expr.Literal expr){
|
||||
return expr.value;
|
||||
}
|
||||
TValue visit(Expr.Grouping expr) {
|
||||
return evaluate(expr.expression);
|
||||
}
|
||||
TValue visit(Expr.Unary expr) {
|
||||
TValue right = evaluate(expr.right);
|
||||
switch(expr.operator.type){
|
||||
case TokenType.MINUS:
|
||||
checkNumberOperand(expr.operator, right);
|
||||
return TValue.dbl(-right.dblValue);
|
||||
case TokenType.BANG:
|
||||
return TValue.bln(!isTruthy(right));
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
TValue visit(Expr.Binary expr){
|
||||
TValue left = evaluate(expr.left);
|
||||
TValue right = evaluate(expr.right);
|
||||
static string m(TokenType t, string op, string v, string vv){
|
||||
return q{case %s: return TValue.%s( left.%s %s right.%s );}.format(t, v, vv, op, vv);
|
||||
}
|
||||
with(TokenType) switch(expr.operator.type){
|
||||
static foreach(t, op; [ MINUS: "-", SLASH: "/", STAR: "*" ]){
|
||||
checkNumberOperand(expr.operator, left);
|
||||
checkNumberOperand(expr.operator, right);
|
||||
mixin(ctEval!(m(t, op, "dbl", "dblValue")));
|
||||
}
|
||||
case PLUS:
|
||||
if(left.isDbl && right.isDbl)
|
||||
return TValue.dbl(left.dblValue + right.dblValue);
|
||||
else if(left.isStr && right.isStr)
|
||||
return TValue.str(left.strValue ~ right.strValue);
|
||||
checkNumberOperand(expr.operator, left);
|
||||
checkNumberOperand(expr.operator, right);
|
||||
assert(0);
|
||||
|
||||
static foreach(t, op; [ GREATER: ">", GREATER_EQUAL: ">=", LESS: "<", LESS_EQUAL: "<=" ]){
|
||||
checkNumberOperand(expr.operator, left);
|
||||
checkNumberOperand(expr.operator, right);
|
||||
mixin(ctEval!(m(t, op, "bln", "dblValue")));
|
||||
}
|
||||
|
||||
case BANG_EQUAL:
|
||||
return TValue.bln(!isEqual(left, right));
|
||||
case EQUAL_EQUAL:
|
||||
return TValue.bln(isEqual(left, right));
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue