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

@@ -80,6 +80,15 @@ let sx_dict_set_b d k v =
match d, k with
| Dict tbl, String key -> Hashtbl.replace tbl key v; v
| Dict tbl, Keyword key -> Hashtbl.replace tbl key v; v
| CekFrame f, String key ->
(match key with
| "value" | "extra" | "ho-type" | "scheme" | "indexed"
| "phase" | "has-effects" | "match-val" | "current-item"
| "update-fn" | "head-name" -> f.cf_extra <- v; v
| "remaining" -> f.cf_remaining <- v; v
| "subscribers" | "results" | "raw-args" -> f.cf_results <- v; v
| "emitted" | "effect-list" | "first-render" | "extra2" -> f.cf_extra2 <- v; v
| _ -> raise (Eval_error ("dict-set! cek-frame: unknown field " ^ key)))
| VmFrame f, String key ->
(match key with
| "ip" -> f.vf_ip <- val_to_int v; v
@@ -116,6 +125,8 @@ let get_val container key =
| "emitted" -> f.cf_extra2 | "effect-list" -> f.cf_extra2
| "first-render" -> f.cf_extra2 | "file" -> f.cf_env
| "extra" -> f.cf_extra | "extra2" -> f.cf_extra2
| "subscribers" -> f.cf_results
| "prev-tracking" -> f.cf_extra
| _ -> Nil)
| VmFrame f, String k ->
(match k with