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);
|
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
|
@Override
|
||||||
public String visitBinaryExpr(Expr.Binary expr) {
|
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
|
@Override
|
||||||
public String visitGroupingExpr(Expr.Grouping expr) {
|
public String visitGroupingExpr(Expr.Grouping expr) {
|
||||||
return parenthesize("group", expr.expression);
|
return parenthesizeExpr("group", expr.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,12 +39,12 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitLogicalExpr(Expr.Logical expr) {
|
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
|
@Override
|
||||||
public String visitUnaryExpr(Expr.Unary expr) {
|
public String visitUnaryExpr(Expr.Unary expr) {
|
||||||
return parenthesize(expr.operator.lexeme, expr.right);
|
return parenthesizeExpr(expr.operator.lexeme, expr.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,12 +54,12 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitAssignExpr(Expr.Assign expression) {
|
public String visitAssignExpr(Expr.Assign expression) {
|
||||||
return parenthesize(expression.name.lexeme + " = ", expression.value);
|
return parenthesizeExpr(expression.name.lexeme + " = ", expression.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitVarStmt(Stmt.Var statement) {
|
public String visitVarStmt(Stmt.Var statement) {
|
||||||
return parenthesize("define " + statement.name.lexeme + " = ", statement.initializer);
|
return parenthesizeExpr("define " + statement.name.lexeme + " = ", statement.initializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,8 +67,8 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
builder.append('(');
|
builder.append('(');
|
||||||
builder.append(parenthesize("while", statement.condition));
|
builder.append(parenthesizeExpr("while", statement.condition));
|
||||||
builder.append(parenthesize("do", statement.body));
|
builder.append(parenthesizeStmt("do", statement.body));
|
||||||
builder.append(')');
|
builder.append(')');
|
||||||
|
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
@ -66,7 +76,7 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitPrintStmt(Stmt.Print statement) {
|
public String visitPrintStmt(Stmt.Print statement) {
|
||||||
return parenthesize("print", statement.expression);
|
return parenthesizeExpr("print", statement.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,21 +89,25 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
builder.append("(");
|
builder.append("(");
|
||||||
builder.append(parenthesize("if", stmt.condition));
|
builder.append(parenthesizeExpr("if", stmt.condition));
|
||||||
builder.append(parenthesize("then", stmt.thenBranch));
|
builder.append(parenthesizeStmt("then", stmt.thenBranch));
|
||||||
|
|
||||||
if (stmt.elseBranch != null) {
|
if (stmt.elseBranch != null) {
|
||||||
builder.append(parenthesize("else", stmt.elseBranch));
|
builder.append(parenthesizeStmt("else", stmt.elseBranch));
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitBlockStmt(Stmt.Block block) {
|
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();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
builder.append("(").append(name);
|
builder.append("(").append(name);
|
||||||
|
@ -106,7 +120,7 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parenthesize(String name, List<Stmt> statements) {
|
private String parenthesizeStmt(String name, List<Stmt> statements) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
builder.append("(").append(name);
|
builder.append("(").append(name);
|
||||||
|
@ -119,8 +133,8 @@ class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parenthesize(String name, Stmt... statements) {
|
private String parenthesizeStmt(String name, Stmt... statements) {
|
||||||
return parenthesize(name, statements);
|
return parenthesizeStmt(name, statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
@ -20,4 +20,5 @@ add_jar(Lox
|
||||||
Interpreter.java
|
Interpreter.java
|
||||||
RuntimeError.java
|
RuntimeError.java
|
||||||
Environment.java
|
Environment.java
|
||||||
|
LoxCallable.java
|
||||||
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.craftinginterpreters.lox;
|
package com.craftinginterpreters.lox;
|
||||||
|
|
||||||
|
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> {
|
||||||
|
@ -222,6 +223,27 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return null;
|
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) {
|
public void interpret(List<Stmt> statements) {
|
||||||
try {
|
try {
|
||||||
for (Stmt statement : statements) {
|
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();
|
Stmt body = statement();
|
||||||
|
|
||||||
if (increment != null) {
|
if (increment != null) {
|
||||||
body = new Stmt.Block(
|
body = new Stmt.Block(Arrays.asList(body, new Stmt.Expression(increment)));
|
||||||
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);
|
body = new Stmt.While(condition, body);
|
||||||
|
|
||||||
if (initializer != null) {
|
if (initializer != null) {
|
||||||
|
@ -255,7 +253,37 @@ class Parser {
|
||||||
return new Expr.Unary(operator, right);
|
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() {
|
private Expr primary() {
|
||||||
|
|
|
@ -16,9 +16,9 @@ public class GenerateAst {
|
||||||
|
|
||||||
defineAst(outputDir, "Expr",
|
defineAst(outputDir, "Expr",
|
||||||
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",
|
||||||
"Grouping : Expr expression", "Literal : Object value",
|
"Call : Expr callee, Token paren, List<Expr> arguments", "Grouping : Expr expression",
|
||||||
"Logical : Expr left, Token operator, Expr right", "Unary : Token operator, Expr right",
|
"Literal : Object value", "Logical : Expr left, 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",
|
||||||
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
||||||
|
|
Loading…
Reference in a new issue