HS: IO suspension resolver + append command + list stringify

IO Suspension:
- Set _cek_io_resolver in test runner to handle perform/wait/fetch
- io-sleep/io-wait: instant resume (no real delay in tests)
- io-fetch: returns mock {ok:true, status:200, json:{foo:1}} response
- io-wait-for/io-settle: instant resume
- Fixes ~30 tests that were failing with VmSuspended or timeouts

Append command:
- hs-append (pure): string concat or list append
- hs-append! (effectful): DOM insertAdjacentHTML
- Compiler emits set! wrapper for variable targets

Mock DOM:
- dom_stringify handles List → comma-separated string

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 19:43:52 +00:00
parent c8aab54d52
commit c59070ad20

View File

@@ -2130,6 +2130,30 @@ let run_spec_tests env test_files =
Hashtbl.replace mock_body "textContent" (String "");
Nil);
(* IO suspension resolver — handles perform/wait/fetch in event handlers *)
Sx_types._cek_io_resolver := Some (fun request _suspended ->
match request with
| Dict d ->
let op = match Hashtbl.find_opt d "op" with Some (String s) -> s | _ -> "" in
(match op with
| "io-sleep" | "io-wait" -> Nil (* instant resume in tests *)
| "io-settle" -> Nil
| "io-fetch" ->
let url = match Hashtbl.find_opt d "args" with
| Some (List (String u :: _)) -> u | _ -> "" in
(* Return mock fetch response *)
let resp = Hashtbl.create 4 in
Hashtbl.replace resp "ok" (Bool true);
Hashtbl.replace resp "status" (Number 200.0);
Hashtbl.replace resp "url" (String url);
Hashtbl.replace resp "text" (String (Printf.sprintf "{\"foo\":1}"));
Hashtbl.replace resp "json" (let j = Hashtbl.create 2 in Hashtbl.replace j "foo" (Number 1.0); Dict j);
Hashtbl.replace resp "headers" (Dict (Hashtbl.create 0));
Dict resp
| "io-wait-for" -> Nil (* event wait — instant *)
| _ -> Nil)
| _ -> Nil);
(* Load modules needed by tests *)
let spec_dir = Filename.concat project_dir "spec" in
let lib_dir = Filename.concat project_dir "lib" in