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
|
Token.java
|
||||||
Scanner.java
|
Scanner.java
|
||||||
${GENERATED_JAVA_FILENAMES}
|
${GENERATED_JAVA_FILENAMES}
|
||||||
AstPrinter.java
|
|
||||||
Parser.java
|
Parser.java
|
||||||
Interpreter.java
|
Interpreter.java
|
||||||
RuntimeError.java
|
RuntimeError.java
|
||||||
Environment.java
|
Environment.java
|
||||||
LoxCallable.java
|
LoxCallable.java
|
||||||
|
LoxFunction.java
|
||||||
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
||||||
|
|
|
@ -4,7 +4,23 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
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
|
@Override
|
||||||
public Object visitLiteralExpr(Expr.Literal expr) {
|
public Object visitLiteralExpr(Expr.Literal expr) {
|
||||||
|
@ -105,7 +121,7 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
stmt.accept(this);
|
stmt.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeBlock(List<Stmt> statements, Environment environment) {
|
public void executeBlock(List<Stmt> statements, Environment environment) {
|
||||||
Environment previous = this.environment;
|
Environment previous = this.environment;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -131,6 +147,13 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitFunctionStmt(Stmt.Function stmt) {
|
||||||
|
LoxFunction function = new LoxFunction(stmt);
|
||||||
|
environment.define(stmt.name.lexeme, function);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitIfStmt(Stmt.If stmt) {
|
public Void visitIfStmt(Stmt.If stmt) {
|
||||||
if (isTruthy(evaluate(stmt.condition))) {
|
if (isTruthy(evaluate(stmt.condition))) {
|
||||||
|
@ -238,7 +261,8 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
|
|
||||||
LoxCallable function = (LoxCallable) callee;
|
LoxCallable function = (LoxCallable) callee;
|
||||||
if (arguments.size() != function.arity()) {
|
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);
|
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() {
|
private Stmt declaration() {
|
||||||
try {
|
try {
|
||||||
|
if (match(FUN))
|
||||||
|
return function("function");
|
||||||
if (match(VAR))
|
if (match(VAR))
|
||||||
return varDeclaration();
|
return varDeclaration();
|
||||||
|
|
||||||
|
@ -145,6 +147,26 @@ class Parser {
|
||||||
return new Stmt.Expression(expr);
|
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() {
|
private List<Stmt> block() {
|
||||||
List<Stmt> statements = new ArrayList<>();
|
List<Stmt> statements = new ArrayList<>();
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class GenerateAst {
|
||||||
"Unary : Token operator, Expr right", "Variable : Token name"));
|
"Unary : Token operator, Expr right", "Variable : Token name"));
|
||||||
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",
|
||||||
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
||||||
"Var : Token name, Expr initializer", "While : Expr condition, Stmt body"));
|
"Var : Token name, Expr initializer", "While : Expr condition, Stmt body"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue