Add function calls
This commit is contained in:
parent
922a8f6863
commit
4a71c219b5
5 changed files with 84 additions and 4 deletions
|
@ -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)
|
||||
|
|
|
@ -4,7 +4,23 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||
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<Object> arguments) {
|
||||
return (double)System.currentTimeMillis() / 1000.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return "<native fn>"; }
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLiteralExpr(Expr.Literal expr) {
|
||||
|
@ -105,7 +121,7 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
|||
stmt.accept(this);
|
||||
}
|
||||
|
||||
private void executeBlock(List<Stmt> statements, Environment environment) {
|
||||
public void executeBlock(List<Stmt> statements, Environment environment) {
|
||||
Environment previous = this.environment;
|
||||
|
||||
try {
|
||||
|
@ -131,6 +147,13 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
|||
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<Object>, Stmt.Visitor<Void> {
|
|||
|
||||
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);
|
||||
|
|
33
src/com/craftinginterpreters/lox/LoxFunction.java
Normal file
33
src/com/craftinginterpreters/lox/LoxFunction.java
Normal file
|
@ -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<Object> 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 "<fn " + declaration.name.lexeme + ">";
|
||||
}
|
||||
}
|
|
@ -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<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<>();
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ public class GenerateAst {
|
|||
"Unary : Token operator, Expr right", "Variable : Token name"));
|
||||
defineAst(outputDir, "Stmt",
|
||||
Arrays.asList("Block : List<Stmt> statements", "Expression : Expr expression",
|
||||
"Function : Token name, List<Token> params, List<Stmt> body",
|
||||
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
||||
"Var : Token name, Expr initializer", "While : Expr condition, Stmt body"));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue