|
|
@@ -5,6 +5,7 @@ package com.craftinginterpreters.lox;
|
|
|
import static com.craftinginterpreters.lox.TokenType.*;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
import java.util.List;
|
|
|
|
|
|
/**
|
|
|
@@ -53,8 +54,9 @@ public class Parser {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // statement → exprStmt | ifStmt | printStmt | whileStmt | block;
|
|
|
+ // statement → exprStmt | forStmt | ifStmt | printStmt | whileStmt | block;
|
|
|
private Stmt statement() {
|
|
|
+ if (match(FOR)) return forStatement();
|
|
|
if (match(IF)) return ifStatement();
|
|
|
if (match(PRINT)) return printStatement();
|
|
|
if (match(WHILE)) return whileStatement();
|
|
|
@@ -62,6 +64,46 @@ public class Parser {
|
|
|
return expressionStatement();
|
|
|
}
|
|
|
|
|
|
+ private Stmt forStatement() {
|
|
|
+ consume(LEFT_PARAM, "Expect '(' after 'for'.");
|
|
|
+
|
|
|
+ Stmt initializer;
|
|
|
+ if (match(SEMICOLON)) {
|
|
|
+ initializer = null;
|
|
|
+ } else if (match(VAR)) {
|
|
|
+ initializer = varDecl();
|
|
|
+ } else {
|
|
|
+ initializer = expressionStatement();
|
|
|
+ }
|
|
|
+
|
|
|
+ Expr condition = null;
|
|
|
+ if (!check(SEMICOLON)) {
|
|
|
+ condition = expression();
|
|
|
+ }
|
|
|
+ consume(SEMICOLON, "Expect ';' after loop condition.");
|
|
|
+
|
|
|
+ Expr increment = null;
|
|
|
+ if (!check(SEMICOLON)) {
|
|
|
+ increment = expression();
|
|
|
+ }
|
|
|
+ consume(RIGHT_PARAM, "Expect ')' after for clauses.");
|
|
|
+
|
|
|
+ Stmt body = statement();
|
|
|
+
|
|
|
+ // desugaring
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
// whileStmt → "while" "(" expression ")" statement ;
|
|
|
private Stmt whileStatement() {
|
|
|
consume(LEFT_PARAM, "Expect '(' after 'while'.");
|