sx-tools: WASM kernel updates, TW/CSSX rework, content refresh, new debugging tools

Build tooling: updated OCaml bootstrapper, compile-modules, bundle.sh, sx-build-all.
WASM browser: rebuilt sx_browser.bc.js/wasm, sx-platform-2.js, .sxbc bytecode files.
CSSX/Tailwind: reworked cssx.sx templates and tw-layout, added tw-type support.
Content: refreshed essays, plans, geography, reactive islands, docs, demos, handlers.
New tools: bisect_sxbc.sh, test-spa.js, render-trace.sx, morph playwright spec.
Tests: added test-match.sx, test-examples.sx, updated test-tw.sx and web tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 11:31:57 +00:00
parent 9ed1100ef6
commit d40a9c6796
178 changed files with 13591 additions and 9110 deletions

View File

@@ -273,28 +273,109 @@ def compile_spec_to_ml(spec_dir: str | None = None) -> str:
"(Env (Sx_types.make_env ())) (a) ((List []))",
)
# Inject JIT dispatch into continue_with_call's lambda branch.
# After params are bound, check jit_call_hook before creating CEK state.
lambda_body_pattern = (
'(prim_call "slice" [params; (len (args))])); Nil)) in '
'(make_cek_state ((lambda_body (f))) (local) (kont))'
# Inject JIT dispatch + &rest handling into continue_with_call's lambda branch.
# Replace the entire lambda binding + make_cek_state section.
cwc_lambda_old = (
'else (if sx_truthy ((is_lambda (f))) then '
'(let params = (lambda_params (f)) in let local = (env_merge ((lambda_closure (f))) (env)) in '
'(if sx_truthy ((prim_call ">" [(len (args)); (len (params))])) then '
'(raise (Eval_error (value_to_str (String (sx_str ['
'(let _or = (lambda_name (f)) in if sx_truthy _or then _or else (String "lambda")); '
'(String " expects "); (len (params)); (String " args, got "); (len (args))])))))'
' else (let () = ignore ((List.iter (fun pair -> ignore ('
'(env_bind local (sx_to_string (first (pair))) (nth (pair) ((Number 1.0))))))'
' (sx_to_list (prim_call "zip" [params; args])); Nil)) in '
'(let () = ignore ((List.iter (fun p -> ignore ((env_bind local (sx_to_string p) Nil)))'
' (sx_to_list (prim_call "slice" [params; (len (args))])); Nil)) in '
'(make_cek_state ((lambda_body (f))) (local) (kont))))))'
)
lambda_body_jit = (
'(prim_call "slice" [params; (len (args))])); Nil)) in '
cwc_lambda_new = (
'else (if sx_truthy ((is_lambda (f))) then '
'(let params = (lambda_params (f)) in let local = (env_merge ((lambda_closure (f))) (env)) in '
'(if not (bind_lambda_with_rest params args local) then begin '
'let pl = sx_to_list params and al = sx_to_list args in '
'if List.length al > List.length pl then '
'raise (Eval_error (Printf.sprintf "%s expects %d args, got %d" '
'(match lambda_name f with String s -> s | _ -> "lambda") '
'(List.length pl) (List.length al))); '
'List.iter (fun pair -> ignore (env_bind local (sx_to_string (first pair)) (nth pair (Number 1.0)))) '
'(sx_to_list (prim_call "zip" [params; args])); '
'List.iter (fun p -> ignore (env_bind local (sx_to_string p) Nil)) '
'(sx_to_list (prim_call "slice" [params; len args])) end; '
'(match !jit_call_hook, f with '
'| Some hook, Lambda l when l.l_name <> None -> '
'let args_list = match args with '
'List a | ListRef { contents = a } -> a | _ -> [] in '
'let args_list = match args with List a | ListRef { contents = a } -> a | _ -> [] in '
'(match hook f args_list with '
'Some result -> make_cek_value result local kont '
'| None -> make_cek_state (lambda_body f) local kont) '
'| _ -> make_cek_state ((lambda_body (f))) (local) (kont))'
'| _ -> make_cek_state ((lambda_body (f))) (local) (kont))))'
)
if lambda_body_pattern in output:
output = output.replace(lambda_body_pattern, lambda_body_jit, 1)
if cwc_lambda_old in output:
output = output.replace(cwc_lambda_old, cwc_lambda_new, 1)
else:
import sys
print("WARNING: Could not find lambda body pattern for JIT injection", file=sys.stderr)
print("WARNING: Could not find continue_with_call lambda pattern for &rest+JIT injection", file=sys.stderr)
# Patch call_lambda and continue_with_call to handle &rest in lambda params.
# The transpiler can't handle the index-of-based approach, so we inject it.
REST_HELPER = """
(* &rest lambda param binding — injected by bootstrap.py *)
and bind_lambda_with_rest params args local =
let param_list = sx_to_list params in
let arg_list = sx_to_list args in
let rec find_rest i = function
| [] -> None
| h :: rp :: _ when value_to_str h = "&rest" -> Some (i, value_to_str rp)
| _ :: tl -> find_rest (i + 1) tl
in
match find_rest 0 param_list with
| Some (pos, rest_name) ->
let positional = List.filteri (fun i _ -> i < pos) param_list in
List.iteri (fun i p ->
let v = if i < List.length arg_list then List.nth arg_list i else Nil in
ignore (env_bind local (value_to_str p) v)
) positional;
let rest_args = if List.length arg_list > pos
then List (List.filteri (fun i _ -> i >= pos) arg_list)
else List [] in
ignore (env_bind local rest_name rest_args);
true
| None -> false
"""
# Inject the helper before call_lambda
output = output.replace(
"(* call-lambda *)\nand call_lambda",
REST_HELPER + "\n(* call-lambda *)\nand call_lambda",
)
# Patch call_lambda to use &rest-aware binding
call_lambda_marker = "(* call-lambda *)\nand call_lambda f args caller_env =\n"
call_comp_marker = "\n(* call-component *)"
if call_lambda_marker in output and call_comp_marker in output:
start = output.index(call_lambda_marker)
end = output.index(call_comp_marker)
new_call_lambda = """(* call-lambda *)
and call_lambda f args caller_env =
let params = lambda_params f in
let local = env_merge (lambda_closure f) caller_env in
if not (bind_lambda_with_rest params args local) then begin
let pl = sx_to_list params and al = sx_to_list args in
if List.length al > List.length pl then
raise (Eval_error (Printf.sprintf "%s expects %d args, got %d"
(match lambda_name f with String s -> s | _ -> "lambda")
(List.length pl) (List.length al)));
List.iter (fun pair ->
ignore (env_bind local (sx_to_string (first pair)) (nth pair (Number 1.0)))
) (sx_to_list (prim_call "zip" [params; args]));
List.iter (fun p ->
ignore (env_bind local (sx_to_string p) Nil)
) (sx_to_list (prim_call "slice" [params; len args]))
end;
make_thunk (lambda_body f) local
"""
output = output[:start] + new_call_lambda + output[end:]
else:
print("WARNING: Could not find call_lambda for &rest injection", file=sys.stderr)
# Instrument recursive cek_run to capture kont on error (for comp-trace).
# The iterative cek_run_iterative already does this, but cek_call uses