Evaluating expressions chapter

This commit is contained in:
Mariano Riefolo 2024-06-28 15:34:19 +02:00
parent 0a892df176
commit c9159fda81
3 changed files with 145 additions and 1 deletions

125
src/lox/Interpreter.java Normal file
View File

@ -0,0 +1,125 @@
package lox;
public class Interpreter implements Expr.Visitor<Object> {
void interpret(Expr expression) {
try {
Object value = evaluate(expression);
System.out.println(stringify(value));
} catch (RuntimeError error) {
Lox.runtimeError(error);
}
}
@Override
public Object visitBinaryExpr(Expr.Binary expr) {
Object left = evaluate(expr.left);
Object right = evaluate(expr.right);
switch (expr.operator.type) {
case GREATER:
checkNumberOperands(expr.operator, left, right);
return (double) left > (double) right;
case GREATER_EQUAL:
checkNumberOperands(expr.operator, left, right);
return (double) left >= (double) right;
case LESS:
checkNumberOperands(expr.operator, left, right);
return (double) left < (double) right;
case LESS_EQUAL:
checkNumberOperands(expr.operator, left, right);
return (double) left <= (double) right;
case MINUS:
checkNumberOperands(expr.operator, left, right);
return (double) left - (double) right;
case PLUS:
if (left instanceof Double && right instanceof Double) {
return (double) left + (double) right;
}
if (left instanceof String && right instanceof String) {
return (String) left + (String) right;
}
throw new RuntimeError(expr.operator,
"Operands must be two numbers or two strings.");
case SLASH:
checkNumberOperands(expr.operator, left, right);
return (double) left / (double) right;
case STAR:
checkNumberOperands(expr.operator, left, right);
return (double) left * (double) right;
case BANG_EQUAL:
return !isEqual(left, right);
case EQUAL_EQUAL:
return isEqual(left, right);
default:
return null;
}
}
@Override
public Object visitGroupingExpr(Expr.Grouping expr) {
return evaluate(expr.expression);
}
@Override
public Object visitLiteralExpr(Expr.Literal expr) {
return expr.value;
}
@Override
public Object visitUnaryExpr(Expr.Unary expr) {
Object right = evaluate(expr.right);
return switch (expr.operator.type) {
case BANG -> !isTruthy(right);
case MINUS -> {
checkNumberOperand(expr.operator, right);
yield -(double) right;
}
default -> null;
};
}
private void checkNumberOperand(Token operator, Object operand) {
if (operand instanceof Double) return;
throw new RuntimeError(operator, "Operand must be a number.");
}
private void checkNumberOperands(Token operator,
Object left, Object right) {
if (left instanceof Double && right instanceof Double) return;
throw new RuntimeError(operator, "Operands must be numbers");
}
private boolean isTruthy(Object object) {
if (object == null) return false;
if (object instanceof Boolean) return (Boolean) object;
return true;
}
private boolean isEqual(Object a, Object b) {
if (a == null && b == null) return true;
if (a == null) return false;
return a.equals(b);
}
private String stringify(Object object) {
if (object == null) return "nil";
if (object instanceof Double) {
String text = object.toString();
if (text.endsWith(".0")) {
text = text.substring(0, text.length() - 2);
}
return text;
}
return object.toString();
}
private Object evaluate(Expr expr) {
return expr.accept(this);
}
}

View File

@ -9,7 +9,9 @@ import java.nio.file.Paths;
import java.util.List; import java.util.List;
public class Lox { public class Lox {
private static final Interpreter interpreter = new Interpreter();
static boolean hadError = false; static boolean hadError = false;
static boolean hadRuntimeError = false;
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
if (args.length > 1) { if (args.length > 1) {
@ -27,6 +29,7 @@ public class Lox {
run(new String(bytes, Charset.defaultCharset())); run(new String(bytes, Charset.defaultCharset()));
if (hadError) System.exit(65); if (hadError) System.exit(65);
if (hadRuntimeError) System.exit(70);
} }
private static void runPrompt() throws IOException { private static void runPrompt() throws IOException {
@ -51,13 +54,19 @@ public class Lox {
if (hadError) return; if (hadError) return;
System.out.println(new AstPrinter().print(expression)); interpreter.interpret(expression);
} }
static void error(int line, String message) { static void error(int line, String message) {
report(line, "", message); report(line, "", message);
} }
static void runtimeError(RuntimeError error) {
System.err.println(error.getMessage() +
"\n[line " + error.token.line + "]");
hadRuntimeError = true;
}
private static void report(int line, String where, String message) { private static void report(int line, String where, String message) {
System.err.println("[line " + line + "] Error" + where + ": " + message); System.err.println("[line " + line + "] Error" + where + ": " + message);
hadError = true; hadError = true;

10
src/lox/RuntimeError.java Normal file
View File

@ -0,0 +1,10 @@
package lox;
public class RuntimeError extends RuntimeException {
final Token token;
RuntimeError(Token token, String message) {
super(message);
this.token = token;
}
}