3d533c5a47739af341647b03d0e3ac9b6513fa8e — Alex Karle 1 year, 5 months ago a11d38c
ch9.2: Implement if statements

Pretty cool to see this shake out :)

> var x = 3;
> if (x == 3) { print "woo"; } else { print "else"; }
2 files changed, 34 insertions(+), 5 deletions(-)

M interpreter.scm
M parser.scm
M interpreter.scm => interpreter.scm +13 -5
@@ 147,13 147,21 @@
	      (execute (car stmts) new-env)
	      (loop (cdr stmts)))))))
   ((if-stmt? stmt)
    (if (truthy? (evaluate (if-stmt-cond-expr stmt) env))
	(execute (if-stmt-then-stmt stmt) env)
	(if (not (null? (if-stmt-else-stmt stmt)))
	    (execute (if-stmt-else-stmt stmt) env)
   (else (runtime-err! (format "Unknown stmt ~A" stmt)))))

;; Save the global-env outside interpret so that it persists in the REPL
(define global-env (make-env #f))

(define (interpret stmts)
  (call/cc (lambda (cc)
	     (set! interpreter-abort cc)
	     (let ((global-env (make-env #f)))
	       (let loop ((sts stmts))
		 (if (not (null? sts))
		     (begin (execute (car sts) global-env)
			    (loop (cdr sts)))))))))
	     (let loop ((sts stmts))
	       (if (not (null? sts))
		   (begin (execute (car sts) global-env)
			  (loop (cdr sts))))))))

M parser.scm => parser.scm +21 -0
@@ 42,6 42,7 @@
(define-record expr-stmt value)
(define-record var-stmt name init)
(define-record block stmts)
(define-record if-stmt cond-expr then-stmt else-stmt)

(set-record-printer! print-stmt
  (lambda (x out)

@@ 59,6 60,12 @@
  (lambda (x out)
    (fprintf out "(block ~A)" (block-stmts x))))

(set-record-printer! if-stmt
  (lambda (x out)
    (fprintf out "(if ~A ~A ~A)"
      (if-stmt-cond-expr x)
      (if-stmt-then-stmt x)
      (if-stmt-else-stmt x))))

;; helper to check if first is of types

@@ 85,6 92,8 @@
(define (parse-statement tokens)
  (cond ((top-type? tokens '(PRINT))
	 (parse-print-statement (cdr tokens)))
	((top-type? tokens '(IF))
	 (parse-if-statement (cdr tokens)))
	((top-type? tokens '(LEFT_BRACE))
	 (let-values (((stmts toks) (parse-block (cdr tokens))))
	   ;; TODO: return the block record instead of stmts? Not the

@@ 119,6 128,18 @@
	      ;; but (loop) returns multiple values (sigh)
	      (loop (append stmts (list decl)) rest))))))

(define (parse-if-statement tokens)
  (if (not (top-type? tokens '(LEFT_PAREN)))
      (parse-err! tokens "Expected '(' after 'if'")
      (let-values (((cond-expr toks) (parse-expression '() (cdr tokens))))
	(if (not (top-type? toks '(RIGHT_PAREN)))
	    (parse-err! toks "Expected ')' after if condition")
	    (let-values (((then-stmt toks2) (parse-statement (cdr toks))))
	      (if (top-type? toks2 '(ELSE))
		  (let-values (((else-stmt toks3) (parse-statement (cdr toks2))))
		    (values (make-if-stmt cond-expr then-stmt else-stmt) toks3))
		  (values (make-if-stmt cond-expr then-stmt '()) toks2)))))))

(define (parse-assignment expr toks)
  (let-values (((e2 t2) (parse-equality expr toks)))
    (if (top-type? t2 '(EQUAL))