Compare commits

...

1 commit

Author SHA1 Message Date
a0df1715fc Add anonymous functions 2021-02-17 22:06:55 -08:00
5 changed files with 69 additions and 1 deletions

View file

@ -22,4 +22,5 @@ add_jar(Lox
LoxCallable.java LoxCallable.java
LoxFunction.java LoxFunction.java
Return.java Return.java
LoxLambda.java
ENTRY_POINT com/craftinginterpreters/lox/Lox) ENTRY_POINT com/craftinginterpreters/lox/Lox)

View file

@ -158,6 +158,11 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
return null; return null;
} }
@Override
public Object visitLambdaExpr(Expr.Lambda expr) {
return new LoxLambda(expr, environment);
}
@Override @Override
public Void visitIfStmt(Stmt.If stmt) { public Void visitIfStmt(Stmt.If stmt) {
if (isTruthy(evaluate(stmt.condition))) { if (isTruthy(evaluate(stmt.condition))) {

View file

@ -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<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) {
return returnValue.value;
}
return null;
}
@Override
public String toString() {
return "<fn anonymous>";
}
}

View file

@ -28,6 +28,8 @@ class Parser {
} }
private Expr expression() { private Expr expression() {
if (match(FUN))
return lambda();
return assignment(); return assignment();
} }
@ -180,6 +182,25 @@ class Parser {
return new Stmt.Function(name, parameters, body); return new Stmt.Function(name, parameters, body);
} }
private Expr.Lambda lambda() {
consume(LEFT_PAREN, "You can't see this message.");
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, "Expext '{' before lambda body.");
List<Stmt> body = block();
return new Expr.Lambda(parameters, body);
}
private List<Stmt> block() { private List<Stmt> block() {
List<Stmt> statements = new ArrayList<>(); List<Stmt> statements = new ArrayList<>();

View file

@ -18,7 +18,8 @@ public class GenerateAst {
Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right", Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right",
"Call : Expr callee, Token paren, List<Expr> arguments", "Grouping : Expr expression", "Call : Expr callee, Token paren, List<Expr> arguments", "Grouping : Expr expression",
"Literal : Object value", "Logical : Expr left, Token operator, Expr right", "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<Token> params, List<Stmt> body"));
defineAst(outputDir, "Stmt", defineAst(outputDir, "Stmt",
Arrays.asList("Block : List<Stmt> statements", "Expression : Expr expression", Arrays.asList("Block : List<Stmt> statements", "Expression : Expr expression",
"Function : Token name, List<Token> params, List<Stmt> body", "Function : Token name, List<Token> params, List<Stmt> body",