From 415557bdff9d34b562c8b8c17dbe6467a54420e5 Mon Sep 17 00:00:00 2001 From: Alex Karle Date: Fri, 18 Nov 2022 14:03:52 -0500 Subject: [PATCH] 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! --- examples/for.lox | 8 ++++++++ parser.scm | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 examples/for.lox diff --git a/examples/for.lox b/examples/for.lox new file mode 100644 index 0000000..91d3786 --- /dev/null +++ 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 index b33a4be..cdfc8d0 100644 --- 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)) -- libgit2 1.1.1