From ce9c5d3a08d8efaebede9d9dc72e776f550554c2 Mon Sep 17 00:00:00 2001 From: giles Date: Tue, 24 Mar 2026 02:50:23 +0000 Subject: [PATCH] Add scope-collected/scope-clear-collected!/scope-emitted primitives Register hashtable-based scope accessors that bypass the CEK special form dispatch, for use by adapter-html.sx and shell templates. Co-Authored-By: Claude Opus 4.6 (1M context) --- hosts/javascript/platform.py | 2 ++ hosts/ocaml/bin/sx_server.ml | 17 +++++++++++++++++ shared/sx/templates/shell.sx | 4 +--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/hosts/javascript/platform.py b/hosts/javascript/platform.py index 5ca8756..dbf0af6 100644 --- a/hosts/javascript/platform.py +++ b/hosts/javascript/platform.py @@ -1141,6 +1141,8 @@ PRIMITIVES_JS_MODULES: dict[str, str] = { PRIMITIVES["scope-emit!"] = scopeEmit; PRIMITIVES["scope-peek"] = scopePeek; PRIMITIVES["scope-emitted"] = sxEmitted; + PRIMITIVES["scope-collected"] = sxCollected; + PRIMITIVES["scope-clear-collected!"] = sxClearCollected; // ---- VM stack primitives ---- // The VM spec (vm.sx) requires these array-like operations. diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index 3585f0f..ccd38af 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -224,6 +224,23 @@ let () = Sx_primitives.register "scope-emitted" (fun args -> (match stack with List items :: _ -> List items | _ -> List []) | _ -> List []) +let () = Sx_primitives.register "scope-collected" (fun args -> + match args with + | [String name] -> + let stack = try Hashtbl.find _scope_stacks name with Not_found -> [] in + (match stack with List items :: _ -> List items | _ -> List []) + | _ -> List []) + +let () = Sx_primitives.register "scope-clear-collected!" (fun args -> + match args with + | [String name] -> + let stack = try Hashtbl.find _scope_stacks name with Not_found -> [] in + (match stack with + | _ :: rest -> Hashtbl.replace _scope_stacks name (List [] :: rest) + | [] -> Hashtbl.replace _scope_stacks name [List []]); + Nil + | _ -> Nil) + let () = Sx_primitives.register "provide-push!" (fun args -> match Sx_primitives.get_primitive "scope-push!" with | NativeFn (_, fn) -> fn args | _ -> Nil) diff --git a/shared/sx/templates/shell.sx b/shared/sx/templates/shell.sx index 6667d5e..eb83fb4 100644 --- a/shared/sx/templates/shell.sx +++ b/shared/sx/templates/shell.sx @@ -32,9 +32,7 @@ (meta :name "csrf-token" :content csrf) (style :id "sx-css" (raw! (or sx-css ""))) ;; CSSX rules from island SSR — must be in so they survive - ;; #main-panel morphs during SPA navigation. Inline the flush logic - ;; rather than calling ~cssx/flush (which has :affinity :client and - ;; gets skipped during SSR rendering). + ;; #main-panel morphs during SPA navigation. (let ((cssx-rules (collected "cssx"))) (clear-collected! "cssx") (when (not (empty? cssx-rules))