[jlox] Add for loops (using syntactic sugar!)

This commit is contained in:
ctsk
2022-09-10 11:46:18 +02:00
parent a4c1076008
commit a516090b4f

View File

@@ -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'.");