commit 415557bdff9d34b562c8b8c17dbe6467a54420e5 (patch)
parent cf77b879d8cbf5bd345a8c40d197dd9f8708c9fb
Author: Alex Karle <alex@alexkarle.com>
Date: Fri, 18 Nov 2022 14:03:52 -0500
ch9.5: Implement an ugly version of for-loops
I realized knee deep into the desugaring that these cascading 'let's
should just be function composition... I'll refactor in a subsequent
commit. For now I need to go for a jog!
Diffstat:
2 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/examples/for.lox b/examples/for.lox
@@ -0,0 +1,8 @@
+var a = 0;
+var temp;
+
+for (var b = 1; a < 10000; b = temp + b) {
+ print a;
+ temp = a;
+ a = b;
+}
diff --git a/parser.scm b/parser.scm
@@ -102,6 +102,8 @@
(define (parse-statement tokens)
(cond ((top-type? tokens '(PRINT))
(parse-print-statement (cdr tokens)))
+ ((top-type? tokens '(FOR))
+ (parse-for-statement (cdr tokens)))
((top-type? tokens '(IF))
(parse-if-statement (cdr tokens)))
((top-type? tokens '(WHILE))
@@ -120,6 +122,7 @@
(values (maker expr) (cdr toks))
(if in-repl
(values (maker expr) toks)
+ ;; TODO: this might break for-loop parsing in the repl?
(parse-err! toks "expected ;")))))
(define (parse-print-statement tokens)
@@ -137,6 +140,45 @@
(let-values (((body-stmt toks2) (parse-statement (cdr toks))))
(values (make-while-stmt cond-expr body-stmt) toks2))))))
+(define (parse-for-statement tokens)
+ ;; TODO: how do we simplify this many parse-err! asserts / parse passes?
+ (if (not (top-type? tokens '(LEFT_PAREN)))
+ (parse-err! tokens "Expected '(' after 'for'")
+ (let-values (((init toks)
+ (cond ((top-type? (cdr tokens) '(SEMICOLON))
+ (values '() (cddr tokens)))
+ ((top-type? (cdr tokens) '(VAR))
+ (parse-var-decl (cddr tokens)))
+ (else (parse-expression-statement (cdr tokens))))))
+ (let-values (((conde toks2)
+ (cond ((top-type? toks '(SEMICOLON))
+ (values '() toks))
+ (else (parse-expression '() toks)))))
+ (if (not (top-type? toks2 '(SEMICOLON)))
+ (parse-err! toks2 "Expected ';' after loop condition")
+ (let-values (((incr toks3)
+ (cond ((top-type? (cdr toks2) '(RIGHT_PAREN))
+ (values '() (cdr toks2)))
+ (else (parse-expression '() (cdr toks2))))))
+ (if (not (top-type? toks3 '(RIGHT_PAREN)))
+ (parse-err! toks3 "Expected ')' after for clauses")
+ (let-values (((body toks4) (parse-statement (cdr toks3))))
+ ;; TODO: refactor. I seem to like to "transform" variables
+ ;; by just repeatedly let-binding new versions instead of
+ ;; using set! --> maybe use composed functions?
+ (let ((incr-body
+ (if (null? incr)
+ body
+ (make-block (list body (make-expr-stmt incr))))))
+ (let ((cond-body
+ (if (null? conde)
+ (make-while-stmt (make-literal #t) incr-body)
+ (make-while-stmt conde incr-body))))
+ (if (null? init)
+ (values cond-body toks4)
+ (values (make-block (list init cond-body)) toks4))))))))))))
+
+
(define (parse-block tokens)
(let loop ((stmts '()) (toks tokens))
(if (top-type? toks '(RIGHT_BRACE))