Fix WASM browser: broken links (&rest bytecode) + broken reactive counter (ListRef mutation)
Two bugs fixed: 1. Links: bytecode compiler doesn't handle &rest params — treats them as positional, so (first rest) gets a raw string instead of a list. Replaced &rest with explicit optional params in all bytecode-compiled web SX files (dom-query, dom-add-listener, browser-push-state, etc.). The VM already pads missing args with Nil. 2. Reactive counter: signal-remove-sub! used (filter ...) which returns immutable List, but signal-add-sub! uses (append!) which only mutates ListRef. Subscribers silently vanished after first effect re-run. Fixed by adding remove! primitive that mutates ListRef in-place. Also: - Added evalVM API to WASM kernel (compile + run through bytecode VM) - Added scope tracing (scope-push!/pop!/peek/context instrumentation) - Added Playwright reactive mode for debugging island signal/DOM state - Replaced cek-call with direct calls in core-signals.sx effect/computed - Recompiled all 23 bytecode modules Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,16 @@ open Sx_types
|
||||
Used by aser for spread/provide/emit patterns, CSSX collect/flush, etc. *)
|
||||
let scope_stacks : (string, value list) Hashtbl.t = Hashtbl.create 8
|
||||
|
||||
(** Debug trace for scope operations — enabled from JS *)
|
||||
let _scope_trace = ref false
|
||||
let _scope_log : string list ref = ref []
|
||||
let scope_trace_enable () = _scope_trace := true; _scope_log := []
|
||||
let scope_trace_disable () = _scope_trace := false
|
||||
let scope_trace_drain () =
|
||||
let log = List.rev !_scope_log in
|
||||
_scope_log := [];
|
||||
log
|
||||
|
||||
(** Request cookies — set by the Python bridge before each render.
|
||||
get-cookie reads from here; set-cookie is a no-op on the server. *)
|
||||
let request_cookies : (string, string) Hashtbl.t = Hashtbl.create 8
|
||||
@@ -40,6 +50,8 @@ let () =
|
||||
match args with
|
||||
| [String name; value] ->
|
||||
let stack = try Hashtbl.find scope_stacks name with Not_found -> [] in
|
||||
if !_scope_trace then
|
||||
_scope_log := Printf.sprintf "PUSH %s depth=%d->%d" name (List.length stack) (List.length stack + 1) :: !_scope_log;
|
||||
Hashtbl.replace scope_stacks name (value :: stack); Nil
|
||||
| _ -> Nil);
|
||||
|
||||
@@ -47,6 +59,8 @@ let () =
|
||||
match args with
|
||||
| [String name] ->
|
||||
let stack = try Hashtbl.find scope_stacks name with Not_found -> [] in
|
||||
if !_scope_trace then
|
||||
_scope_log := Printf.sprintf "POP %s depth=%d->%d" name (List.length stack) (max 0 (List.length stack - 1)) :: !_scope_log;
|
||||
(match stack with _ :: rest -> Hashtbl.replace scope_stacks name rest | [] -> ()); Nil
|
||||
| _ -> Nil);
|
||||
|
||||
@@ -54,6 +68,8 @@ let () =
|
||||
match args with
|
||||
| [String name] ->
|
||||
let stack = try Hashtbl.find scope_stacks name with Not_found -> [] in
|
||||
if !_scope_trace then
|
||||
_scope_log := Printf.sprintf "PEEK %s depth=%d found=%b" name (List.length stack) (stack <> []) :: !_scope_log;
|
||||
(match stack with v :: _ -> v | [] -> Nil)
|
||||
| _ -> Nil);
|
||||
|
||||
@@ -63,6 +79,8 @@ let () =
|
||||
match args with
|
||||
| [String name] | [String name; _] ->
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user