aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-01-20 22:52:47 -0800
committerGravatar Tom Willemse2021-01-20 22:52:47 -0800
commit922a8f68637f24fc447a8d687b75a676d3b310bb (patch)
tree881eccd352db8839dee5e0ef92e82af6e0dd5554
parent60b940f1f5b411053ee62d5cd5188fe62e8f9e58 (diff)
downloadcrafting-interpreters-922a8f68637f24fc447a8d687b75a676d3b310bb.tar.gz
crafting-interpreters-922a8f68637f24fc447a8d687b75a676d3b310bb.zip
Add function calling syntax
-rw-r--r--src/com/craftinginterpreters/lox/AstPrinter.java48
-rw-r--r--src/com/craftinginterpreters/lox/CMakeLists.txt1
-rw-r--r--src/com/craftinginterpreters/lox/Interpreter.java22
-rw-r--r--src/com/craftinginterpreters/lox/LoxCallable.java9
-rw-r--r--src/com/craftinginterpreters/lox/Parser.java40
-rw-r--r--src/com/craftinginterpreters/tool/GenerateAst.java6
6 files changed, 100 insertions, 26 deletions
diff --git a/src/com/craftinginterpreters/lox/AstPrinter.java b/src/com/craftinginterpreters/lox/AstPrinter.java
index 65f1916..4c120d3 100644
--- a/src/com/craftinginterpreters/lox/AstPrinter.java
+++ b/src/com/craftinginterpreters/lox/AstPrinter.java
@@ -11,13 +11,23 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
}
@Override
+ public String visitCallExpr(Expr.Call expr) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append(print(expr.callee));
+ builder.append(parenthesizeExpr("", expr.arguments));
+
+ return builder.toString();
+ }
+
+ @Override
public String visitBinaryExpr(Expr.Binary expr) {
- return parenthesize(expr.operator.lexeme, expr.left, expr.right);
+ return parenthesizeExpr(expr.operator.lexeme, expr.left, expr.right);
}
@Override
public String visitGroupingExpr(Expr.Grouping expr) {
- return parenthesize("group", expr.expression);
+ return parenthesizeExpr("group", expr.expression);
}
@Override
@@ -29,12 +39,12 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
@Override
public String visitLogicalExpr(Expr.Logical expr) {
- return parenthesize(expr.operator.type.toString(), expr.left, expr.right);
+ return parenthesizeExpr(expr.operator.type.toString(), expr.left, expr.right);
}
@Override
public String visitUnaryExpr(Expr.Unary expr) {
- return parenthesize(expr.operator.lexeme, expr.right);
+ return parenthesizeExpr(expr.operator.lexeme, expr.right);
}
@Override
@@ -44,12 +54,12 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
@Override
public String visitAssignExpr(Expr.Assign expression) {
- return parenthesize(expression.name.lexeme + " = ", expression.value);
+ return parenthesizeExpr(expression.name.lexeme + " = ", expression.value);
}
@Override
public String visitVarStmt(Stmt.Var statement) {
- return parenthesize("define " + statement.name.lexeme + " = ", statement.initializer);
+ return parenthesizeExpr("define " + statement.name.lexeme + " = ", statement.initializer);
}
@Override
@@ -57,8 +67,8 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
StringBuilder builder = new StringBuilder();
builder.append('(');
- builder.append(parenthesize("while", statement.condition));
- builder.append(parenthesize("do", statement.body));
+ builder.append(parenthesizeExpr("while", statement.condition));
+ builder.append(parenthesizeStmt("do", statement.body));
builder.append(')');
return builder.toString();
@@ -66,7 +76,7 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
@Override
public String visitPrintStmt(Stmt.Print statement) {
- return parenthesize("print", statement.expression);
+ return parenthesizeExpr("print", statement.expression);
}
@Override
@@ -79,21 +89,25 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
StringBuilder builder = new StringBuilder();
builder.append("(");
- builder.append(parenthesize("if", stmt.condition));
- builder.append(parenthesize("then", stmt.thenBranch));
+ builder.append(parenthesizeExpr("if", stmt.condition));
+ builder.append(parenthesizeStmt("then", stmt.thenBranch));
if (stmt.elseBranch != null) {
- builder.append(parenthesize("else", stmt.elseBranch));
+ builder.append(parenthesizeStmt("else", stmt.elseBranch));
}
return builder.toString();
}
@Override
public String visitBlockStmt(Stmt.Block block) {
- return parenthesize("", block.statements);
+ return parenthesizeStmt("", block.statements);
+ }
+
+ private String parenthesizeExpr(String name, Expr... exprs) {
+ return parenthesizeExpr(name, exprs);
}
- private String parenthesize(String name, Expr... exprs) {
+ private String parenthesizeExpr(String name, List<Expr> exprs) {
StringBuilder builder = new StringBuilder();
builder.append("(").append(name);
@@ -106,7 +120,7 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
return builder.toString();
}
- private String parenthesize(String name, List<Stmt> statements) {
+ private String parenthesizeStmt(String name, List<Stmt> statements) {
StringBuilder builder = new StringBuilder();
builder.append("(").append(name);
@@ -119,8 +133,8 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
return builder.toString();
}
- private String parenthesize(String name, Stmt... statements) {
- return parenthesize(name, statements);
+ private String parenthesizeStmt(String name, Stmt... statements) {
+ return parenthesizeStmt(name, statements);
}
public static void main(String[] args) {
diff --git a/src/com/craftinginterpreters/lox/CMakeLists.txt b/src/com/craftinginterpreters/lox/CMakeLists.txt
index 447b2cf..b437b7a 100644
--- a/src/com/craftinginterpreters/lox/CMakeLists.txt
+++ b/src/com/craftinginterpreters/lox/CMakeLists.txt
@@ -20,4 +20,5 @@ add_jar(Lox
Interpreter.java
RuntimeError.java
Environment.java
+ LoxCallable.java
ENTRY_POINT com/craftinginterpreters/lox/Lox)
diff --git a/src/com/craftinginterpreters/lox/Interpreter.java b/src/com/craftinginterpreters/lox/Interpreter.java
index 9d0cfb3..f752e77 100644
--- a/src/com/craftinginterpreters/lox/Interpreter.java
+++ b/src/com/craftinginterpreters/lox/Interpreter.java
@@ -1,5 +1,6 @@
package com.craftinginterpreters.lox;
+import java.util.ArrayList;
import java.util.List;
class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
@@ -222,6 +223,27 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
return null;
}
+ @Override
+ public Object visitCallExpr(Expr.Call expr) {
+ Object callee = evaluate(expr.callee);
+
+ List<Object> arguments = new ArrayList<>();
+ for (Expr argument : expr.arguments) {
+ arguments.add(evaluate(argument));
+ }
+
+ if (!(callee instanceof LoxCallable)) {
+ throw new RuntimeError(expr.paren, "Can only call functions and classes.");
+ }
+
+ LoxCallable function = (LoxCallable) callee;
+ if (arguments.size() != function.arity()) {
+ throw new RuntimeError(expr.paren, "Expected " + function.arity() + " arguments but got " + arguments.size() + ".");
+ }
+
+ return function.call(this, arguments);
+ }
+
public void interpret(List<Stmt> statements) {
try {
for (Stmt statement : statements) {
diff --git a/src/com/craftinginterpreters/lox/LoxCallable.java b/src/com/craftinginterpreters/lox/LoxCallable.java
new file mode 100644
index 0000000..4204c20
--- /dev/null
+++ b/src/com/craftinginterpreters/lox/LoxCallable.java
@@ -0,0 +1,9 @@
+package com.craftinginterpreters.lox;
+
+import java.util.List;
+
+interface LoxCallable {
+ int arity();
+
+ Object call(Interpreter interpreter, List<Object> arguments);
+}
diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java
index 7d7b27a..df3ce3f 100644
--- a/src/com/craftinginterpreters/lox/Parser.java
+++ b/src/com/craftinginterpreters/lox/Parser.java
@@ -84,13 +84,11 @@ class Parser {
Stmt body = statement();
if (increment != null) {
- body = new Stmt.Block(
- Arrays.asList(
- body,
- new Stmt.Expression(increment)));
+ body = new Stmt.Block(Arrays.asList(body, new Stmt.Expression(increment)));
}
- if (condition == null) condition = new Expr.Literal(true);
+ if (condition == null)
+ condition = new Expr.Literal(true);
body = new Stmt.While(condition, body);
if (initializer != null) {
@@ -255,7 +253,37 @@ class Parser {
return new Expr.Unary(operator, right);
}
- return primary();
+ return call();
+ }
+
+ private Expr finishCall(Expr callee) {
+ List<Expr> arguments = new ArrayList<>();
+ if (!check(RIGHT_PAREN)) {
+ do {
+ if (arguments.size() >= 255) {
+ error(peek(), "Can't have more than 255 arguments.");
+ }
+ arguments.add(expression());
+ } while (match(COMMA));
+ }
+
+ Token paren = consume(RIGHT_PAREN, "Expect ')' after arguments.");
+
+ return new Expr.Call(callee, paren, arguments);
+ }
+
+ private Expr call() {
+ Expr expr = primary();
+
+ while (true) {
+ if (match(LEFT_PAREN)) {
+ expr = finishCall(expr);
+ } else {
+ break;
+ }
+ }
+
+ return expr;
}
private Expr primary() {
diff --git a/src/com/craftinginterpreters/tool/GenerateAst.java b/src/com/craftinginterpreters/tool/GenerateAst.java
index 8845c6e..8c063bf 100644
--- a/src/com/craftinginterpreters/tool/GenerateAst.java
+++ b/src/com/craftinginterpreters/tool/GenerateAst.java
@@ -16,9 +16,9 @@ public class GenerateAst {
defineAst(outputDir, "Expr",
Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right",
- "Grouping : Expr expression", "Literal : Object value",
- "Logical : Expr left, Token operator, Expr right", "Unary : Token operator, Expr right",
- "Variable : Token name"));
+ "Call : Expr callee, Token paren, List<Expr> arguments", "Grouping : Expr expression",
+ "Literal : Object value", "Logical : Expr left, Token operator, Expr right",
+ "Unary : Token operator, Expr right", "Variable : Token name"));
defineAst(outputDir, "Stmt",
Arrays.asList("Block : List<Stmt> statements", "Expression : Expr expression",
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",