sx-http: CSSX source before components in defs, JIT closure bug identified
Move client library sources (cssx.sx) before defcomp/defisland definitions in component-defs so defines are evaluated first. Identified root cause of CSSX "Not callable: nil" errors: JIT compiler captures free variable values at compile time instead of looking them up at runtime from vm_globals. When ~cssx/tw's JIT code calls cssx-process-token, it uses the compile-time snapshot (nil) instead of the runtime value (lambda). The function IS in global_env (type-of returns "lambda") but the JIT bytecode doesn't see it. Fix needed: JIT compiler should emit GLOBAL_GET instructions for free variables that reference vm_globals at runtime, not capture at compile. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1653,8 +1653,24 @@ let read_css_file path =
|
|||||||
|
|
||||||
(** Pre-compute shell statics and inject into env as __shell-* vars. *)
|
(** Pre-compute shell statics and inject into env as __shell-* vars. *)
|
||||||
let http_inject_shell_statics env static_dir sx_sxc =
|
let http_inject_shell_statics env static_dir sx_sxc =
|
||||||
(* Component definitions for client *)
|
(* Component definitions for client.
|
||||||
|
Client library sources FIRST (CSSX etc.) so defines are available
|
||||||
|
before defcomp/defisland bodies that reference them. *)
|
||||||
let buf = Buffer.create 65536 in
|
let buf = Buffer.create 65536 in
|
||||||
|
let project_dir = try Sys.getenv "SX_PROJECT_DIR" with Not_found ->
|
||||||
|
Filename.dirname (Filename.dirname static_dir) in
|
||||||
|
let templates_dir = project_dir ^ "/shared/sx/templates" in
|
||||||
|
let client_libs = [
|
||||||
|
templates_dir ^ "/cssx.sx";
|
||||||
|
] in
|
||||||
|
List.iter (fun path ->
|
||||||
|
if Sys.file_exists path then begin
|
||||||
|
let src = In_channel.with_open_text path In_channel.input_all in
|
||||||
|
Buffer.add_string buf src;
|
||||||
|
Buffer.add_char buf '\n'
|
||||||
|
end
|
||||||
|
) client_libs;
|
||||||
|
(* Then component/island definitions *)
|
||||||
Hashtbl.iter (fun _sym v ->
|
Hashtbl.iter (fun _sym v ->
|
||||||
match v with
|
match v with
|
||||||
| Component c ->
|
| Component c ->
|
||||||
@@ -1671,22 +1687,6 @@ let http_inject_shell_statics env static_dir sx_sxc =
|
|||||||
i.i_name ps (serialize_value i.i_body))
|
i.i_name ps (serialize_value i.i_body))
|
||||||
| _ -> ()
|
| _ -> ()
|
||||||
) env.bindings;
|
) env.bindings;
|
||||||
(* Prepend client library source files — these define functions that
|
|
||||||
island components need at runtime (CSSX, signals, etc.).
|
|
||||||
Read directly from .sx files, same as Quart's _CLIENT_LIBRARY_SOURCES. *)
|
|
||||||
let project_dir = try Sys.getenv "SX_PROJECT_DIR" with Not_found ->
|
|
||||||
Filename.dirname (Filename.dirname static_dir) in
|
|
||||||
let templates_dir = project_dir ^ "/shared/sx/templates" in
|
|
||||||
let client_libs = [
|
|
||||||
templates_dir ^ "/cssx.sx";
|
|
||||||
] in
|
|
||||||
List.iter (fun path ->
|
|
||||||
if Sys.file_exists path then begin
|
|
||||||
let src = In_channel.with_open_text path In_channel.input_all in
|
|
||||||
Buffer.add_string buf src;
|
|
||||||
Buffer.add_char buf '\n'
|
|
||||||
end
|
|
||||||
) client_libs;
|
|
||||||
let raw_defs = Buffer.contents buf in
|
let raw_defs = Buffer.contents buf in
|
||||||
(* Component-defs are inlined in <script type="text/sx">.
|
(* Component-defs are inlined in <script type="text/sx">.
|
||||||
The escape_sx_string function handles </ → <\\/ inside string
|
The escape_sx_string function handles </ → <\\/ inside string
|
||||||
|
|||||||
Reference in New Issue
Block a user