Fix vm-global-get in native OCaml VM + transpiled VM ref
The previous commit fixed lib/vm.sx (SX spec) but the server uses sx_vm.ml (hand-maintained native OCaml) and sx_vm_ref.ml (transpiled). Both had the same globals-first lookup bug. Now all three implementations check closure env before vm.globals, matching vm-global-set. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -410,21 +410,23 @@ and run vm =
|
||||
| 20 (* OP_GLOBAL_GET *) ->
|
||||
let idx = read_u16 frame in
|
||||
let name = match consts.(idx) with String s -> s | _ -> "" in
|
||||
let v = try Hashtbl.find vm.globals name with Not_found ->
|
||||
(* Walk the closure env chain for inner functions *)
|
||||
let id = Sx_types.intern name in
|
||||
let rec env_lookup e =
|
||||
try Hashtbl.find e.bindings id
|
||||
with Not_found ->
|
||||
match e.parent with Some p -> env_lookup p | None ->
|
||||
try Sx_primitives.get_primitive name
|
||||
with _ -> raise (Eval_error ("VM undefined: " ^ name))
|
||||
in
|
||||
match frame.closure.vm_closure_env with
|
||||
| Some env -> env_lookup env
|
||||
(* Check closure env first (matches OP_GLOBAL_SET priority) *)
|
||||
let id = Sx_types.intern name in
|
||||
let found_in_env = match frame.closure.vm_closure_env with
|
||||
| Some env ->
|
||||
let rec env_lookup e =
|
||||
try Some (Hashtbl.find e.bindings id)
|
||||
with Not_found ->
|
||||
match e.parent with Some p -> env_lookup p | None -> None
|
||||
in env_lookup env
|
||||
| None -> None
|
||||
in
|
||||
let v = match found_in_env with
|
||||
| Some v -> v
|
||||
| None ->
|
||||
try Sx_primitives.get_primitive name
|
||||
with _ -> raise (Eval_error ("VM undefined: " ^ name))
|
||||
try Hashtbl.find vm.globals name with Not_found ->
|
||||
try Sx_primitives.get_primitive name
|
||||
with _ -> raise (Eval_error ("VM undefined: " ^ name))
|
||||
in
|
||||
push vm v
|
||||
| 21 (* OP_GLOBAL_SET *) ->
|
||||
|
||||
@@ -198,32 +198,31 @@ let vm_globals_ref v = let m = unwrap_vm v in Dict m.vm_globals
|
||||
let vm_global_get vm_val frame_val name =
|
||||
let m = unwrap_vm vm_val in
|
||||
let n = value_to_string name in
|
||||
(* Try globals table first *)
|
||||
match Hashtbl.find_opt m.vm_globals n with
|
||||
let f = unwrap_frame frame_val in
|
||||
(* Check closure env first (matches vm_global_set priority) *)
|
||||
let found_in_env = match f.vf_closure.vm_closure_env with
|
||||
| Some env ->
|
||||
let id = intern n in
|
||||
let rec find_env e =
|
||||
match Hashtbl.find_opt e.bindings id with
|
||||
| Some v -> Some v
|
||||
| None -> (match e.parent with Some p -> find_env p | None -> None)
|
||||
in find_env env
|
||||
| None -> None
|
||||
in
|
||||
match found_in_env with
|
||||
| Some v -> v
|
||||
| None ->
|
||||
(* Walk closure env chain *)
|
||||
let f = unwrap_frame frame_val in
|
||||
let not_found () =
|
||||
(* Try evaluator's primitive table *)
|
||||
match Hashtbl.find_opt m.vm_globals n with
|
||||
| Some v -> v
|
||||
| None ->
|
||||
try prim_call n [] with _ ->
|
||||
(* Try symbol resolve hook — transparent lazy module loading *)
|
||||
match !_symbol_resolve_hook with
|
||||
| Some hook ->
|
||||
(match hook n with
|
||||
| Some v -> v
|
||||
| None -> raise (Eval_error ("VM undefined: " ^ n)))
|
||||
| None -> raise (Eval_error ("VM undefined: " ^ n))
|
||||
in
|
||||
(match f.vf_closure.vm_closure_env with
|
||||
| Some env ->
|
||||
let id = intern n in
|
||||
let rec find_env e =
|
||||
match Hashtbl.find_opt e.bindings id with
|
||||
| Some v -> v
|
||||
| None -> (match e.parent with Some p -> find_env p | None -> not_found ())
|
||||
in find_env env
|
||||
| None -> not_found ())
|
||||
|
||||
let vm_global_set vm_val frame_val name v =
|
||||
let m = unwrap_vm vm_val in
|
||||
|
||||
Reference in New Issue
Block a user