commit 3d533c5a47739af341647b03d0e3ac9b6513fa8e (patch)
parent a11d38c70322ff1e99e783a4e7a776bb80b8b56f
Author: Alex Karle <alex@alexkarle.com>
Date: Fri, 18 Nov 2022 11:14:18 -0500
ch9.2: Implement if statements
Pretty cool to see this shake out :)
> var x = 3;
3
> if (x == 3) { print "woo"; } else { print "else"; }
woo
Diffstat:
2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/interpreter.scm b/interpreter.scm
@@ -147,13 +147,21 @@
(begin
(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))))))))
diff --git a/parser.scm b/parser.scm
@@ -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))