aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-07-08 00:14:31 -0700
committerGravatar Tom Willemse2021-07-08 02:25:13 -0700
commit68a2ebd34fc94488e89ffb82b359ec6e7e152ae9 (patch)
tree0dbbe26aff8fc38805b4b3780ae7842c433b9522 /src
parent62bd0f83dc909547a69abb8b0aed40cf098b4c95 (diff)
downloadcrafting-interpreters-68a2ebd34fc94488e89ffb82b359ec6e7e152ae9.tar.gz
crafting-interpreters-68a2ebd34fc94488e89ffb82b359ec6e7e152ae9.zip
Restructure project to make room for clox
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore1
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/CMakePresets.json17
-rw-r--r--src/com/craftinginterpreters/CMakeLists.txt2
-rw-r--r--src/com/craftinginterpreters/lox/.gitignore1
-rw-r--r--src/com/craftinginterpreters/lox/AstPrinter.java147
-rw-r--r--src/com/craftinginterpreters/lox/CMakeLists.txt28
-rw-r--r--src/com/craftinginterpreters/lox/Environment.java63
-rw-r--r--src/com/craftinginterpreters/lox/Interpreter.java392
-rw-r--r--src/com/craftinginterpreters/lox/Lox.java93
-rw-r--r--src/com/craftinginterpreters/lox/LoxCallable.java9
-rw-r--r--src/com/craftinginterpreters/lox/LoxClass.java51
-rw-r--r--src/com/craftinginterpreters/lox/LoxFunction.java52
-rw-r--r--src/com/craftinginterpreters/lox/LoxInstance.java34
-rw-r--r--src/com/craftinginterpreters/lox/Parser.java457
-rw-r--r--src/com/craftinginterpreters/lox/Resolver.java299
-rw-r--r--src/com/craftinginterpreters/lox/Return.java10
-rw-r--r--src/com/craftinginterpreters/lox/RuntimeError.java10
-rw-r--r--src/com/craftinginterpreters/lox/Scanner.java207
-rw-r--r--src/com/craftinginterpreters/lox/Token.java19
-rw-r--r--src/com/craftinginterpreters/lox/TokenType.java20
-rw-r--r--src/com/craftinginterpreters/tool/CMakeLists.txt3
-rw-r--r--src/com/craftinginterpreters/tool/GenerateAst.java100
-rw-r--r--src/fib.lox9
-rw-r--r--src/test.lox7
25 files changed, 16 insertions, 2023 deletions
diff --git a/src/.gitignore b/src/.gitignore
deleted file mode 100644
index e35d885..0000000
--- a/src/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-_build
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index 52a7d57..0000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-cmake_minimum_required(VERSION 2.19)
-
-find_package(Java REQUIRED)
-include(UseJava)
-
-project(Lox NONE)
-
-add_subdirectory(com/craftinginterpreters)
diff --git a/src/CMakePresets.json b/src/CMakePresets.json
deleted file mode 100644
index 728cdb0..0000000
--- a/src/CMakePresets.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "version": 1,
- "cmakeMinimumRequired": {
- "major": 3,
- "minor": 19,
- "patch": 0
- },
- "configurePresets": [
- {
- "name": "default",
- "displayName": "Default Config",
- "description": "Default build using Makefile generator",
- "generator": "Unix Makefiles",
- "binaryDir": "${sourceDir}/_build"
- }
- ]
-}
diff --git a/src/com/craftinginterpreters/CMakeLists.txt b/src/com/craftinginterpreters/CMakeLists.txt
deleted file mode 100644
index 959eedd..0000000
--- a/src/com/craftinginterpreters/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-add_subdirectory(tool)
-add_subdirectory(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<String>, Stmt.Visitor<String> {
- 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<Expr> 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<Stmt> 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<String, Object> 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<Object>, Stmt.Visitor<Void> {
- final Environment globals = new Environment();
- private Environment environment = globals;
- private final Map<Expr, Integer> locals = new HashMap<>();
-
- Interpreter() {
- globals.define("clock", new LoxCallable() {
- @Override
- public int arity() {
- return 0;
- }
-
- @Override
- public Object call(Interpreter interpreter, List<Object> arguments) {
- return (double) System.currentTimeMillis() / 1000.0;
- }
-
- @Override
- public String toString() {
- return "<native fn>";
- }
- });
- }
-
- @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<Stmt> 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<String, LoxFunction> 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<Object> 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<Stmt> 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<Token> tokens = scanner.scanTokens();
- Parser parser = new Parser(tokens);
- List<Stmt> 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<Object> 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<String, LoxFunction> methods;
-
- LoxClass(String name, LoxClass superclass, Map<String, LoxFunction> 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<Object> 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<Object> 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 "<fn " + declaration.name.lexeme + ">";
- }
-}
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<String, Object> 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<Token> tokens;
- private int current = 0;
-
- Parser(List<Token> tokens) {
- this.tokens = tokens;
- }
-
- public List<Stmt> parse() {
- List<Stmt> 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<Stmt.Function> 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<Token> 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<Stmt> body = block();
- return new Stmt.Function(name, parameters, body);
- }
-
- private List<Stmt> block() {
- List<Stmt> 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<Expr> 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<Void>, Stmt.Visitor<Void> {
- private final Interpreter interpreter;
- private final Stack<Map<String, Boolean>> 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<Stmt> 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<String, Boolean>());
- }
-
- private void endScope() {
- scopes.pop();
-
- }
-
- private void declare(Token name) {
- if (scopes.isEmpty())
- return;
-
- Map<String, Boolean> 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<Token> tokens = new ArrayList<>();
- private int start = 0;
- private int current = 0;
- private int line = 1;
- private static final Map<String, TokenType> 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<Token> 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
-}
diff --git a/src/com/craftinginterpreters/tool/CMakeLists.txt b/src/com/craftinginterpreters/tool/CMakeLists.txt
deleted file mode 100644
index b98d2eb..0000000
--- a/src/com/craftinginterpreters/tool/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-add_jar(GenerateAst
- GenerateAst.java
- ENTRY_POINT com/craftinginterpreters/tool/GenerateAst)
diff --git a/src/com/craftinginterpreters/tool/GenerateAst.java b/src/com/craftinginterpreters/tool/GenerateAst.java
deleted file mode 100644
index 04b4500..0000000
--- a/src/com/craftinginterpreters/tool/GenerateAst.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.craftinginterpreters.tool;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.List;
-
-public class GenerateAst {
- public static void main(String[] args) throws IOException {
- if (args.length != 1) {
- System.err.println("Usage: generate_ast <output directory>");
- System.exit(64);
- }
-
- String outputDir = args[0];
-
- defineAst(outputDir, "Expr",
- Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right",
- "Call : Expr callee, Token paren, List<Expr> arguments", "Get : Expr object, Token name",
- "Grouping : Expr expression", "Literal : Object value",
- "Logical : Expr left, Token operator, Expr right", "Set : Expr object, Token name, Expr value",
- "Super : Token keyword, Token method", "This : Token keyword",
- "Unary : Token operator, Expr right", "Variable : Token name"));
- defineAst(outputDir, "Stmt",
- Arrays.asList("Block : List<Stmt> statements",
- "Class : Token name, Expr.Variable superclass, List<Stmt.Function> methods",
- "Expression : Expr expression", "Function : Token name, List<Token> params, List<Stmt> body",
- "If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
- "Return : Token keyword, Expr value", "Var : Token name, Expr initializer",
- "While : Expr condition, Stmt body"));
- }
-
- private static void defineAst(String outputDir, String baseName, List<String> types) throws IOException {
- String path = outputDir + "/" + baseName + ".java";
- PrintWriter writer = new PrintWriter(path);
-
- writer.println("package com.craftinginterpreters.lox;");
- writer.println();
- writer.println("import java.util.List;");
- writer.println();
- writer.println("abstract class " + baseName + " {");
-
- defineVisitor(writer, baseName, types);
-
- for (String type : types) {
- String className = type.split(":")[0].trim();
- String fields = type.split(":")[1].trim();
- defineType(writer, baseName, className, fields);
- }
-
- // The base accept() method
- writer.println();
- writer.println(" abstract <R> R accept(Visitor<R> visitor);");
-
- writer.println("}");
- writer.close();
- }
-
- private static void defineVisitor(PrintWriter writer, String baseName, List<String> types) {
- writer.println(" interface Visitor<R> {");
-
- for (String type : types) {
- String typeName = type.split(":")[0].trim();
- writer.println(" R visit" + typeName + baseName + "(" + typeName + " " + baseName.toLowerCase() + ");");
- }
-
- writer.println(" }");
- }
-
- private static void defineType(PrintWriter writer, String baseName, String className, String fieldList) {
- writer.println(" static class " + className + " extends " + baseName + " {");
-
- // Constructor
- writer.println(" " + className + "(" + fieldList + ") {");
-
- // Store parameters in fields.
- String[] fields = fieldList.split(", ");
- for (String field : fields) {
- String name = field.split(" ")[1];
- writer.println(" this." + name + " = " + name + ";");
- }
-
- writer.println(" }");
-
- // Visitor pattern.
- writer.println();
- writer.println(" @Override");
- writer.println(" <R> R accept(Visitor<R> visitor) {");
- writer.println(" return visitor.visit" + className + baseName + "(this);");
- writer.println(" }");
-
- // Fields
- writer.println();
- for (String field : fields) {
- writer.println(" final " + field + ";");
- }
-
- writer.println(" }");
- }
-}
diff --git a/src/fib.lox b/src/fib.lox
new file mode 100644
index 0000000..dd6fb5e
--- /dev/null
+++ b/src/fib.lox
@@ -0,0 +1,9 @@
+fun fib(n) {
+ if (n < 2) return n;
+ return fib(n - 1) + fib(n - 2);
+}
+
+var before = clock();
+print fib(40);
+var after = clock();
+print after - before;
diff --git a/src/test.lox b/src/test.lox
new file mode 100644
index 0000000..8810767
--- /dev/null
+++ b/src/test.lox
@@ -0,0 +1,7 @@
+class Bacon {
+eat() {
+print "Crunch crunch crunch!";
+}
+}
+
+Bacon().eat();