Add function calling syntax
This commit is contained in:
parent
60b940f1f5
commit
922a8f6863
6 changed files with 100 additions and 26 deletions
|
@ -10,14 +10,24 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
|||
return expr.accept(this);
|
||||
}
|
||||
|
||||
@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 parenthesize(String name, Expr... exprs) {
|
||||
private String parenthesizeExpr(String name, Expr... exprs) {
|
||||
return parenthesizeExpr(name, 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) {
|
||||
|
|
|
@ -20,4 +20,5 @@ add_jar(Lox
|
|||
Interpreter.java
|
||||
RuntimeError.java
|
||||
Environment.java
|
||||
LoxCallable.java
|
||||
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
||||
|
|
|
@ -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) {
|
||||
|
|
9
src/com/craftinginterpreters/lox/LoxCallable.java
Normal file
9
src/com/craftinginterpreters/lox/LoxCallable.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
package com.craftinginterpreters.lox;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface LoxCallable {
|
||||
int arity();
|
||||
|
||||
Object call(Interpreter interpreter, List<Object> arguments);
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue