[jlox] Add for loops (using syntactic sugar!)
This commit is contained in:
@@ -15,11 +15,15 @@ import static xyz.ctsk.lox.TokenType.*;
|
|||||||
* | statement ;
|
* | statement ;
|
||||||
* varDecl → "var" IDENTIFIER ( "=" expression )? ";" ;
|
* varDecl → "var" IDENTIFIER ( "=" expression )? ";" ;
|
||||||
* statement → exprStmt
|
* statement → exprStmt
|
||||||
|
* | forStmt
|
||||||
* | ifStmt
|
* | ifStmt
|
||||||
* | printStmt
|
* | printStmt
|
||||||
* | whileStmt
|
* | whileStmt
|
||||||
* | block ;
|
* | block ;
|
||||||
* block → "{" declaration* "}" ;
|
* block → "{" declaration* "}" ;
|
||||||
|
* forStmt → "for" "(" (varDecl | exprStmt | ";")
|
||||||
|
* expression? ";"
|
||||||
|
* expression? ")" statement ;
|
||||||
* ifStmt → "if" "(" expression ")" statement ( "else" statement )? ;
|
* ifStmt → "if" "(" expression ")" statement ( "else" statement )? ;
|
||||||
* whileStmt → "while" "(" expression ")" statement ;
|
* whileStmt → "while" "(" expression ")" statement ;
|
||||||
* printStmt → "print" expression ";" ;
|
* printStmt → "print" expression ";" ;
|
||||||
@@ -82,6 +86,7 @@ public class Parser {
|
|||||||
|
|
||||||
|
|
||||||
private Stmt statement() {
|
private Stmt statement() {
|
||||||
|
if (match(FOR)) return forStatement();
|
||||||
if (match(IF)) return ifStatement();
|
if (match(IF)) return ifStatement();
|
||||||
if (match(PRINT)) return printStatement();
|
if (match(PRINT)) return printStatement();
|
||||||
if (match(WHILE)) return whileStatement();
|
if (match(WHILE)) return whileStatement();
|
||||||
@@ -89,6 +94,42 @@ public class Parser {
|
|||||||
return expressionStatement();
|
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 = check(SEMICOLON) ? null : expression();
|
||||||
|
consume(SEMICOLON, "Expect ';' after loop condition.");
|
||||||
|
|
||||||
|
Expr increment = check(RIGHT_PAREN) ? null : expression();
|
||||||
|
consume(RIGHT_PAREN, "Expect ')' after for clauses.");
|
||||||
|
|
||||||
|
Stmt body = statement();
|
||||||
|
|
||||||
|
if (increment != null) {
|
||||||
|
body = new Stmt.Block(List.of(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(List.of(initializer, body));
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Stmt ifStatement() {
|
private Stmt ifStatement() {
|
||||||
consume(LEFT_PAREN, "Expect '(' after 'if'.");
|
consume(LEFT_PAREN, "Expect '(' after 'if'.");
|
||||||
|
|||||||
Reference in New Issue
Block a user