From 4a71c219b5fa8e9e28af43925284f429092ba68e Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Sun, 31 Jan 2021 17:11:47 -0800 Subject: [PATCH] Add function calls --- .../craftinginterpreters/lox/CMakeLists.txt | 2 +- .../craftinginterpreters/lox/Interpreter.java | 30 +++++++++++++++-- .../craftinginterpreters/lox/LoxFunction.java | 33 +++++++++++++++++++ src/com/craftinginterpreters/lox/Parser.java | 22 +++++++++++++ .../tool/GenerateAst.java | 1 + 5 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/com/craftinginterpreters/lox/LoxFunction.java diff --git a/src/com/craftinginterpreters/lox/CMakeLists.txt b/src/com/craftinginterpreters/lox/CMakeLists.txt index b437b7a..a068037 100644 --- a/src/com/craftinginterpreters/lox/CMakeLists.txt +++ b/src/com/craftinginterpreters/lox/CMakeLists.txt @@ -15,10 +15,10 @@ add_jar(Lox Token.java Scanner.java ${GENERATED_JAVA_FILENAMES} - AstPrinter.java Parser.java Interpreter.java RuntimeError.java Environment.java LoxCallable.java + LoxFunction.java ENTRY_POINT com/craftinginterpreters/lox/Lox) diff --git a/src/com/craftinginterpreters/lox/Interpreter.java b/src/com/craftinginterpreters/lox/Interpreter.java index f752e77..407c537 100644 --- a/src/com/craftinginterpreters/lox/Interpreter.java +++ b/src/com/craftinginterpreters/lox/Interpreter.java @@ -4,7 +4,23 @@ import java.util.ArrayList; import java.util.List; class Interpreter implements Expr.Visitor, Stmt.Visitor { - private Environment environment = new Environment(); + final Environment globals = new Environment(); + private Environment environment = globals; + + 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) { @@ -105,7 +121,7 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { stmt.accept(this); } - private void executeBlock(List statements, Environment environment) { + public void executeBlock(List statements, Environment environment) { Environment previous = this.environment; try { @@ -131,6 +147,13 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { return null; } + @Override + public Void visitFunctionStmt(Stmt.Function stmt) { + LoxFunction function = new LoxFunction(stmt); + environment.define(stmt.name.lexeme, function); + return null; + } + @Override public Void visitIfStmt(Stmt.If stmt) { if (isTruthy(evaluate(stmt.condition))) { @@ -238,7 +261,8 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { LoxCallable function = (LoxCallable) callee; if (arguments.size() != function.arity()) { - throw new RuntimeError(expr.paren, "Expected " + function.arity() + " arguments but got " + arguments.size() + "."); + throw new RuntimeError(expr.paren, + "Expected " + function.arity() + " arguments but got " + arguments.size() + "."); } return function.call(this, arguments); diff --git a/src/com/craftinginterpreters/lox/LoxFunction.java b/src/com/craftinginterpreters/lox/LoxFunction.java new file mode 100644 index 0000000..d2e367b --- /dev/null +++ b/src/com/craftinginterpreters/lox/LoxFunction.java @@ -0,0 +1,33 @@ +package com.craftinginterpreters.lox; + +import java.util.List; + +class LoxFunction implements LoxCallable { + private final Stmt.Function declaration; + + LoxFunction(Stmt.Function declaration) { + this.declaration = declaration; + } + + @Override + public int arity() { + return declaration.params.size(); + } + + @Override + public Object call(Interpreter interpreter, List arguments) { + Environment environment = new Environment(interpreter.globals); + + for (int i = 0; i < declaration.params.size(); i++) { + environment.define(declaration.params.get(i).lexeme, arguments.get(i)); + } + + interpreter.executeBlock(declaration.body, environment); + return null; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java index df3ce3f..c427bc4 100644 --- a/src/com/craftinginterpreters/lox/Parser.java +++ b/src/com/craftinginterpreters/lox/Parser.java @@ -33,6 +33,8 @@ class Parser { private Stmt declaration() { try { + if (match(FUN)) + return function("function"); if (match(VAR)) return varDeclaration(); @@ -145,6 +147,26 @@ class Parser { 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<>(); diff --git a/src/com/craftinginterpreters/tool/GenerateAst.java b/src/com/craftinginterpreters/tool/GenerateAst.java index 8c063bf..92c7967 100644 --- a/src/com/craftinginterpreters/tool/GenerateAst.java +++ b/src/com/craftinginterpreters/tool/GenerateAst.java @@ -21,6 +21,7 @@ public class GenerateAst { "Unary : Token operator, Expr right", "Variable : Token name")); defineAst(outputDir, "Stmt", Arrays.asList("Block : List statements", "Expression : Expr expression", + "Function : Token name, List params, List body", "If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression", "Var : Token name, Expr initializer", "While : Expr condition, Stmt body")); }