fisl

fisl is scheme lox
git clone git://git.alexkarle.com.com/fisl
Log | Files | Refs | README | LICENSE

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:
Minterpreter.scm | 18+++++++++++++-----
Mparser.scm | 21+++++++++++++++++++++
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))