Evaluating Expressions 7

This commit is contained in:
nazrin 2025-05-31 17:44:11 +00:00
parent d937226553
commit f4338ba51f
6 changed files with 182 additions and 63 deletions

108
src/jlox/interpreter.d Normal file
View 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);
}
}
}