Fix WASM reactive signals: unify context/scope, fix flush-subscribers
Three root causes for reactive attribute updates not propagating in WASM: 1. `context` CEK special form only searched kont provide frames, missing `scope-push!` entries in the native scope_stacks hashtable. Unified by adding scope_stacks fallback to step_sf_context. 2. `flush-subscribers` used bare `(sub)` call which failed to invoke complex closures in for-each HO callbacks. Changed to `(cek-call sub nil)`. 3. Test eagerly evaluated `(deref s)` before render-to-dom saw it. Fixed tests to use quoted expressions matching real browser boot. WASM native: 10/10, WASM shell: 26/26. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -480,9 +480,9 @@ and step_sf_scope args env kont =
|
||||
and step_sf_provide args env kont =
|
||||
(let name = (trampoline ((eval_expr ((first (args))) (env)))) in let val' = (trampoline ((eval_expr ((nth (args) ((Number 1.0)))) (env)))) in let body = (prim_call "slice" [args; (Number 2.0)]) in (if sx_truthy ((empty_p (body))) then (make_cek_value (Nil) (env) (kont)) else (make_cek_state ((first (body))) (env) ((kont_push ((make_provide_frame (name) (val') ((rest (body))) (env))) (kont))))))
|
||||
|
||||
(* step-sf-context *)
|
||||
(* step-sf-context — check kont provide frames first, then fall back to scope_stacks *)
|
||||
and step_sf_context args env kont =
|
||||
(let name = (trampoline ((eval_expr ((first (args))) (env)))) in let default_val = (if sx_truthy ((prim_call ">=" [(len (args)); (Number 2.0)])) then (trampoline ((eval_expr ((nth (args) ((Number 1.0)))) (env)))) else Nil) in let frame = (kont_find_provide (kont) (name)) in (make_cek_value ((if sx_truthy ((is_nil (frame))) then default_val else (get (frame) ((String "value"))))) (env) (kont)))
|
||||
(let name = (trampoline ((eval_expr ((first (args))) (env)))) in let default_val = (if sx_truthy ((prim_call ">=" [(len (args)); (Number 2.0)])) then (trampoline ((eval_expr ((nth (args) ((Number 1.0)))) (env)))) else Nil) in let frame = (kont_find_provide (kont) (name)) in (if sx_truthy ((Bool (not (sx_truthy ((is_nil (frame))))))) then (make_cek_value ((get (frame) ((String "value")))) (env) (kont)) else (let scope_val = (sx_context (name) (Nil)) in (make_cek_value ((if sx_truthy ((is_nil (scope_val))) then default_val else scope_val)) (env) (kont)))))
|
||||
|
||||
(* step-sf-emit *)
|
||||
and step_sf_emit args env kont =
|
||||
|
||||
@@ -77,16 +77,24 @@ let () =
|
||||
|
||||
register "context" (fun args ->
|
||||
match args with
|
||||
| [String name] | [String name; _] ->
|
||||
| (String name) :: rest ->
|
||||
let stack = try Hashtbl.find scope_stacks name with Not_found -> [] in
|
||||
if !_scope_trace then
|
||||
_scope_log := Printf.sprintf "CTX %s depth=%d found=%b" name (List.length stack) (stack <> []) :: !_scope_log;
|
||||
(match stack, args with
|
||||
| v :: _, _ -> v
|
||||
| [], [_; default_val] -> default_val
|
||||
| [], _ -> Nil)
|
||||
(match stack with
|
||||
| v :: _ -> v
|
||||
| [] -> (match rest with default_val :: _ -> default_val | [] -> Nil))
|
||||
| _ -> Nil);
|
||||
|
||||
register "context-debug" (fun args ->
|
||||
match args with
|
||||
| [String name] ->
|
||||
let stack = try Hashtbl.find scope_stacks name with Not_found -> [] in
|
||||
let all_keys = Hashtbl.fold (fun k _ acc -> k :: acc) scope_stacks [] in
|
||||
String (Printf.sprintf "name=%s stack_len=%d all_keys=[%s]"
|
||||
name (List.length stack) (String.concat "," all_keys))
|
||||
| _ -> String "bad args");
|
||||
|
||||
(* --- Collect / collected / clear-collected! --- *)
|
||||
|
||||
register "collect!" (fun args ->
|
||||
|
||||
Reference in New Issue
Block a user