From 3d533c5a47739af341647b03d0e3ac9b6513fa8e Mon Sep 17 00:00:00 2001 From: Alex Karle Date: Fri, 18 Nov 2022 11:14:18 -0500 Subject: [PATCH] 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 --- interpreter.scm | 18 +++++++++++++----- parser.scm | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/interpreter.scm b/interpreter.scm index 8a50ee4..206abee 100644 --- 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 index dcc6b19..6381f6b 100644 --- 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)) -- libgit2 1.1.1