Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
147 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package com.craftinginterpreters.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); | ||
} | ||
} | ||
|
||
private String stringify(Object object) { | ||
if (object == null) return "nil"; | ||
if (!(object instanceof Double)) return object.toString(); | ||
|
||
String text = object.toString(); | ||
if (text.endsWith(".0")) { | ||
text = text.substring(0, text.length() - 2); | ||
} | ||
return text; | ||
} | ||
|
||
@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); | ||
} | ||
|
||
return new RuntimeException("Unreachable code in visiting binary expression"); | ||
} | ||
|
||
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 isEqual(Object left, Object right) { | ||
if (left == null && right == null) return true; | ||
if (left == null) return false; | ||
|
||
return left.equals(right); | ||
} | ||
|
||
@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); | ||
|
||
switch (expr.operator.type) { | ||
case BANG: | ||
return !isTruthy(right); | ||
case MINUS: | ||
checkNumberOperand(expr.operator, right); | ||
return -(double)right; | ||
} | ||
|
||
// WE HOPE THIS NEVER HAPPENS | ||
throw new RuntimeException("isn't this code unreachable ???"); | ||
} | ||
|
||
private void checkNumberOperand(Token operator, Object operand) { | ||
if (operand instanceof Double) return; | ||
|
||
throw new RuntimeError(operator, "Operand must be a number"); | ||
} | ||
|
||
private boolean isTruthy(Object object) { | ||
if (object == null) return false; | ||
if (object instanceof Boolean) return (boolean)object; | ||
|
||
return true; | ||
} | ||
|
||
private Object evaluate(Expr expression) { | ||
return expression.accept(this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.craftinginterpreters.lox; | ||
|
||
public class RuntimeError extends RuntimeException { | ||
|
||
final Token token; | ||
|
||
public RuntimeError(Token token, String message) { | ||
super(message); | ||
this.token = token; | ||
} | ||
} |