fisl

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

commit 5ff7353e5f4508d427c30baee6233140b5c71a7a (patch)
parent e98c287ec33108ff0904f5391fc3de4ed9f1d948
Author: Alex Karle <alex@alexkarle.com>
Date:   Fri, 18 Nov 2022 12:08:59 -0500

assignment: Fix assignment vs definition bug

I had intermingled assignment and definition such that

var x = 5;

and

x = 5;

did the same thing, when really the first should create a new binding
in the current environment and the second should update the value in
*whichever environment has x defined (the closest one)*.

This was found while implementing 'while' since the following was an
infinite loop:

var x = 10;
while (x > 0) {
    print x;
    x = x - 1;
}

With the splitting of var -> env-def! and = -> env-set! in this patch,
it works as expected!

Diffstat:
Minterpreter.scm | 15+++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/interpreter.scm b/interpreter.scm @@ -15,9 +15,17 @@ (if parent (env-get parent el) (runtime-err! (format "Unbound variable ~A" el)))))) - ((eq? action 'set) + ((eq? action 'def) + ;; var block, sets in current env (lambda (el val) (hash-table-set! ht el val))) + ((eq? action 'set) + (lambda (el val) + (if (hash-table-exists? ht el) + (hash-table-set! ht el val) + (if parent + (env-set! parent el val) + (runtime-err! (format "Unable to set unbound variable ~A" el)))))) ((eq? action 'exists) (lambda (el) (if (hash-table-exists? ht el) @@ -31,6 +39,9 @@ (define (env-set! env key val) ((env 'set) key val)) +(define (env-def! env key val) + ((env 'def) key val)) + (define (env-exists? env key) ((env 'exists) key)) @@ -145,7 +156,7 @@ (if (null? (var-stmt-init stmt)) '() (evaluate (var-stmt-init stmt) env)))) - (env-set! env (token-lexeme (var-stmt-name stmt)) value)) + (env-def! env (token-lexeme (var-stmt-name stmt)) value)) '()) ((expr-stmt? stmt) (let ((res (evaluate (expr-stmt-value stmt) env)))