From c62b73a2477b9fa625285e9c2ca1e51c2bcb8024 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Thu, 14 Jan 2021 23:53:47 -0800 Subject: [PATCH] Add branching primitives --- .../craftinginterpreters/lox/AstPrinter.java | 23 ++++++++++ .../craftinginterpreters/lox/Interpreter.java | 24 +++++++++++ src/com/craftinginterpreters/lox/Parser.java | 42 ++++++++++++++++++- .../tool/GenerateAst.java | 9 ++-- 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/com/craftinginterpreters/lox/AstPrinter.java b/src/com/craftinginterpreters/lox/AstPrinter.java index d5163df..8f7be78 100644 --- a/src/com/craftinginterpreters/lox/AstPrinter.java +++ b/src/com/craftinginterpreters/lox/AstPrinter.java @@ -27,6 +27,11 @@ class AstPrinter implements Expr.Visitor, Stmt.Visitor { return expr.value.toString(); } + @Override + public String visitLogicalExpr(Expr.Logical expr) { + return parenthesize(expr.operator.type.toString(), expr.left, expr.right); + } + @Override public String visitUnaryExpr(Expr.Unary expr) { return parenthesize(expr.operator.lexeme, expr.right); @@ -57,6 +62,20 @@ class AstPrinter implements Expr.Visitor, Stmt.Visitor { return expression.expression.accept(this); } + @Override + public String visitIfStmt(Stmt.If stmt) { + StringBuilder builder = new StringBuilder(); + + builder.append("("); + builder.append(parenthesize("if", stmt.condition)); + builder.append(parenthesize("then", stmt.thenBranch)); + + if (stmt.elseBranch != null) { + builder.append(parenthesize("else", stmt.elseBranch)); + } + return builder.toString(); + } + @Override public String visitBlockStmt(Stmt.Block block) { return parenthesize("", block.statements); @@ -88,6 +107,10 @@ class AstPrinter implements Expr.Visitor, Stmt.Visitor { return builder.toString(); } + private String parenthesize(String name, Stmt... statements) { + return parenthesize(name, statements); + } + public static void main(String[] args) { Expr expression = new Expr.Binary( new Expr.Unary(new Token(TokenType.MINUS, "-", null, 1), new Expr.Literal(123)), diff --git a/src/com/craftinginterpreters/lox/Interpreter.java b/src/com/craftinginterpreters/lox/Interpreter.java index e03ca37..6c32233 100644 --- a/src/com/craftinginterpreters/lox/Interpreter.java +++ b/src/com/craftinginterpreters/lox/Interpreter.java @@ -10,6 +10,19 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { return expr.value; } + @Override + public Object visitLogicalExpr(Expr.Logical expr) { + Object left = evaluate(expr.left); + + if (expr.operator.type == TokenType.OR) { + if (isTruthy(left)) return left; + } else { + if (!isTruthy(left)) return left; + } + + return evaluate(expr.right); + } + @Override public Object visitUnaryExpr(Expr.Unary expr) { Object right = evaluate(expr.right); @@ -115,6 +128,17 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { return null; } + @Override + public Void visitIfStmt(Stmt.If stmt) { + if (isTruthy(evaluate(stmt.condition))) { + execute(stmt.thenBranch); + } else if (stmt.elseBranch != null) { + execute(stmt.elseBranch); + } + + return null; + } + @Override public Void visitPrintStmt(Stmt.Print stmt) { Object value = evaluate(stmt.expression); diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java index f044feb..1643129 100644 --- a/src/com/craftinginterpreters/lox/Parser.java +++ b/src/com/craftinginterpreters/lox/Parser.java @@ -43,6 +43,8 @@ class Parser { } private Stmt statement() { + if (match(IF)) + return ifStatement(); if (match(PRINT)) return printStatement(); if (match(LEFT_BRACE)) @@ -51,6 +53,20 @@ class Parser { return expressionStatement(); } + private Stmt ifStatement() { + consume(LEFT_PAREN, "Expect '(' after 'if'."); + Expr condition = expression(); + consume(RIGHT_PAREN, "Expect ')' after if condition."); + + Stmt thenBranch = statement(); + Stmt elseBranch = null; + if (match(ELSE)) { + elseBranch = statement(); + } + + return new Stmt.If(condition, thenBranch, elseBranch); + } + private Stmt printStatement() { Expr value = expression(); consume(SEMICOLON, "Expect ';' after value."); @@ -87,7 +103,7 @@ class Parser { } private Expr assignment() { - Expr expr = equality(); + Expr expr = or(); if (match(EQUAL)) { Token equals = previous(); @@ -104,6 +120,30 @@ class Parser { return expr; } + private Expr or() { + Expr expr = and(); + + while (match(OR)) { + Token operator = previous(); + Expr right = and(); + expr = new Expr.Logical(expr, operator, right); + } + + return expr; + } + + private Expr and() { + Expr expr = equality(); + + while (match(AND)) { + Token operator = previous(); + Expr right = equality(); + expr = new Expr.Logical(expr, operator, right); + } + + return expr; + } + private Expr equality() { Expr expr = comparison(); diff --git a/src/com/craftinginterpreters/tool/GenerateAst.java b/src/com/craftinginterpreters/tool/GenerateAst.java index c9f1398..a3935e1 100644 --- a/src/com/craftinginterpreters/tool/GenerateAst.java +++ b/src/com/craftinginterpreters/tool/GenerateAst.java @@ -16,10 +16,13 @@ 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", "Unary : 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")); - defineAst(outputDir, "Stmt", Arrays.asList("Block : List statements", "Expression : Expr expression", - "Print : Expr expression", "Var : Token name, Expr initializer")); + defineAst(outputDir, "Stmt", + Arrays.asList("Block : List statements", "Expression : Expr expression", + "If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression", + "Var : Token name, Expr initializer")); } private static void defineAst(String outputDir, String baseName, List types) throws IOException {