From a0df1715fcefd422a0cdd0d247c79cd966b304d5 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Wed, 17 Feb 2021 22:06:55 -0800 Subject: [PATCH] Add anonymous functions --- .../craftinginterpreters/lox/CMakeLists.txt | 1 + .../craftinginterpreters/lox/Interpreter.java | 5 +++ .../craftinginterpreters/lox/LoxLambda.java | 40 +++++++++++++++++++ src/com/craftinginterpreters/lox/Parser.java | 21 ++++++++++ .../tool/GenerateAst.java | 3 +- 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/com/craftinginterpreters/lox/LoxLambda.java diff --git a/src/com/craftinginterpreters/lox/CMakeLists.txt b/src/com/craftinginterpreters/lox/CMakeLists.txt index fa93588..53dbef3 100644 --- a/src/com/craftinginterpreters/lox/CMakeLists.txt +++ b/src/com/craftinginterpreters/lox/CMakeLists.txt @@ -22,4 +22,5 @@ add_jar(Lox LoxCallable.java LoxFunction.java Return.java + LoxLambda.java ENTRY_POINT com/craftinginterpreters/lox/Lox) diff --git a/src/com/craftinginterpreters/lox/Interpreter.java b/src/com/craftinginterpreters/lox/Interpreter.java index 3e3be86..b4efd5c 100644 --- a/src/com/craftinginterpreters/lox/Interpreter.java +++ b/src/com/craftinginterpreters/lox/Interpreter.java @@ -158,6 +158,11 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { return null; } + @Override + public Object visitLambdaExpr(Expr.Lambda expr) { + return new LoxLambda(expr, environment); + } + @Override public Void visitIfStmt(Stmt.If stmt) { if (isTruthy(evaluate(stmt.condition))) { diff --git a/src/com/craftinginterpreters/lox/LoxLambda.java b/src/com/craftinginterpreters/lox/LoxLambda.java new file mode 100644 index 0000000..8c87460 --- /dev/null +++ b/src/com/craftinginterpreters/lox/LoxLambda.java @@ -0,0 +1,40 @@ +package com.craftinginterpreters.lox; + +import java.util.List; + +class LoxLambda implements LoxCallable { + private final Expr.Lambda declaration; + private final Environment closure; + + LoxLambda(Expr.Lambda declaration, Environment closure) { + this.closure = closure; + this.declaration = declaration; + } + + @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) { + return returnValue.value; + } + + return null; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java index 528326c..b6c134a 100644 --- a/src/com/craftinginterpreters/lox/Parser.java +++ b/src/com/craftinginterpreters/lox/Parser.java @@ -28,6 +28,8 @@ class Parser { } private Expr expression() { + if (match(FUN)) + return lambda(); return assignment(); } @@ -180,6 +182,25 @@ class Parser { return new Stmt.Function(name, parameters, body); } + private Expr.Lambda lambda() { + consume(LEFT_PAREN, "You can't see this message."); + 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, "Expext '{' before lambda body."); + List body = block(); + return new Expr.Lambda(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 2bf442b..beb161e 100644 --- a/src/com/craftinginterpreters/tool/GenerateAst.java +++ b/src/com/craftinginterpreters/tool/GenerateAst.java @@ -18,7 +18,8 @@ public class GenerateAst { Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right", "Call : Expr callee, Token paren, List arguments", "Grouping : Expr expression", "Literal : Object value", "Logical : Expr left, Token operator, Expr right", - "Unary : Token operator, Expr right", "Variable : Token name")); + "Unary : Token operator, Expr right", "Variable : Token name", + "Lambda : List params, List body")); defineAst(outputDir, "Stmt", Arrays.asList("Block : List statements", "Expression : Expr expression", "Function : Token name, List params, List body",