Step 10c: bind CEK special form + provide-set frame + scope-stack integration

bind is now a CEK special form that captures its body unevaluated,
establishes a tracking context (*bind-tracking*), and registers
subscribers on provide frames when context reads are tracked.

- bind special form: step-sf-bind, make-bind-frame, bind continue handler
- provide-set frame: provide! evaluates value with kont (fixes peek bug)
- context tracking: step-sf-context appends to *bind-tracking* when active
- scope-stack fallback: provide pushes to scope stack for cek-call contexts
- CekFrame mutation: cf_remaining/cf_results/cf_extra2 now mutable
- Transpiler: subscribers + prev-tracking field mappings, *bind-tracking* in ml-mutable-globals
- Test fixes: string-append → str, restored edge-cases suite

Passing: bind returns initial value, bind with expression, bind with let,
bind no deps is static, bind with conditional deps, provide! updates/multiple/nil,
provide! computed new value, peek read-modify-write, guard inside bind,
bind with string-append, provide! same value does not notify, bind does not
fire on unrelated provide!, bind sees latest value, bind inside provide scope.

Remaining: subscriber re-evaluation on provide! (scope-stack key issue),
batch coalescing (no batch support yet).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 09:13:33 +00:00
parent 98fd315f14
commit a965731a33
6 changed files with 300 additions and 225 deletions

View File

@@ -106,7 +106,7 @@
:prefix "item-"
(assert-equal
(list "item-a" "item-b")
(map (fn (x) (string-append (context :prefix) x)) (list "a" "b")))))
(map (fn (x) (str (context :prefix) x)) (list "a" "b")))))
(deftest
"context with keyword name"
(provide :my-key 99 (assert-equal 99 (context :my-key)))))
@@ -260,10 +260,7 @@
:x 5
(assert-equal
"value: 5"
(bind
(let
((v (context :x)))
(string-append "value: " (number->string v)))))))
(bind (let ((v (context :x))) (str "value: " v))))))
(deftest
"bind no deps is static"
(let
@@ -532,7 +529,7 @@
"guard inside bind"
(provide
:x 1
(assert-equal 1 (bind (guard (exn (#t -1)) (context :x))))))
(assert-equal 1 (bind (guard (exn (true -1)) (context :x))))))
(deftest
"bind with string-append"
(provide
@@ -541,4 +538,4 @@
:second "world"
(assert-equal
"hello world"
(bind (string-append (context :first) " " (context :second))))))))
(bind (str (context :first) " " (context :second))))))))