IO registry: defio declares platform suspension points
Core SX has zero IO — platforms extend __io-registry via (defio name :category :data/:code/:effect ...). The server web platform declares 44 operations in web/io.sx. batchable_helpers now derived from registry (:batchable true) instead of hardcoded list. Startup validation warns if bound IO ops lack registry entries. Browser gets empty registry, ready for step 5 (IO suspension). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -608,6 +608,25 @@ let make_test_env () =
|
||||
island
|
||||
| _ -> Nil)));
|
||||
|
||||
(* defio — IO registry for platform suspension points *)
|
||||
let io_registry = Hashtbl.create 64 in
|
||||
ignore (Sx_types.env_bind env "__io-registry" (Dict io_registry));
|
||||
ignore (Sx_ref.register_special_form (String "defio") (NativeFn ("defio", fun sf_args ->
|
||||
let raw_args = match sf_args with
|
||||
| [List a; Env _] | [ListRef { contents = a }; Env _] -> a
|
||||
| _ -> [] in
|
||||
match raw_args with
|
||||
| String name :: rest ->
|
||||
let entry = Hashtbl.create 8 in
|
||||
let rec parse = function
|
||||
| Keyword k :: v :: rest -> Hashtbl.replace entry k v; parse rest
|
||||
| _ -> () in
|
||||
parse rest;
|
||||
Hashtbl.replace entry "name" (String name);
|
||||
Hashtbl.replace io_registry name (Dict entry);
|
||||
Dict entry
|
||||
| _ -> Nil)));
|
||||
|
||||
(* --- Primitives for canonical.sx / content tests --- *)
|
||||
bind "contains-char?" (fun args ->
|
||||
match args with
|
||||
|
||||
@@ -1948,7 +1948,27 @@ let http_setup_declarative_stubs env =
|
||||
noop "defquery";
|
||||
noop "defaction";
|
||||
noop "defrelation";
|
||||
noop "defstyle"
|
||||
noop "defstyle";
|
||||
(* IO registry — starts empty, platforms extend via defio.
|
||||
defio is a special form that populates __io-registry with metadata
|
||||
about suspension points (IO ops that require platform resolution). *)
|
||||
let io_registry = Hashtbl.create 64 in
|
||||
ignore (env_bind env "__io-registry" (Dict io_registry));
|
||||
ignore (Sx_ref.register_special_form (String "defio") (NativeFn ("defio", fun sf_args ->
|
||||
let raw_args = match sf_args with
|
||||
| [List a; Env _] | [ListRef { contents = a }; Env _] -> a
|
||||
| _ -> [] in
|
||||
match raw_args with
|
||||
| String name :: rest ->
|
||||
let entry = Hashtbl.create 8 in
|
||||
let rec parse = function
|
||||
| Keyword k :: v :: rest -> Hashtbl.replace entry k v; parse rest
|
||||
| _ -> () in
|
||||
parse rest;
|
||||
Hashtbl.replace entry "name" (String name);
|
||||
Hashtbl.replace io_registry name (Dict entry);
|
||||
Dict entry
|
||||
| _ -> Nil)))
|
||||
|
||||
let http_setup_platform_constructors env =
|
||||
(* Platform constructor functions expected by evaluator.sx.
|
||||
@@ -2365,6 +2385,7 @@ let http_mode port =
|
||||
spec_base ^ "/signals.sx";
|
||||
lib_base ^ "/compiler.sx";
|
||||
web_base ^ "/adapter-html.sx"; web_base ^ "/adapter-sx.sx";
|
||||
web_base ^ "/io.sx";
|
||||
web_base ^ "/web-forms.sx"; web_base ^ "/engine.sx";
|
||||
web_base ^ "/request-handler.sx";
|
||||
web_base ^ "/page-helpers.sx";
|
||||
@@ -2404,11 +2425,35 @@ let http_mode port =
|
||||
load_dir sx_sx;
|
||||
let t1 = Unix.gettimeofday () in
|
||||
Printf.eprintf "[sx-http] All files loaded in %.3fs\n%!" (t1 -. t0);
|
||||
(* Derive batchable_helpers from __io-registry *)
|
||||
(try match env_get env "__io-registry" with
|
||||
| Dict registry ->
|
||||
let batchable = Hashtbl.fold (fun name entry acc ->
|
||||
match entry with
|
||||
| Dict d -> (match Hashtbl.find_opt d "batchable" with
|
||||
| Some (Bool true) -> name :: acc | _ -> acc)
|
||||
| _ -> acc) registry [] in
|
||||
if batchable <> [] then batchable_helpers := batchable;
|
||||
Printf.eprintf "[sx-http] IO registry: %d ops, %d batchable\n%!"
|
||||
(Hashtbl.length registry) (List.length batchable);
|
||||
(* Validate: warn if bound IO ops are not declared *)
|
||||
let expected = ["query"; "action"; "request-arg"; "request-method";
|
||||
"ctx"; "helper"; "json-encode"; "into"; "sleep";
|
||||
"set-response-status"; "set-response-header"] in
|
||||
List.iter (fun name ->
|
||||
if not (Hashtbl.mem registry name) then
|
||||
Printf.eprintf "[sx-http] WARNING: IO '%s' bound but not in registry\n%!" name
|
||||
) expected
|
||||
| _ -> ()
|
||||
with _ -> ());
|
||||
(* Extract app config from __app-config dict *)
|
||||
(try match env_get env "__app-config" with
|
||||
| Dict d ->
|
||||
_app_config := Some d;
|
||||
batchable_helpers := get_app_list "batchable-helpers" ["highlight"; "component-source"];
|
||||
(* App config can add extra batchable helpers on top of registry *)
|
||||
let extra = get_app_list "batchable-helpers" [] in
|
||||
if extra <> [] then
|
||||
batchable_helpers := List.sort_uniq String.compare (!batchable_helpers @ extra);
|
||||
Printf.eprintf "[sx-http] App config loaded: title=%s prefix=%s\n%!"
|
||||
(get_app_str "title" "?") (get_app_str "path-prefix" "?")
|
||||
| _ -> Printf.eprintf "[sx-http] WARNING: __app-config is not a dict\n%!"
|
||||
|
||||
@@ -671,6 +671,27 @@ let () =
|
||||
|
||||
bind "define-page-helper" (fun _ -> Nil);
|
||||
|
||||
(* IO registry — starts empty in browser. Platforms extend via defio.
|
||||
Browser has zero suspension points initially; future browser IO
|
||||
(lazy module loads, fetch-request) will add entries here. *)
|
||||
let io_registry = Hashtbl.create 16 in
|
||||
ignore (env_bind global_env "__io-registry" (Dict io_registry));
|
||||
ignore (Sx_ref.register_special_form (String "defio") (NativeFn ("defio", fun sf_args ->
|
||||
let raw_args = match sf_args with
|
||||
| [List a; Env _] | [ListRef { contents = a }; Env _] -> a
|
||||
| _ -> [] in
|
||||
match raw_args with
|
||||
| String name :: rest ->
|
||||
let entry = Hashtbl.create 8 in
|
||||
let rec parse = function
|
||||
| Keyword k :: v :: rest -> Hashtbl.replace entry k v; parse rest
|
||||
| _ -> () in
|
||||
parse rest;
|
||||
Hashtbl.replace entry "name" (String name);
|
||||
Hashtbl.replace io_registry name (Dict entry);
|
||||
Dict entry
|
||||
| _ -> Nil)));
|
||||
|
||||
(* --- Render --- *)
|
||||
Sx_render.setup_render_env global_env;
|
||||
bind "set-render-active!" (fun _ -> Nil);
|
||||
|
||||
Reference in New Issue
Block a user