Evaluating Expressions
This commit is contained in:
parent
bbd8a8ca66
commit
9d05747655
2
src/main/java/me/rose/lox/.clang-format
Normal file
2
src/main/java/me/rose/lox/.clang-format
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
BasedOnStyle: GNU
|
||||
164
src/main/java/me/rose/lox/Interpreter.java
Normal file
164
src/main/java/me/rose/lox/Interpreter.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
package me.rose.lox;
|
||||
|
||||
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 Object
|
||||
evaluate (Expr expr)
|
||||
{
|
||||
return expr.accept (this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object
|
||||
visitGroupingExpr (Expr.Grouping expr)
|
||||
{
|
||||
return evaluate (expr.expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object
|
||||
visitBinaryExpr (Expr.Binary expr)
|
||||
{
|
||||
Object left = evaluate (expr.left);
|
||||
Object right = evaluate (expr.right);
|
||||
|
||||
switch (expr.operator.type)
|
||||
{
|
||||
case GREATER:
|
||||
checkNumberOperand (expr.operator, left, right);
|
||||
return (double)left > (double)right;
|
||||
case GREATER_EQUAL:
|
||||
checkNumberOperand (expr.operator, left, right);
|
||||
return (double)left >= (double)right;
|
||||
case LESS:
|
||||
checkNumberOperand (expr.operator, left, right);
|
||||
return (double)left < (double)right;
|
||||
case LESS_EQUAL:
|
||||
checkNumberOperand (expr.operator, left, right);
|
||||
return (double)left <= (double)right;
|
||||
case BANG_EQUAL:
|
||||
return !isEqual (left, right);
|
||||
case EQUAL_EQUAL:
|
||||
return isEqual (left, right);
|
||||
case MINUS:
|
||||
checkNumberOperand (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:
|
||||
checkNumberOperand (expr.operator, left, right);
|
||||
return (double)left / (double)right;
|
||||
case STAR:
|
||||
checkNumberOperand (expr.operator, left, right);
|
||||
return (double)left * (double)right;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void
|
||||
checkNumberOperand (Token operator, Object operand)
|
||||
{
|
||||
if (operand instanceof Double)
|
||||
return;
|
||||
throw new RuntimeError (operator, "Operand must be a number.");
|
||||
}
|
||||
|
||||
private void
|
||||
checkNumberOperand (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 ();
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,9 @@ import java.util.List;
|
|||
|
||||
public class Lox
|
||||
{
|
||||
private static final Interpreter interpreter = new Interpreter ();
|
||||
static boolean hadError = false;
|
||||
static boolean hadRuntimeError = false;
|
||||
|
||||
public static void
|
||||
main (String[] args) throws IOException
|
||||
|
|
@ -38,6 +40,8 @@ public class Lox
|
|||
|
||||
if (hadError)
|
||||
System.exit (65);
|
||||
if (hadRuntimeError)
|
||||
System.exit (70);
|
||||
}
|
||||
|
||||
private static void
|
||||
|
|
@ -67,6 +71,8 @@ public class Lox
|
|||
|
||||
if (hadError)
|
||||
return;
|
||||
|
||||
interpreter.interpret (expression);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -75,6 +81,14 @@ public class Lox
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
12
src/main/java/me/rose/lox/RuntimeError.java
Normal file
12
src/main/java/me/rose/lox/RuntimeError.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package me.rose.lox;
|
||||
|
||||
class RuntimeError extends RuntimeException
|
||||
{
|
||||
final Token token;
|
||||
|
||||
RuntimeError (Token token, String message)
|
||||
{
|
||||
super (message);
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
2
src/main/java/me/rose/tool/.clang-format
Normal file
2
src/main/java/me/rose/tool/.clang-format
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
BasedOnStyle: GNU
|
||||
Loading…
Reference in a new issue