aboutsummaryrefslogtreecommitdiffstats
path: root/clox/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'clox/src/compiler.c')
-rw-r--r--clox/src/compiler.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index beda5d5..aed21f7 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -288,6 +288,51 @@ static void expressionStatement() {
emitByte(OP_POP);
}
+static void forStatement() {
+ beginScope();
+ consume(TOKEN_LEFT_PAREN, "Expect '(' after 'for'.");
+ if (match(TOKEN_SEMICOLON)) {
+ // No initializer
+ } else if (match(TOKEN_VAR)) {
+ varDeclaration();
+ } else {
+ expressionStatement();
+ }
+
+ int loopStart = currentChunk()->count;
+ int exitJump = -1;
+ if (!match(TOKEN_SEMICOLON)) {
+ expression();
+ consume(TOKEN_SEMICOLON, "Expect ';' after loop condition.");
+
+ // Jump out of the loop if the condition is false.
+ exitJump = emitJump(OP_JUMP_IF_FALSE);
+ emitByte(OP_POP); /* Condition. */
+ }
+
+ if (!match(TOKEN_RIGHT_PAREN)) {
+ int bodyJump = emitJump(OP_JUMP);
+ int incrementStart = currentChunk()->count;
+ expression();
+ emitByte(OP_POP);
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after for clauses.");
+
+ emitLoop(loopStart);
+ loopStart = incrementStart;
+ patchJump(bodyJump);
+ }
+
+ statement();
+ emitLoop(loopStart);
+
+ if (exitJump != -1) {
+ patchJump(exitJump);
+ emitByte(OP_POP); /* Condition. */
+ }
+
+ endScope();
+}
+
static void ifStatement() {
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
expression();
@@ -366,6 +411,8 @@ static void declaration() {
static void statement() {
if (match(TOKEN_PRINT)) {
printStatement();
+ } else if (match(TOKEN_FOR)) {
+ forStatement();
} else if (match(TOKEN_IF)) {
ifStatement();
} else if (match(TOKEN_WHILE)) {