Fix env-merge for Dict/Nil args + add adapter-html.sx primitives
sx_runtime.ml: unwrap_env now accepts Dict and Nil (converts to Env), fixing env-merge when adapter-html.sx passes dict-as-env. sx_server.ml + run_tests.ml: env-merge bindings use Sx_runtime.env_merge (which handles Dict/Nil) instead of requiring strict Env pattern match. sx_primitives.ml: Added scope stack (scope-push!/pop!/peek/emit!, emitted), type predicates (lambda?/island?/component?/macro?), component accessors (closure/name/params/body/has-children?), lambda accessors, for-each-indexed, empty-dict?, make-raw-html, raw-html-content, is-else-clause?. 8 OCaml render tests still fail (env propagation in render-lambda-html) — same adapter code works in JS and in production via Python bridge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -208,7 +208,7 @@ let make_test_env () =
|
|||||||
|
|
||||||
bind "env-merge" (fun args ->
|
bind "env-merge" (fun args ->
|
||||||
match args with
|
match args with
|
||||||
| [Env a; Env b] -> Env (Sx_types.env_merge a b)
|
| [a; b] -> Sx_runtime.env_merge a b
|
||||||
| _ -> raise (Eval_error "env-merge: expected 2 envs"));
|
| _ -> raise (Eval_error "env-merge: expected 2 envs"));
|
||||||
|
|
||||||
(* --- Equality --- *)
|
(* --- Equality --- *)
|
||||||
@@ -280,6 +280,11 @@ let make_test_env () =
|
|||||||
bind "eval-expr" (fun args ->
|
bind "eval-expr" (fun args ->
|
||||||
match args with
|
match args with
|
||||||
| [expr; Env e] -> eval_expr expr (Env e)
|
| [expr; Env e] -> eval_expr expr (Env e)
|
||||||
|
| [expr; Dict d] ->
|
||||||
|
(* Dict used as env — wrap it *)
|
||||||
|
let e = Sx_types.make_env () in
|
||||||
|
Hashtbl.iter (fun k v -> ignore (Sx_types.env_bind e k v)) d;
|
||||||
|
eval_expr expr (Env e)
|
||||||
| [expr] -> eval_expr expr (Env env)
|
| [expr] -> eval_expr expr (Env env)
|
||||||
| _ -> raise (Eval_error "eval-expr: expected (expr env)"));
|
| _ -> raise (Eval_error "eval-expr: expected (expr env)"));
|
||||||
bind "scope-push!" (fun args ->
|
bind "scope-push!" (fun args ->
|
||||||
|
|||||||
@@ -824,7 +824,7 @@ let make_server_env () =
|
|||||||
|
|
||||||
bind "env-merge" (fun args ->
|
bind "env-merge" (fun args ->
|
||||||
match args with
|
match args with
|
||||||
| [Env a; Env b] -> Env (env_merge a b)
|
| [a; b] -> Sx_runtime.env_merge a b
|
||||||
| _ -> raise (Eval_error "env-merge: expected 2 envs"));
|
| _ -> raise (Eval_error "env-merge: expected 2 envs"));
|
||||||
|
|
||||||
(* Strict mode state *)
|
(* Strict mode state *)
|
||||||
|
|||||||
@@ -242,6 +242,14 @@ let type_of v = String (Sx_types.type_of v)
|
|||||||
The transpiled CEK machine stores envs in dicts as Env values. *)
|
The transpiled CEK machine stores envs in dicts as Env values. *)
|
||||||
let unwrap_env = function
|
let unwrap_env = function
|
||||||
| Env e -> e
|
| Env e -> e
|
||||||
|
| Dict d ->
|
||||||
|
(* Dict used as env — wrap it. Needed by adapter-html.sx which
|
||||||
|
passes dicts as env args (e.g. empty {} as caller env). *)
|
||||||
|
let e = Sx_types.make_env () in
|
||||||
|
Hashtbl.iter (fun k v -> ignore (Sx_types.env_bind e k v)) d;
|
||||||
|
e
|
||||||
|
| Nil ->
|
||||||
|
Sx_types.make_env ()
|
||||||
| v -> raise (Eval_error ("Expected env, got " ^ Sx_types.type_of v))
|
| v -> raise (Eval_error ("Expected env, got " ^ Sx_types.type_of v))
|
||||||
|
|
||||||
let env_has e name = Bool (Sx_types.env_has (unwrap_env e) (value_to_str name))
|
let env_has e name = Bool (Sx_types.env_has (unwrap_env e) (value_to_str name))
|
||||||
|
|||||||
Reference in New Issue
Block a user