From 68a2ebd34fc94488e89ffb82b359ec6e7e152ae9 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Thu, 8 Jul 2021 00:14:31 -0700 Subject: Restructure project to make room for clox --- src/com/craftinginterpreters/lox/.gitignore | 1 - src/com/craftinginterpreters/lox/AstPrinter.java | 147 ------- src/com/craftinginterpreters/lox/CMakeLists.txt | 28 -- src/com/craftinginterpreters/lox/Environment.java | 63 --- src/com/craftinginterpreters/lox/Interpreter.java | 392 ------------------ src/com/craftinginterpreters/lox/Lox.java | 93 ----- src/com/craftinginterpreters/lox/LoxCallable.java | 9 - src/com/craftinginterpreters/lox/LoxClass.java | 51 --- src/com/craftinginterpreters/lox/LoxFunction.java | 52 --- src/com/craftinginterpreters/lox/LoxInstance.java | 34 -- src/com/craftinginterpreters/lox/Parser.java | 457 --------------------- src/com/craftinginterpreters/lox/Resolver.java | 299 -------------- src/com/craftinginterpreters/lox/Return.java | 10 - src/com/craftinginterpreters/lox/RuntimeError.java | 10 - src/com/craftinginterpreters/lox/Scanner.java | 207 ---------- src/com/craftinginterpreters/lox/Token.java | 19 - src/com/craftinginterpreters/lox/TokenType.java | 20 - 17 files changed, 1892 deletions(-) delete mode 100644 src/com/craftinginterpreters/lox/.gitignore delete mode 100644 src/com/craftinginterpreters/lox/AstPrinter.java delete mode 100644 src/com/craftinginterpreters/lox/CMakeLists.txt delete mode 100644 src/com/craftinginterpreters/lox/Environment.java delete mode 100644 src/com/craftinginterpreters/lox/Interpreter.java delete mode 100644 src/com/craftinginterpreters/lox/Lox.java delete mode 100644 src/com/craftinginterpreters/lox/LoxCallable.java delete mode 100644 src/com/craftinginterpreters/lox/LoxClass.java delete mode 100644 src/com/craftinginterpreters/lox/LoxFunction.java delete mode 100644 src/com/craftinginterpreters/lox/LoxInstance.java delete mode 100644 src/com/craftinginterpreters/lox/Parser.java delete mode 100644 src/com/craftinginterpreters/lox/Resolver.java delete mode 100644 src/com/craftinginterpreters/lox/Return.java delete mode 100644 src/com/craftinginterpreters/lox/RuntimeError.java delete mode 100644 src/com/craftinginterpreters/lox/Scanner.java delete mode 100644 src/com/craftinginterpreters/lox/Token.java delete mode 100644 src/com/craftinginterpreters/lox/TokenType.java (limited to 'src/com/craftinginterpreters/lox') diff --git a/src/com/craftinginterpreters/lox/.gitignore b/src/com/craftinginterpreters/lox/.gitignore deleted file mode 100644 index 0260b11..0000000 --- a/src/com/craftinginterpreters/lox/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Expr.java diff --git a/src/com/craftinginterpreters/lox/AstPrinter.java b/src/com/craftinginterpreters/lox/AstPrinter.java deleted file mode 100644 index 4c120d3..0000000 --- a/src/com/craftinginterpreters/lox/AstPrinter.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.List; - -/** - * AstPrinter - */ -class AstPrinter implements Expr.Visitor, Stmt.Visitor { - String print(Expr expr) { - return expr.accept(this); - } - - @Override - public String visitCallExpr(Expr.Call expr) { - StringBuilder builder = new StringBuilder(); - - builder.append(print(expr.callee)); - builder.append(parenthesizeExpr("", expr.arguments)); - - return builder.toString(); - } - - @Override - public String visitBinaryExpr(Expr.Binary expr) { - return parenthesizeExpr(expr.operator.lexeme, expr.left, expr.right); - } - - @Override - public String visitGroupingExpr(Expr.Grouping expr) { - return parenthesizeExpr("group", expr.expression); - } - - @Override - public String visitLiteralExpr(Expr.Literal expr) { - if (expr.value == null) - return "nil"; - return expr.value.toString(); - } - - @Override - public String visitLogicalExpr(Expr.Logical expr) { - return parenthesizeExpr(expr.operator.type.toString(), expr.left, expr.right); - } - - @Override - public String visitUnaryExpr(Expr.Unary expr) { - return parenthesizeExpr(expr.operator.lexeme, expr.right); - } - - @Override - public String visitVariableExpr(Expr.Variable expr) { - return expr.name.lexeme; - } - - @Override - public String visitAssignExpr(Expr.Assign expression) { - return parenthesizeExpr(expression.name.lexeme + " = ", expression.value); - } - - @Override - public String visitVarStmt(Stmt.Var statement) { - return parenthesizeExpr("define " + statement.name.lexeme + " = ", statement.initializer); - } - - @Override - public String visitWhileStmt(Stmt.While statement) { - StringBuilder builder = new StringBuilder(); - - builder.append('('); - builder.append(parenthesizeExpr("while", statement.condition)); - builder.append(parenthesizeStmt("do", statement.body)); - builder.append(')'); - - return builder.toString(); - } - - @Override - public String visitPrintStmt(Stmt.Print statement) { - return parenthesizeExpr("print", statement.expression); - } - - @Override - public String visitExpressionStmt(Stmt.Expression expression) { - return expression.expression.accept(this); - } - - @Override - public String visitIfStmt(Stmt.If stmt) { - StringBuilder builder = new StringBuilder(); - - builder.append("("); - builder.append(parenthesizeExpr("if", stmt.condition)); - builder.append(parenthesizeStmt("then", stmt.thenBranch)); - - if (stmt.elseBranch != null) { - builder.append(parenthesizeStmt("else", stmt.elseBranch)); - } - return builder.toString(); - } - - @Override - public String visitBlockStmt(Stmt.Block block) { - return parenthesizeStmt("", block.statements); - } - - private String parenthesizeExpr(String name, Expr... exprs) { - return parenthesizeExpr(name, exprs); - } - - private String parenthesizeExpr(String name, List exprs) { - StringBuilder builder = new StringBuilder(); - - builder.append("(").append(name); - for (Expr expr : exprs) { - builder.append(" "); - builder.append(expr.accept(this)); - } - builder.append(")"); - - return builder.toString(); - } - - private String parenthesizeStmt(String name, List statements) { - StringBuilder builder = new StringBuilder(); - - builder.append("(").append(name); - for (Stmt statement : statements) { - builder.append(" "); - builder.append(statement.accept(this)); - } - builder.append(")"); - - return builder.toString(); - } - - private String parenthesizeStmt(String name, Stmt... statements) { - return parenthesizeStmt(name, statements); - } - - public static void main(String[] args) { - Expr expression = new Expr.Binary( - new Expr.Unary(new Token(TokenType.MINUS, "-", null, 1), new Expr.Literal(123)), - new Token(TokenType.STAR, "*", null, 1), new Expr.Grouping(new Expr.Literal(45.67))); - - System.out.println(new AstPrinter().print(expression)); - } -} diff --git a/src/com/craftinginterpreters/lox/CMakeLists.txt b/src/com/craftinginterpreters/lox/CMakeLists.txt deleted file mode 100644 index aeab240..0000000 --- a/src/com/craftinginterpreters/lox/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -get_target_property(GENERATE_AST_JAR GenerateAst JAR_FILE) - -set(GENERATED_JAVA_FILENAMES - ${CMAKE_CURRENT_BINARY_DIR}/Expr.java - ${CMAKE_CURRENT_BINARY_DIR}/Stmt.java - CACHE INTERNAL "") - -add_custom_command(OUTPUT ${GENERATED_JAVA_FILENAMES} - COMMAND java -jar ${GENERATE_AST_JAR} ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS GenerateAst ${GENERATE_AST_JAR}) - -add_jar(Lox - Lox.java - TokenType.java - Token.java - Scanner.java - ${GENERATED_JAVA_FILENAMES} - Parser.java - Interpreter.java - RuntimeError.java - Environment.java - LoxCallable.java - LoxFunction.java - Return.java - Resolver.java - LoxClass.java - LoxInstance.java - ENTRY_POINT com/craftinginterpreters/lox/Lox) diff --git a/src/com/craftinginterpreters/lox/Environment.java b/src/com/craftinginterpreters/lox/Environment.java deleted file mode 100644 index 407b9b3..0000000 --- a/src/com/craftinginterpreters/lox/Environment.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.HashMap; -import java.util.Map; - -class Environment { - final Environment enclosing; - private final Map values = new HashMap<>(); - - Environment() { - enclosing = null; - } - - Environment(Environment enclosing) { - this.enclosing = enclosing; - } - - Object get(Token name) { - if (values.containsKey(name.lexeme)) { - return values.get(name.lexeme); - } - - if (enclosing != null) - return enclosing.get(name); - - throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'."); - } - - void assign(Token name, Object value) { - if (values.containsKey(name.lexeme)) { - values.put(name.lexeme, value); - return; - } - - if (enclosing != null) { - enclosing.assign(name, value); - return; - } - - throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'."); - } - - void define(String name, Object value) { - values.put(name, value); - } - - Environment ancestor(int distance) { - Environment environment = this; - for (int i = 0; i < distance; i++) { - environment = environment.enclosing; - } - - return environment; - } - - Object getAt(int distance, String name) { - return ancestor(distance).values.get(name); - } - - void assignAt(int distance, Token name, Object value) { - ancestor(distance).values.put(name.lexeme, value); - } -} diff --git a/src/com/craftinginterpreters/lox/Interpreter.java b/src/com/craftinginterpreters/lox/Interpreter.java deleted file mode 100644 index 3f4d385..0000000 --- a/src/com/craftinginterpreters/lox/Interpreter.java +++ /dev/null @@ -1,392 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -class Interpreter implements Expr.Visitor, Stmt.Visitor { - final Environment globals = new Environment(); - private Environment environment = globals; - private final Map locals = new HashMap<>(); - - Interpreter() { - globals.define("clock", new LoxCallable() { - @Override - public int arity() { - return 0; - } - - @Override - public Object call(Interpreter interpreter, List arguments) { - return (double) System.currentTimeMillis() / 1000.0; - } - - @Override - public String toString() { - return ""; - } - }); - } - - @Override - public Object visitLiteralExpr(Expr.Literal expr) { - return expr.value; - } - - @Override - public Object visitLogicalExpr(Expr.Logical expr) { - Object left = evaluate(expr.left); - - if (expr.operator.type == TokenType.OR) { - if (isTruthy(left)) - return left; - } else { - if (!isTruthy(left)) - return left; - } - - return evaluate(expr.right); - } - - @Override - public Object visitSetExpr(Expr.Set expr) { - Object object = evaluate(expr.object); - - if (!(object instanceof LoxInstance)) { - throw new RuntimeError(expr.name, "Only instances have fields."); - } - - Object value = evaluate(expr.value); - ((LoxInstance) object).set(expr.name, value); - return value; - } - - @Override - public Object visitSuperExpr(Expr.Super expr) { - int distance = locals.get(expr); - LoxClass superclass = (LoxClass) environment.getAt(distance, "super"); - - LoxInstance object = (LoxInstance) environment.getAt(distance - 1, "this"); - - LoxFunction method = superclass.findMethod(expr.method.lexeme); - - if (method == null) { - throw new RuntimeError(expr.method, "Undefined property '" + expr.method.lexeme + "'."); - } - - return method.bind(object); - } - - @Override - public Object visitThisExpr(Expr.This expr) { - return lookUpVariable(expr.keyword, expr); - } - - @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; - } - - // Unreachable. - return null; - } - - @Override - public Object visitVariableExpr(Expr.Variable expr) { - return lookUpVariable(expr.name, expr); - } - - private Object lookUpVariable(Token name, Expr expr) { - Integer distance = locals.get(expr); - if (distance != null) { - return environment.getAt(distance, name.lexeme); - } else { - return globals.get(name); - } - } - - 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(); - } - - @Override - public Object visitGroupingExpr(Expr.Grouping expr) { - return evaluate(expr.expression); - } - - private Object evaluate(Expr expr) { - return expr.accept(this); - } - - private void execute(Stmt stmt) { - stmt.accept(this); - } - - public void resolve(Expr expr, int depth) { - locals.put(expr, depth); - } - - public void executeBlock(List statements, Environment environment) { - Environment previous = this.environment; - - try { - this.environment = environment; - - for (Stmt statement : statements) { - execute(statement); - } - } finally { - this.environment = previous; - } - } - - @Override - public Void visitBlockStmt(Stmt.Block stmt) { - executeBlock(stmt.statements, new Environment(environment)); - return null; - } - - @Override - public Void visitClassStmt(Stmt.Class stmt) { - Object superclass = null; - if (stmt.superclass != null) { - superclass = evaluate(stmt.superclass); - if (!(superclass instanceof LoxClass)) { - throw new RuntimeError(stmt.superclass.name, "Superclass must be a class."); - } - } - environment.define(stmt.name.lexeme, null); - - if (stmt.superclass != null) { - environment = new Environment(environment); - environment.define("super", superclass); - } - - Map methods = new HashMap<>(); - for (Stmt.Function method : stmt.methods) { - LoxFunction function = new LoxFunction(method, environment, method.name.lexeme.equals("init")); - methods.put(method.name.lexeme, function); - } - - LoxClass klass = new LoxClass(stmt.name.lexeme, (LoxClass) superclass, methods); - - if (superclass != null) { - environment = environment.enclosing; - } - - environment.assign(stmt.name, klass); - return null; - } - - @Override - public Void visitExpressionStmt(Stmt.Expression stmt) { - evaluate(stmt.expression); - return null; - } - - @Override - public Void visitFunctionStmt(Stmt.Function stmt) { - LoxFunction function = new LoxFunction(stmt, environment, false); - environment.define(stmt.name.lexeme, function); - return null; - } - - @Override - public Void visitIfStmt(Stmt.If stmt) { - if (isTruthy(evaluate(stmt.condition))) { - execute(stmt.thenBranch); - } else if (stmt.elseBranch != null) { - execute(stmt.elseBranch); - } - - return null; - } - - @Override - public Void visitPrintStmt(Stmt.Print stmt) { - Object value = evaluate(stmt.expression); - System.out.println(stringify(value)); - return null; - } - - @Override - public Void visitReturnStmt(Stmt.Return stmt) { - Object value = null; - if (stmt.value != null) - value = evaluate(stmt.value); - - throw new Return(value); - } - - @Override - public Void visitVarStmt(Stmt.Var stmt) { - Object value = null; - if (stmt.initializer != null) { - value = evaluate(stmt.initializer); - } - - environment.define(stmt.name.lexeme, value); - return null; - } - - @Override - public Void visitWhileStmt(Stmt.While stmt) { - while (isTruthy(evaluate(stmt.condition))) { - execute(stmt.body); - } - - return null; - } - - @Override - public Object visitAssignExpr(Expr.Assign expr) { - Object value = evaluate(expr.value); - - Integer distance = locals.get(expr); - if (distance != null) { - environment.assignAt(distance, expr.name, value); - } else { - globals.assign(expr.name, value); - } - - return value; - } - - @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 BANG_EQUAL: - return !isEqual(left, right); - case EQUAL_EQUAL: - return isEqual(left, 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; - } - - // Unreachable. - return null; - } - - @Override - public Object visitCallExpr(Expr.Call expr) { - Object callee = evaluate(expr.callee); - - List arguments = new ArrayList<>(); - for (Expr argument : expr.arguments) { - arguments.add(evaluate(argument)); - } - - if (!(callee instanceof LoxCallable)) { - throw new RuntimeError(expr.paren, "Can only call functions and classes."); - } - - LoxCallable function = (LoxCallable) callee; - if (arguments.size() != function.arity()) { - throw new RuntimeError(expr.paren, - "Expected " + function.arity() + " arguments but got " + arguments.size() + "."); - } - - return function.call(this, arguments); - } - - @Override - public Object visitGetExpr(Expr.Get expr) { - Object object = evaluate(expr.object); - if (object instanceof LoxInstance) { - return ((LoxInstance) object).get(expr.name); - } - - throw new RuntimeError(expr.name, "Only instances have properties."); - } - - public void interpret(List statements) { - try { - for (Stmt statement : statements) { - execute(statement); - } - } catch (RuntimeError error) { - Lox.runtimeError(error); - } - } -} diff --git a/src/com/craftinginterpreters/lox/Lox.java b/src/com/craftinginterpreters/lox/Lox.java deleted file mode 100644 index 6115f8f..0000000 --- a/src/com/craftinginterpreters/lox/Lox.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; - -public class Lox { - private static final Interpreter interpreter = new Interpreter(); - public static boolean hadError = false; - public static boolean hadRuntimeError = false; - - public static void main(String[] args) throws IOException { - if (args.length > 1) { - System.out.println("Usage: jlox [script]"); - System.exit(64); - } else if (args.length == 1) { - runFile(args[0]); - } else { - runPrompt(); - } - } - - private static void runFile(String path) throws IOException { - byte[] bytes = Files.readAllBytes(Paths.get(path)); - run(new String(bytes, Charset.defaultCharset())); - - // Indicate an error in the exit code. - if (hadError) - System.exit(65); - if (hadRuntimeError) - System.exit(70); - } - - private static void runPrompt() throws IOException { - InputStreamReader input = new InputStreamReader(System.in); - BufferedReader reader = new BufferedReader(input); - - for (;;) { - System.out.print("> "); - String line = reader.readLine(); - if (line == null) - break; - run(line); - hadError = false; - } - } - - private static void run(String source) { - Scanner scanner = new Scanner(source); - List tokens = scanner.scanTokens(); - Parser parser = new Parser(tokens); - List statements = parser.parse(); - - // Stop if there was a syntax error - if (hadError) - return; - - Resolver resolver = new Resolver(interpreter); - resolver.resolve(statements); - - // Stop if there was a resolution error - if (hadError) - return; - - interpreter.interpret(statements); - } - - public static void error(int line, String message) { - report(line, "", message); - } - - private static void report(int line, String where, String message) { - System.err.println("[line " + line + "] Error" + where + ": " + message); - hadError = true; - } - - public static void error(Token token, String message) { - if (token.type == TokenType.EOF) { - report(token.line, " at end", message); - } else { - report(token.line, " at '" + token.lexeme + "'", message); - } - } - - public static void runtimeError(RuntimeError error) { - System.err.println(error.getMessage() + "\n[line " + error.token.line + "]"); - hadRuntimeError = true; - } -} diff --git a/src/com/craftinginterpreters/lox/LoxCallable.java b/src/com/craftinginterpreters/lox/LoxCallable.java deleted file mode 100644 index 4204c20..0000000 --- a/src/com/craftinginterpreters/lox/LoxCallable.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.List; - -interface LoxCallable { - int arity(); - - Object call(Interpreter interpreter, List arguments); -} diff --git a/src/com/craftinginterpreters/lox/LoxClass.java b/src/com/craftinginterpreters/lox/LoxClass.java deleted file mode 100644 index 5d1c136..0000000 --- a/src/com/craftinginterpreters/lox/LoxClass.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.List; -import java.util.Map; - -class LoxClass implements LoxCallable { - final String name; - final LoxClass superclass; - private final Map methods; - - LoxClass(String name, LoxClass superclass, Map methods) { - this.superclass = superclass; - this.name = name; - this.methods = methods; - } - - LoxFunction findMethod(String name) { - if (methods.containsKey(name)) { - return methods.get(name); - } - - if (superclass != null) { - return superclass.findMethod(name); - } - - return null; - } - - @Override - public String toString() { - return name; - } - - @Override - public Object call(Interpreter interpreter, List arguments) { - LoxInstance instance = new LoxInstance(this); - LoxFunction initializer = findMethod("init"); - if (initializer != null) { - initializer.bind(instance).call(interpreter, arguments); - } - return instance; - } - - - @Override - public int arity() { - LoxFunction initializer = findMethod("init"); - if (initializer == null) return 0; - return initializer.arity(); - } -} diff --git a/src/com/craftinginterpreters/lox/LoxFunction.java b/src/com/craftinginterpreters/lox/LoxFunction.java deleted file mode 100644 index 07dd727..0000000 --- a/src/com/craftinginterpreters/lox/LoxFunction.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.List; - -class LoxFunction implements LoxCallable { - private final Stmt.Function declaration; - private final Environment closure; - private final boolean isInitializer; - - LoxFunction(Stmt.Function declaration, Environment closure, boolean isInitializer) { - this.isInitializer = isInitializer; - this.closure = closure; - this.declaration = declaration; - } - - LoxFunction bind(LoxInstance instance) { - Environment environment = new Environment(closure); - environment.define("this", instance); - return new LoxFunction(declaration, environment, isInitializer); - } - - @Override - public int arity() { - return declaration.params.size(); - } - - @Override - public Object call(Interpreter interpreter, List arguments) { - Environment environment = new Environment(closure); - - for (int i = 0; i < declaration.params.size(); i++) { - environment.define(declaration.params.get(i).lexeme, arguments.get(i)); - } - - try { - interpreter.executeBlock(declaration.body, environment); - } catch (Return returnValue) { - if (isInitializer) - return closure.getAt(0, "this"); - return returnValue.value; - } - - if (isInitializer) - return closure.getAt(0, "this"); - return null; - } - - @Override - public String toString() { - return ""; - } -} diff --git a/src/com/craftinginterpreters/lox/LoxInstance.java b/src/com/craftinginterpreters/lox/LoxInstance.java deleted file mode 100644 index 64989e0..0000000 --- a/src/com/craftinginterpreters/lox/LoxInstance.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.HashMap; -import java.util.Map; - -class LoxInstance { - private LoxClass klass; - private final Map fields = new HashMap<>(); - - LoxInstance(LoxClass klass) { - this.klass = klass; - } - - Object get(Token name) { - if (fields.containsKey(name.lexeme)) { - return fields.get(name.lexeme); - } - - LoxFunction method = klass.findMethod(name.lexeme); - if (method != null) - return method.bind(this); - - throw new RuntimeError(name, "Undefined proprety '" + name.lexeme + "'."); - } - - void set(Token name, Object value) { - fields.put(name.lexeme, value); - } - - @Override - public String toString() { - return klass.name + " instance"; - } -} diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java deleted file mode 100644 index ab4baaa..0000000 --- a/src/com/craftinginterpreters/lox/Parser.java +++ /dev/null @@ -1,457 +0,0 @@ -package com.craftinginterpreters.lox; - -import static com.craftinginterpreters.lox.TokenType.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -class Parser { - private static class ParseError extends RuntimeException { - } - - private final List tokens; - private int current = 0; - - Parser(List tokens) { - this.tokens = tokens; - } - - public List parse() { - List statements = new ArrayList<>(); - - while (!isAtEnd()) { - statements.add(declaration()); - } - - return statements; - } - - private Expr expression() { - return assignment(); - } - - private Stmt declaration() { - try { - if (match(CLASS)) - return classDeclaration(); - if (match(FUN)) - return function("function"); - if (match(VAR)) - return varDeclaration(); - - return statement(); - } catch (ParseError error) { - synchronize(); - return null; - } - } - - private Stmt classDeclaration() { - Token name = consume(IDENTIFIER, "Expect class name."); - - Expr.Variable superclass = null; - if (match(LESS)) { - consume(IDENTIFIER, "Expect superclass name."); - superclass = new Expr.Variable(previous()); - } - - consume(LEFT_BRACE, "Expect '{' before class body."); - - List methods = new ArrayList<>(); - while (!check(RIGHT_BRACE) && !isAtEnd()) { - methods.add(function("method")); - } - - consume(RIGHT_BRACE, "Expect '}' after class body."); - - return new Stmt.Class(name, superclass, methods); - } - - private Stmt statement() { - if (match(FOR)) - return forStatement(); - if (match(IF)) - return ifStatement(); - if (match(PRINT)) - return printStatement(); - if (match(RETURN)) - return returnStatement(); - if (match(WHILE)) - return whileStatement(); - if (match(LEFT_BRACE)) - return new Stmt.Block(block()); - - return expressionStatement(); - } - - private Stmt forStatement() { - consume(LEFT_PAREN, "Expect '(' after 'for'."); - - Stmt initializer; - if (match(SEMICOLON)) { - initializer = null; - } else if (match(VAR)) { - initializer = varDeclaration(); - } else { - initializer = expressionStatement(); - } - - Expr condition = null; - if (!check(SEMICOLON)) { - condition = expression(); - } - consume(SEMICOLON, "Expect ';' after loop condition."); - - Expr increment = null; - if (!check(RIGHT_PAREN)) { - increment = expression(); - } - consume(RIGHT_PAREN, "Expect ')' after for clauses."); - Stmt body = statement(); - - if (increment != null) { - body = new Stmt.Block(Arrays.asList(body, new Stmt.Expression(increment))); - } - - if (condition == null) - condition = new Expr.Literal(true); - body = new Stmt.While(condition, body); - - if (initializer != null) { - body = new Stmt.Block(Arrays.asList(initializer, body)); - } - - return body; - } - - private Stmt ifStatement() { - consume(LEFT_PAREN, "Expect '(' after 'if'."); - Expr condition = expression(); - consume(RIGHT_PAREN, "Expect ')' after if condition."); - - Stmt thenBranch = statement(); - Stmt elseBranch = null; - if (match(ELSE)) { - elseBranch = statement(); - } - - return new Stmt.If(condition, thenBranch, elseBranch); - } - - private Stmt printStatement() { - Expr value = expression(); - consume(SEMICOLON, "Expect ';' after value."); - return new Stmt.Print(value); - } - - private Stmt returnStatement() { - Token keyword = previous(); - Expr value = null; - if (!check(SEMICOLON)) { - value = expression(); - } - - consume(SEMICOLON, "Expect ';' after return value."); - return new Stmt.Return(keyword, value); - } - - private Stmt varDeclaration() { - Token name = consume(IDENTIFIER, "Expect variable name."); - - Expr initializer = null; - if (match(EQUAL)) { - initializer = expression(); - } - - consume(SEMICOLON, "Expect ';' after variable declaration."); - return new Stmt.Var(name, initializer); - } - - private Stmt whileStatement() { - consume(LEFT_PAREN, "Expect '(' after 'while'."); - Expr condition = expression(); - consume(RIGHT_PAREN, "Expect ')' after condition."); - Stmt body = statement(); - - return new Stmt.While(condition, body); - } - - private Stmt expressionStatement() { - Expr expr = expression(); - consume(SEMICOLON, "Expect ';' after expression."); - return new Stmt.Expression(expr); - } - - private Stmt.Function function(String kind) { - Token name = consume(IDENTIFIER, "Expect " + kind + " name."); - consume(LEFT_PAREN, "Expect '(' after " + kind + " name."); - List parameters = new ArrayList(); - if (!check(RIGHT_PAREN)) { - do { - if (parameters.size() >= 255) { - error(peek(), "Can't have more than 255 parameters."); - } - - parameters.add(consume(IDENTIFIER, "Expect parameter name.")); - } while (match(COMMA)); - } - consume(RIGHT_PAREN, "Expect ')' after parameters."); - - consume(LEFT_BRACE, "Expect '{' before " + kind + " body."); - List body = block(); - return new Stmt.Function(name, parameters, body); - } - - private List block() { - List statements = new ArrayList<>(); - - while (!check(RIGHT_BRACE) && !isAtEnd()) { - statements.add(declaration()); - } - - consume(RIGHT_BRACE, "Expect '}' after block."); - return statements; - } - - private Expr assignment() { - Expr expr = or(); - - if (match(EQUAL)) { - Token equals = previous(); - Expr value = assignment(); - - if (expr instanceof Expr.Variable) { - Token name = ((Expr.Variable) expr).name; - return new Expr.Assign(name, value); - } else if (expr instanceof Expr.Get) { - Expr.Get get = (Expr.Get) expr; - return new Expr.Set(get.object, get.name, value); - } - - error(equals, "Invalid assignment target."); - } - - return expr; - } - - private Expr or() { - Expr expr = and(); - - while (match(OR)) { - Token operator = previous(); - Expr right = and(); - expr = new Expr.Logical(expr, operator, right); - } - - return expr; - } - - private Expr and() { - Expr expr = equality(); - - while (match(AND)) { - Token operator = previous(); - Expr right = equality(); - expr = new Expr.Logical(expr, operator, right); - } - - return expr; - } - - private Expr equality() { - Expr expr = comparison(); - - while (match(BANG_EQUAL, EQUAL_EQUAL)) { - Token operator = previous(); - Expr right = comparison(); - expr = new Expr.Binary(expr, operator, right); - } - - return expr; - } - - private Expr comparison() { - Expr expr = term(); - - while (match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL)) { - Token operator = previous(); - Expr right = term(); - expr = new Expr.Binary(expr, operator, right); - } - - return expr; - } - - private Expr term() { - Expr expr = factor(); - - while (match(MINUS, PLUS)) { - Token operator = previous(); - Expr right = factor(); - expr = new Expr.Binary(expr, operator, right); - } - - return expr; - } - - private Expr factor() { - Expr expr = unary(); - - while (match(SLASH, STAR)) { - Token operator = previous(); - Expr right = unary(); - expr = new Expr.Binary(expr, operator, right); - } - - return expr; - } - - private Expr unary() { - if (match(BANG, MINUS)) { - Token operator = previous(); - Expr right = unary(); - return new Expr.Unary(operator, right); - } - - return call(); - } - - private Expr finishCall(Expr callee) { - List arguments = new ArrayList<>(); - if (!check(RIGHT_PAREN)) { - do { - if (arguments.size() >= 255) { - error(peek(), "Can't have more than 255 arguments."); - } - arguments.add(expression()); - } while (match(COMMA)); - } - - Token paren = consume(RIGHT_PAREN, "Expect ')' after arguments."); - - return new Expr.Call(callee, paren, arguments); - } - - private Expr call() { - Expr expr = primary(); - - while (true) { - if (match(LEFT_PAREN)) { - expr = finishCall(expr); - } else if (match(DOT)) { - Token name = consume(IDENTIFIER, "Expect property name after '.'"); - expr = new Expr.Get(expr, name); - } else { - break; - } - } - - return expr; - } - - private Expr primary() { - if (match(FALSE)) - return new Expr.Literal(false); - if (match(TRUE)) - return new Expr.Literal(true); - if (match(NIL)) - return new Expr.Literal(null); - - if (match(NUMBER, STRING)) { - return new Expr.Literal(previous().literal); - } - - if (match(SUPER)) { - Token keyword = previous(); - consume(DOT, "Expect '.' after 'super'."); - Token method = consume(IDENTIFIER, "Expect superclass method name."); - return new Expr.Super(keyword, method); - } - - if (match(THIS)) - return new Expr.This(previous()); - - if (match(IDENTIFIER)) { - return new Expr.Variable(previous()); - } - - if (match(LEFT_PAREN)) { - Expr expr = expression(); - consume(RIGHT_PAREN, "Expect ')' after expression."); - return new Expr.Grouping(expr); - } - - throw error(peek(), "Expect expression."); - } - - private boolean match(TokenType... types) { - for (TokenType type : types) { - if (check(type)) { - advance(); - return true; - } - } - - return false; - } - - private Token consume(TokenType type, String message) { - if (check(type)) - return advance(); - - throw error(peek(), message); - } - - private boolean check(TokenType type) { - if (isAtEnd()) - return false; - return peek().type == type; - } - - private Token advance() { - if (!isAtEnd()) - current++; - return previous(); - } - - private boolean isAtEnd() { - return peek().type == EOF; - } - - private Token peek() { - return tokens.get(current); - } - - private Token previous() { - return tokens.get(current - 1); - } - - private ParseError error(Token token, String message) { - Lox.error(token, message); - return new ParseError(); - } - - private void synchronize() { - advance(); - - while (!isAtEnd()) { - if (previous().type == SEMICOLON) - return; - - switch (peek().type) { - case CLASS: - case FUN: - case VAR: - case FOR: - case IF: - case WHILE: - case PRINT: - case RETURN: - return; - } - - advance(); - } - } -} diff --git a/src/com/craftinginterpreters/lox/Resolver.java b/src/com/craftinginterpreters/lox/Resolver.java deleted file mode 100644 index fe3a641..0000000 --- a/src/com/craftinginterpreters/lox/Resolver.java +++ /dev/null @@ -1,299 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -class Resolver implements Expr.Visitor, Stmt.Visitor { - private final Interpreter interpreter; - private final Stack> scopes = new Stack<>(); - private FunctionType currentFunction = FunctionType.NONE; - - Resolver(Interpreter interpreter) { - this.interpreter = interpreter; - } - - private enum FunctionType { - NONE, FUNCTION, INITIALIZER, METHOD - } - - private enum ClassType { - NONE, CLASS, SUBCLASS - } - - private ClassType currentClass = ClassType.NONE; - - public void resolve(List statements) { - for (Stmt statement : statements) { - resolve(statement); - } - } - - @Override - public Void visitBlockStmt(Stmt.Block stmt) { - beginScope(); - resolve(stmt.statements); - endScope(); - return null; - } - - @Override - public Void visitClassStmt(Stmt.Class stmt) { - ClassType enclosingClass = currentClass; - currentClass = ClassType.CLASS; - - declare(stmt.name); - define(stmt.name); - - if (stmt.superclass != null && stmt.name.lexeme.equals(stmt.superclass.name.lexeme)) { - Lox.error(stmt.superclass.name, "A class can't inherit from itself."); - } - - if (stmt.superclass != null) { - currentClass = ClassType.SUBCLASS; - - resolve(stmt.superclass); - } - - if (stmt.superclass != null) { - beginScope(); - scopes.peek().put("super", true); - } - - beginScope(); - scopes.peek().put("this", true); - - for (Stmt.Function method : stmt.methods) { - FunctionType declaration = FunctionType.METHOD; - if (method.name.lexeme.equals("init")) { - declaration = FunctionType.INITIALIZER; - } - resolveFunction(method, declaration); - } - - endScope(); - - if (stmt.superclass != null) { - endScope(); - } - - currentClass = enclosingClass; - return null; - } - - @Override - public Void visitExpressionStmt(Stmt.Expression stmt) { - resolve(stmt.expression); - return null; - } - - @Override - public Void visitFunctionStmt(Stmt.Function stmt) { - declare(stmt.name); - define(stmt.name); - - resolveFunction(stmt, FunctionType.FUNCTION); - return null; - } - - @Override - public Void visitIfStmt(Stmt.If stmt) { - resolve(stmt.condition); - resolve(stmt.thenBranch); - if (stmt.elseBranch != null) - resolve(stmt.elseBranch); - return null; - } - - @Override - public Void visitPrintStmt(Stmt.Print stmt) { - resolve(stmt.expression); - return null; - } - - @Override - public Void visitReturnStmt(Stmt.Return stmt) { - if (currentFunction == FunctionType.NONE) { - Lox.error(stmt.keyword, "Can't return from top-level code."); - } - - if (stmt.value != null) { - if (currentFunction == FunctionType.INITIALIZER) { - Lox.error(stmt.keyword, "Can't return a value from an initializer."); - } - resolve(stmt.value); - } - - return null; - } - - @Override - public Void visitVarStmt(Stmt.Var stmt) { - declare(stmt.name); - if (stmt.initializer != null) { - resolve(stmt.initializer); - } - define(stmt.name); - return null; - } - - @Override - public Void visitWhileStmt(Stmt.While stmt) { - resolve(stmt.condition); - resolve(stmt.body); - return null; - } - - @Override - public Void visitAssignExpr(Expr.Assign expr) { - resolve(expr.value); - resolveLocal(expr, expr.name); - return null; - } - - @Override - public Void visitBinaryExpr(Expr.Binary expr) { - resolve(expr.left); - resolve(expr.right); - return null; - } - - @Override - public Void visitCallExpr(Expr.Call expr) { - resolve(expr.callee); - - for (Expr argument : expr.arguments) { - resolve(argument); - } - - return null; - } - - @Override - public Void visitGetExpr(Expr.Get expr) { - resolve(expr.object); - return null; - } - - @Override - public Void visitGroupingExpr(Expr.Grouping expr) { - resolve(expr.expression); - return null; - } - - @Override - public Void visitLiteralExpr(Expr.Literal expr) { - return null; - } - - @Override - public Void visitSetExpr(Expr.Set expr) { - resolve(expr.value); - resolve(expr.object); - return null; - } - - @Override - public Void visitSuperExpr(Expr.Super expr) { - if (currentClass == ClassType.NONE) { - Lox.error(expr.keyword, "Can't use 'super' outside of a class."); - } else if (currentClass != ClassType.SUBCLASS) { - Lox.error(expr.keyword, "Can't use 'super' in a class with no superclass."); - } - - resolveLocal(expr, expr.keyword); - return null; - } - - @Override - public Void visitThisExpr(Expr.This expr) { - if (currentClass == ClassType.NONE) { - Lox.error(expr.keyword, "Can't use 'this' outside of a class."); - return null; - } - - resolveLocal(expr, expr.keyword); - return null; - } - - @Override - public Void visitLogicalExpr(Expr.Logical expr) { - resolve(expr.left); - resolve(expr.right); - return null; - } - - @Override - public Void visitUnaryExpr(Expr.Unary expr) { - resolve(expr.right); - return null; - } - - @Override - public Void visitVariableExpr(Expr.Variable expr) { - if (!scopes.isEmpty() && scopes.peek().get(expr.name.lexeme) == Boolean.FALSE) { - Lox.error(expr.name, "Can't read local variable in its own initializer."); - } - - resolveLocal(expr, expr.name); - return null; - } - - private void resolve(Stmt stmt) { - stmt.accept(this); - } - - private void resolve(Expr expr) { - expr.accept(this); - } - - private void resolveFunction(Stmt.Function function, FunctionType type) { - FunctionType enclosingFunction = currentFunction; - currentFunction = type; - - beginScope(); - for (Token param : function.params) { - declare(param); - define(param); - } - resolve(function.body); - endScope(); - currentFunction = enclosingFunction; - } - - private void beginScope() { - scopes.push(new HashMap()); - } - - private void endScope() { - scopes.pop(); - - } - - private void declare(Token name) { - if (scopes.isEmpty()) - return; - - Map scope = scopes.peek(); - if (scope.containsKey(name.lexeme)) { - Lox.error(name, "Already variable with this name in this scope."); - } - scope.put(name.lexeme, false); - } - - private void define(Token name) { - if (scopes.isEmpty()) - return; - scopes.peek().put(name.lexeme, true); - } - - private void resolveLocal(Expr expr, Token name) { - for (int i = scopes.size() - 1; i >= 0; i--) { - if (scopes.get(i).containsKey(name.lexeme)) { - interpreter.resolve(expr, scopes.size() - 1 - i); - return; - } - } - } -} diff --git a/src/com/craftinginterpreters/lox/Return.java b/src/com/craftinginterpreters/lox/Return.java deleted file mode 100644 index 5bd62d0..0000000 --- a/src/com/craftinginterpreters/lox/Return.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.craftinginterpreters.lox; - -class Return extends RuntimeException { - final Object value; - - Return(Object value) { - super(null, null, false, false); - this.value = value; - } -} diff --git a/src/com/craftinginterpreters/lox/RuntimeError.java b/src/com/craftinginterpreters/lox/RuntimeError.java deleted file mode 100644 index 017865b..0000000 --- a/src/com/craftinginterpreters/lox/RuntimeError.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.craftinginterpreters.lox; - -class RuntimeError extends RuntimeException { - final Token token; - - RuntimeError(Token token, String message) { - super(message); - this.token = token; - } -} diff --git a/src/com/craftinginterpreters/lox/Scanner.java b/src/com/craftinginterpreters/lox/Scanner.java deleted file mode 100644 index e21f701..0000000 --- a/src/com/craftinginterpreters/lox/Scanner.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.craftinginterpreters.lox; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.craftinginterpreters.lox.TokenType.*; - -class Scanner { - private final String source; - private final List tokens = new ArrayList<>(); - private int start = 0; - private int current = 0; - private int line = 1; - private static final Map keywords; - - static { - keywords = new HashMap<>(); - keywords.put("and", AND); - keywords.put("class", CLASS); - keywords.put("else", ELSE); - keywords.put("false", FALSE); - keywords.put("for", FOR); - keywords.put("fun", FUN); - keywords.put("if", IF); - keywords.put("nil", NIL); - keywords.put("or", OR); - keywords.put("print", PRINT); - keywords.put("return", RETURN); - keywords.put("super", SUPER); - keywords.put("this", THIS); - keywords.put("true", TRUE); - keywords.put("var", VAR); - keywords.put("while", WHILE); - } - - Scanner(String source) { - this.source = source; - } - - List scanTokens() { - while (!isAtEnd()) { - // We are at the beginning of the next lexeme. - start = current; - scanToken(); - } - - tokens.add(new Token(EOF, "", null, line)); - return tokens; - } - - private void scanToken() { - char c = advance(); - - switch (c) { - case '(': addToken(LEFT_PAREN); break; - case ')': addToken(RIGHT_PAREN); break; - case '{': addToken(LEFT_BRACE); break; - case '}': addToken(RIGHT_BRACE); break; - case ',': addToken(COMMA); break; - case '.': addToken(DOT); break; - case '-': addToken(MINUS); break; - case '+': addToken(PLUS); break; - case ';': addToken(SEMICOLON); break; - case '*': addToken(STAR); break; - case '!': - addToken(match('=') ? BANG_EQUAL : BANG); - break; - case '=': - addToken(match('=') ? EQUAL_EQUAL : EQUAL); - break; - case '<': - addToken(match('=') ? LESS_EQUAL : LESS); - break; - case '>': - addToken(match('=') ? GREATER_EQUAL : GREATER); - break; - case '/': - if (match('/')) { - // A comment goes until the end of the line. - while (peek() != '\n' && !isAtEnd()) advance(); - } else { - addToken(SLASH); - } - break; - - case ' ': - case '\r': - case '\t': - // Ignore whitespace. - break; - - // I guess this code isn't meant to run on Mac OS 9 and before. - case '\n': - line++; - break; - - case '"': string(); break; - - default: - if (isDigit(c)) { - number(); - } else if (isAlpha(c)) { - identifier(); - } else { - Lox.error(line, "Unexpected character."); - } - break; - } - } - - private void identifier() { - while (isAlphaNumeric(peek())) advance(); - - String text = source.substring(start, current); - TokenType type = keywords.get(text); - if (type == null) type = IDENTIFIER; - addToken(type); - } - - private void number() { - while (isDigit(peek())) advance(); - - // Look for a fractional part. - if (peek() == '.' && isDigit(peekNext())) { - // Consume the "." - advance(); - - while (isDigit(peek())) advance(); - } - - addToken(NUMBER, - Double.parseDouble(source.substring(start, current))); - } - - // I guess we won't be able to include escaped characters in the string? At - // least not escaped " characters. - private void string() { - while (peek() != '"' && !isAtEnd()) { - if (peek() == '\n') line++; - advance(); - } - - if (isAtEnd()) { - Lox.error(line, "Unterminated string."); - return; - } - - // The closing ". - advance(); - - // Trim the surrounding quotes. - String value = source.substring(start + 1, current - 1); - addToken(STRING, value); - } - - private boolean match(char expected) { - if (isAtEnd()) return false; - if (source.charAt(current) != expected) return false; - - current++; - return true; - } - - private char peek() { - if (isAtEnd()) return '\0'; - return source.charAt(current); - } - - private char peekNext() { - if (current + 1 >= source.length()) return '\0'; - return source.charAt(current + 1); - } - - private boolean isAlpha(char c) { - return (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - c == '_'; - } - - private boolean isAlphaNumeric(char c) { - return isAlpha(c) || isDigit(c); - } - - private boolean isDigit(char c) { - return c >= '0' && c <= '9'; - } - - private boolean isAtEnd() { - return current >= source.length(); - } - - private char advance() { - current++; - return source.charAt(current - 1); - } - - private void addToken(TokenType type) { - addToken(type, null); - } - - private void addToken(TokenType type, Object literal) { - String text = source.substring(start, current); - tokens.add(new Token(type, text, literal, line)); - } -} diff --git a/src/com/craftinginterpreters/lox/Token.java b/src/com/craftinginterpreters/lox/Token.java deleted file mode 100644 index 84762a4..0000000 --- a/src/com/craftinginterpreters/lox/Token.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.craftinginterpreters.lox; - -class Token { - final TokenType type; - final String lexeme; - final Object literal; - final int line; - - Token(TokenType type, String lexeme, Object literal, int line) { - this.type = type; - this.lexeme = lexeme; - this.literal = literal; - this.line = line; - } - - public String toString() { - return type + " " + lexeme + " " + literal; - } -} diff --git a/src/com/craftinginterpreters/lox/TokenType.java b/src/com/craftinginterpreters/lox/TokenType.java deleted file mode 100644 index 9ab2a8b..0000000 --- a/src/com/craftinginterpreters/lox/TokenType.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.craftinginterpreters.lox; - -enum TokenType { - // Single-character tokens. - LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, COMMA, DOT, MINUS, PLUS, - SEMICOLON, SLASH, STAR, - - // One or two character tokens. - BANG, BANG_EQUAL, EQUAL, EQUAL_EQUAL, GREATER, GREATER_EQUAL, LESS, - LESS_EQUAL, - - // Literals. - IDENTIFIER, STRING, NUMBER, - - // Keywords. - AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR, PRINT, RETURN, SUPER, THIS, - TRUE, VAR, WHILE, - - EOF -} -- cgit v1.2.3-54-g00ecf