diff --git a/src/com/craftinginterpreters/lox/AstPrinter.java b/src/com/craftinginterpreters/lox/AstPrinter.java index 8f7be78..65f1916 100644 --- a/src/com/craftinginterpreters/lox/AstPrinter.java +++ b/src/com/craftinginterpreters/lox/AstPrinter.java @@ -52,6 +52,18 @@ class AstPrinter implements Expr.Visitor, Stmt.Visitor { return parenthesize("define " + statement.name.lexeme + " = ", statement.initializer); } + @Override + public String visitWhileStmt(Stmt.While statement) { + StringBuilder builder = new StringBuilder(); + + builder.append('('); + builder.append(parenthesize("while", statement.condition)); + builder.append(parenthesize("do", statement.body)); + builder.append(')'); + + return builder.toString(); + } + @Override public String visitPrintStmt(Stmt.Print statement) { return parenthesize("print", statement.expression); diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java index a85d70f..7d7b27a 100644 --- a/src/com/craftinginterpreters/lox/Parser.java +++ b/src/com/craftinginterpreters/lox/Parser.java @@ -4,6 +4,7 @@ import static com.craftinginterpreters.lox.TokenType.*; import java.util.ArrayList; import java.util.List; +import java.util.Arrays; class Parser { private static class ParseError extends RuntimeException { @@ -43,6 +44,8 @@ class Parser { } private Stmt statement() { + if (match(FOR)) + return forStatement(); if (match(IF)) return ifStatement(); if (match(PRINT)) @@ -55,6 +58,48 @@ class Parser { return expressionStatement(); } + private Stmt forStatement() { + consume(LEFT_PAREN, "Expect '(' after 'for'."); + + Stmt initializer; + if (match(SEMICOLON)) { + initializer = null; + } else if (match(VAR)) { + initializer = varDeclaration(); + } else { + initializer = expressionStatement(); + } + + Expr condition = null; + if (!check(SEMICOLON)) { + condition = expression(); + } + consume(SEMICOLON, "Expect ';' after loop condition."); + + Expr increment = null; + if (!check(RIGHT_PAREN)) { + increment = expression(); + } + consume(RIGHT_PAREN, "Expect ')' after for clauses."); + Stmt body = statement(); + + if (increment != null) { + body = new Stmt.Block( + Arrays.asList( + body, + new Stmt.Expression(increment))); + } + + if (condition == null) condition = new Expr.Literal(true); + body = new Stmt.While(condition, body); + + if (initializer != null) { + body = new Stmt.Block(Arrays.asList(initializer, body)); + } + + return body; + } + private Stmt ifStatement() { consume(LEFT_PAREN, "Expect '(' after 'if'."); Expr condition = expression();