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:
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)))