415557bdff9d34b562c8b8c17dbe6467a54420e5 — Alex Karle 1 year, 5 months ago cf77b87
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!
2 files changed, 50 insertions(+), 0 deletions(-)

A examples/for.lox
M parser.scm
A examples/for.lox => examples/for.lox +8 -0
@@ 0,0 1,8 @@
var a = 0;
var temp;

for (var b = 1; a < 10000; b = temp + b) {
  print a;
  temp = a;
  a = b;

M parser.scm => parser.scm +42 -0
@@ 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)
				 (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))