;; lib/ocaml/runtime.sx — minimal OCaml stdlib slice, written in OCaml.
;;
;; Defines List and Option modules with the most-used functions. Loaded
;; on demand via `(ocaml-load-stdlib! env)` from eval.sx, which parses
;; this source through `ocaml-parse-program` and evaluates each decl,
;; threading the env so stdlib bindings become available to user code.
;;
;; What's here is intentionally minimal — Phase 6 grows this into the
;; full ~150-function slice. Everything is defined in OCaml syntax (not
;; SX) on purpose, both as substrate validation and as documentation.

(define ocaml-stdlib-src
  "module List = struct
     let rec length lst =
       match lst with
       | [] -> 0
       | _ :: t -> 1 + length t

     let rec rev_append xs acc =
       match xs with
       | [] -> acc
       | h :: t -> rev_append t (h :: acc)

     let rev xs = rev_append xs []

     let rec map f lst =
       match lst with
       | [] -> []
       | h :: t -> f h :: map f t

     let rec filter p lst =
       match lst with
       | [] -> []
       | h :: t -> if p h then h :: filter p t else filter p t

     let rec fold_left f init lst =
       match lst with
       | [] -> init
       | h :: t -> fold_left f (f init h) t

     let rec fold_right f lst init =
       match lst with
       | [] -> init
       | h :: t -> f h (fold_right f t init)

     let rec append xs ys =
       match xs with
       | [] -> ys
       | h :: t -> h :: append t ys

     let rec iter f lst =
       match lst with
       | [] -> ()
       | h :: t -> f h; iter f t

     let rec mem x lst =
       match lst with
       | [] -> false
       | h :: t -> if h = x then true else mem x t

     let rec for_all p lst =
       match lst with
       | [] -> true
       | h :: t -> if p h then for_all p t else false

     let rec exists p lst =
       match lst with
       | [] -> false
       | h :: t -> if p h then true else exists p t

     let hd lst =
       match lst with
       | [] -> failwith \"List.hd: empty\"
       | h :: _ -> h

     let tl lst =
       match lst with
       | [] -> failwith \"List.tl: empty\"
       | _ :: t -> t

     let rec nth lst n =
       match lst with
       | [] -> failwith \"List.nth: out of range\"
       | h :: t -> if n = 0 then h else nth t (n - 1)

     let rec concat lst =
       match lst with
       | [] -> []
       | h :: t -> append h (concat t)

     let flatten = concat

     let rec init n f =
       if n = 0 then [] else
       begin
         let rec build i =
           if i = n then [] else f i :: build (i + 1)
         in build 0
       end

     let rec find_opt p lst =
       match lst with
       | [] -> None
       | h :: t -> if p h then Some h else find_opt p t

     let rec find p lst =
       match find_opt p lst with
       | None -> failwith \"List.find: not found\"
       | Some x -> x

     let rec partition p lst =
       match lst with
       | [] -> ([], [])
       | h :: t ->
         (match partition p t with
          | (yes, no) ->
            if p h then (h :: yes, no) else (yes, h :: no))

     let rec mapi f lst =
       begin
         let rec go i xs =
           match xs with
           | [] -> []
           | h :: t -> f i h :: go (i + 1) t
         in go 0 lst
       end

     let rec iteri f lst =
       begin
         let rec go i xs =
           match xs with
           | [] -> ()
           | h :: t -> f i h; go (i + 1) t
         in go 0 lst
       end

     let rec assoc k lst =
       match lst with
       | [] -> failwith \"List.assoc: not found\"
       | (k2, v) :: t -> if k = k2 then v else assoc k t

     let rec assoc_opt k lst =
       match lst with
       | [] -> None
       | (k2, v) :: t -> if k = k2 then Some v else assoc_opt k t

     let rec sort cmp xs =
       begin
         let rec split lst =
           match lst with
           | [] -> ([], [])
           | [x] -> ([x], [])
           | x :: y :: rest ->
             (match split rest with
              | (a, b) -> (x :: a, y :: b))
         in
         let rec merge xs ys =
           match xs with
           | [] -> ys
           | x :: xs' ->
             (match ys with
              | [] -> xs
              | y :: ys' ->
                if cmp x y <= 0 then x :: merge xs' (y :: ys')
                else y :: merge (x :: xs') ys')
         in
         match xs with
         | [] -> []
         | [x] -> [x]
         | _ ->
           (match split xs with
            | (a, b) -> merge (sort cmp a) (sort cmp b))
       end

     let stable_sort = sort

     let rec sort_uniq cmp xs =
       let sorted = sort cmp xs in
       let rec dedup ys =
         match ys with
         | [] -> []
         | [x] -> [x]
         | a :: b :: rest ->
           if cmp a b = 0 then dedup (b :: rest)
           else a :: dedup (b :: rest)
       in
       dedup sorted

     let rec find_map f xs =
       match xs with
       | [] -> None
       | h :: t ->
         match f h with
         | Some v -> Some v
         | None -> find_map f t

     let rec equal eq a b =
       match a with
       | [] -> (match b with [] -> true | _ -> false)
       | h :: t ->
         (match b with
          | [] -> false
          | h2 :: t2 -> if eq h h2 then equal eq t t2 else false)

     let rec compare cmp a b =
       match a with
       | [] -> (match b with [] -> 0 | _ -> -1)
       | h :: t ->
         (match b with
          | [] -> 1
          | h2 :: t2 ->
            let c = cmp h h2 in
            if c <> 0 then c else compare cmp t t2)

     let rec combine xs ys =
       match xs with
       | [] -> (match ys with
                | [] -> []
                | _ -> failwith \"List.combine: unequal lengths\")
       | hx :: tx ->
         match ys with
         | [] -> failwith \"List.combine: unequal lengths\"
         | hy :: ty -> (hx, hy) :: combine tx ty

     let rec split lst =
       match lst with
       | [] -> ([], [])
       | (a, b) :: t ->
         (match split t with
          | (xs, ys) -> (a :: xs, b :: ys))

     let rec fold_left2 f acc xs ys =
       match xs with
       | [] -> (match ys with [] -> acc | _ -> failwith \"List.fold_left2: unequal\")
       | hx :: tx ->
         match ys with
         | [] -> failwith \"List.fold_left2: unequal\"
         | hy :: ty -> fold_left2 f (f acc hx hy) tx ty

     let rec iter2 f xs ys =
       match xs with
       | [] -> (match ys with [] -> () | _ -> failwith \"List.iter2: unequal\")
       | hx :: tx ->
         match ys with
         | [] -> failwith \"List.iter2: unequal\"
         | hy :: ty -> f hx hy; iter2 f tx ty

     let rec map2 f xs ys =
       match xs with
       | [] -> (match ys with [] -> [] | _ -> failwith \"List.map2: unequal\")
       | hx :: tx ->
         match ys with
         | [] -> failwith \"List.map2: unequal\"
         | hy :: ty -> f hx hy :: map2 f tx ty

     let rec take n xs =
       if n <= 0 then []
       else
         match xs with
         | [] -> []
         | h :: t -> h :: take (n - 1) t

     let rec drop n xs =
       if n <= 0 then xs
       else
         match xs with
         | [] -> []
         | _ :: t -> drop (n - 1) t

     let rec filter_map f xs =
       match xs with
       | [] -> []
       | h :: t ->
         match f h with
         | None -> filter_map f t
         | Some v -> v :: filter_map f t

     let rec flat_map f xs =
       match xs with
       | [] -> []
       | h :: t -> append (f h) (flat_map f t)

     let concat_map = flat_map
   end ;;

   module Option = struct
     let map f o =
       match o with
       | None -> None
       | Some x -> Some (f x)

     let bind o f =
       match o with
       | None -> None
       | Some x -> f x

     let value o default =
       match o with
       | None -> default
       | Some x -> x

     let get o =
       match o with
       | None -> failwith \"Option.get: None\"
       | Some x -> x

     let is_none o =
       match o with
       | None -> true
       | Some _ -> false

     let is_some o =
       match o with
       | None -> false
       | Some _ -> true

     let iter f o =
       match o with
       | None -> ()
       | Some x -> f x

     let fold none_v f o =
       match o with
       | None -> none_v
       | Some x -> f x

     let to_list o =
       match o with
       | None -> []
       | Some x -> [x]

     let join oo =
       match oo with
       | None -> None
       | Some inner -> inner

     let to_result none_v o =
       match o with
       | None -> Error none_v
       | Some x -> Ok x

     let equal eq a b =
       match a with
       | None -> (match b with None -> true | Some _ -> false)
       | Some x ->
         (match b with None -> false | Some y -> eq x y)

     let compare cmp a b =
       match a with
       | None -> (match b with None -> 0 | Some _ -> -1)
       | Some x ->
         (match b with None -> 1 | Some y -> cmp x y)

     let some x = Some x
     let none = None
   end ;;

   module Result = struct
     let map f r =
       match r with
       | Ok x -> Ok (f x)
       | Error e -> Error e

     let bind r f =
       match r with
       | Ok x -> f x
       | Error e -> Error e

     let is_ok r =
       match r with
       | Ok _ -> true
       | Error _ -> false

     let is_error r =
       match r with
       | Ok _ -> false
       | Error _ -> true

     let get_ok r =
       match r with
       | Ok x -> x
       | Error _ -> failwith \"Result.get_ok: Error\"

     let get_error r =
       match r with
       | Ok _ -> failwith \"Result.get_error: Ok\"
       | Error e -> e

     let map_error f r =
       match r with
       | Ok x -> Ok x
       | Error e -> Error (f e)

     let to_option r =
       match r with
       | Ok x -> Some x
       | Error _ -> None

     let value r default =
       match r with
       | Ok x -> x
       | Error _ -> default

     let iter f r =
       match r with
       | Ok x -> f x
       | Error _ -> ()

     let fold ok_f err_f r =
       match r with
       | Ok x -> ok_f x
       | Error e -> err_f e

     let equal eq_ok eq_err a b =
       match a with
       | Ok x ->
         (match b with Ok y -> eq_ok x y | Error _ -> false)
       | Error e ->
         (match b with Ok _ -> false | Error e2 -> eq_err e e2)

     let compare cmp_ok cmp_err a b =
       match a with
       | Ok x ->
         (match b with Ok y -> cmp_ok x y | Error _ -> -1)
       | Error e ->
         (match b with Ok _ -> 1 | Error e2 -> cmp_err e e2)

     let iter_error f r =
       match r with
       | Ok _ -> ()
       | Error e -> f e
   end ;;

   module String = struct
     let length s = _string_length s
     let get s i = _string_get s i
     let sub s i n = _string_sub s i n
     let concat sep xs = _string_concat sep xs
     let uppercase_ascii s = _string_upper s
     let lowercase_ascii s = _string_lower s
     let starts_with prefix s = _string_starts_with prefix s
     let ends_with suffix s = _string_ends_with suffix s
     let contains s sub = _string_contains s sub
     let trim s = _string_trim s
     let split_on_char c s = _string_split_on_char c s
     let replace_all s a b = _string_replace s a b
     let index_of s sub = _string_index_of s sub
     let make n c =
       let rec aux i acc = if i = 0 then acc else aux (i - 1) (acc ^ c) in
       aux n \"\"
     let init n f =
       let rec aux i acc =
         if i >= n then acc else aux (i + 1) (acc ^ f i)
       in
       aux 0 \"\"
     let map f s =
       let rec aux i acc =
         if i >= _string_length s then acc
         else aux (i + 1) (acc ^ f (_string_get s i))
       in
       aux 0 \"\"
     let iter f s =
       let rec aux i =
         if i >= _string_length s then ()
         else (f (_string_get s i); aux (i + 1))
       in
       aux 0
     let iteri f s =
       let rec aux i =
         if i >= _string_length s then ()
         else (f i (_string_get s i); aux (i + 1))
       in
       aux 0
     let fold_left f init s =
       let rec aux i acc =
         if i >= _string_length s then acc
         else aux (i + 1) (f acc (_string_get s i))
       in
       aux 0 init
     let fold_right f s init =
       let rec aux i acc =
         if i < 0 then acc
         else aux (i - 1) (f (_string_get s i) acc)
       in
       aux (_string_length s - 1) init
     let to_seq s =
       let rec aux i =
         if i >= _string_length s then []
         else _string_get s i :: aux (i + 1)
       in
       aux 0
     let of_seq xs =
       let rec aux ys acc =
         match ys with
         | [] -> acc
         | h :: t -> aux t (acc ^ h)
       in
       aux xs \"\"
     let equal a b = a = b
     let compare a b =
       if a < b then -1 else if a > b then 1 else 0
     let cat a b = a ^ b
     let empty = \"\"
   end ;;

   module Bytes = struct
     (* Thin alias of String — SX has no separate immutable byte type. *)
     let length s = String.length s
     let get s i = String.get s i
     let of_string s = s
     let to_string s = s
     let concat sep xs = String.concat sep xs
     let sub s i n = String.sub s i n
   end ;;

   module Bool = struct
     let equal a b = a = b
     let compare a b =
       if a = b then 0
       else if a then 1
       else -1
     let to_string b = if b then \"true\" else \"false\"
     let of_string s = s = \"true\"
     let not_ b = not b
     let to_int b = if b then 1 else 0
   end ;;

   module Char = struct
     let code c = _char_code c
     let chr n = _char_chr n
     let lowercase_ascii c = _string_lower c
     let uppercase_ascii c = _string_upper c
     let is_digit c =
       let n = _char_code c in n >= 48 && n <= 57
     let is_lower c =
       let n = _char_code c in n >= 97 && n <= 122
     let is_upper c =
       let n = _char_code c in n >= 65 && n <= 90
     let is_alpha c = is_lower c || is_upper c
     let is_alnum c = is_alpha c || is_digit c
     let is_whitespace c =
       c = \" \" || c = \"\\t\" || c = \"\\n\" || c = \"\\r\"
     let equal a b = a = b
     let compare a b = _char_code a - _char_code b
     let escaped c =
       if c = \"\\n\" then \"\\\\n\"
       else if c = \"\\t\" then \"\\\\t\"
       else if c = \"\\r\" then \"\\\\r\"
       else if c = \"\\\\\" then \"\\\\\\\\\"
       else if c = \"\\\"\" then \"\\\\\\\"\"
       else c
   end ;;

   module Filename = struct
     (* Minimal Filename: basename / dirname / extension / concat /
        chop_suffix.  Forward-slash only — doesn't try to detect
        Windows-style separators. *)
     let _last_slash s =
       let n = _string_length s in
       let rec aux i =
         if i < 0 then -1
         else if _string_get s i = \"/\" then i
         else aux (i - 1)
       in
       aux (n - 1)

     let basename s =
       let i = _last_slash s in
       if i < 0 then s
       else _string_sub s (i + 1) (_string_length s - i - 1)

     let dirname s =
       let i = _last_slash s in
       if i < 0 then \".\"
       else if i = 0 then \"/\"
       else _string_sub s 0 i

     let extension s =
       let b = basename s in
       let n = _string_length b in
       let rec aux i =
         if i < 0 then \"\"
         else if _string_get b i = \".\" then
           _string_sub b i (n - i)
         else aux (i - 1)
       in
       aux (n - 1)

     let chop_extension s =
       let ext = extension s in
       let nx = _string_length ext in
       if nx = 0 then s
       else _string_sub s 0 (_string_length s - nx)

     let concat a b =
       if _string_length a = 0 then b
       else if _string_get a (_string_length a - 1) = \"/\" then a ^ b
       else a ^ \"/\" ^ b

     let is_relative s =
       _string_length s = 0 || _string_get s 0 <> \"/\"

     let current_dir_name = \".\"
     let parent_dir_name = \"..\"
     let dir_sep = \"/\"
   end ;;

   module Int = struct
     let to_string i = _string_of_int i
     let of_string s = _int_of_string s
     let abs n = if n < 0 then 0 - n else n
     let max a b = if a > b then a else b
     let min a b = if a < b then a else b
     let max_int = 4611686018427387903
     let min_int = -4611686018427387904
     let zero = 0
     let one = 1
     let minus_one = -1
     let succ n = n + 1
     let pred n = n - 1
     let neg n = 0 - n
     let add a b = a + b
     let sub a b = a - b
     let mul a b = a * b
     let div a b = a / b
     let rem a b = a - b * (a / b)
     let equal a b = a = b
     let compare a b = if a < b then -1 else if a > b then 1 else 0
   end ;;

   module Float = struct
     let to_string f = _string_of_float f
     let of_string s = _int_of_string s
     let sqrt f = _float_sqrt f
     let sin f = _float_sin f
     let cos f = _float_cos f
     let pow a b = _float_pow a b
     let floor f = _float_floor f
     let ceil f = _float_ceil f
     let round f = _float_round f
     let pi = 3.141592653589793
     let zero = 0.0
     let one = 1.0
     let minus_one = -1.0
     let abs f = if f < 0.0 then 0.0 -. f else f
     let neg f = 0.0 -. f
     let add a b = a +. b
     let sub a b = a -. b
     let mul a b = a *. b
     let div a b = a /. b
     let max a b = if a > b then a else b
     let min a b = if a < b then a else b
     let equal a b = a = b
     let compare a b =
       if a < b then -1 else if a > b then 1 else 0
     let to_int f = _float_floor f
     let of_int n = n
   end ;;

   module Printf = struct
     (* sprintf walks fmt char-by-char. On '%' it parses optional
        flags ('-' for left-justify, '0' for zero-pad), an optional
        decimal width, and a final spec letter. Specs supported:
        %d %i %u %s %f %c %b %x %X %o (and %% as a literal).
        Width pads the formatted argument to at least N characters. *)
     let sprintf fmt =
       let n = _string_length fmt in
       let is_spec c =
         c = \"d\" || c = \"i\" || c = \"u\" || c = \"s\" || c = \"f\"
         || c = \"c\" || c = \"b\" || c = \"x\" || c = \"X\" || c = \"o\"
       in
       let is_digit c =
         let k = _char_code c in k >= 48 && k <= 57
       in
       let pad s width left zero =
         let pad_len = width - _string_length s in
         if pad_len <= 0 then s
         else
           let ch = if zero && (not left) then \"0\" else \" \" in
           let rec mk k acc = if k = 0 then acc else mk (k - 1) (acc ^ ch) in
           let padding = mk pad_len \"\" in
           if left then s ^ padding else padding ^ s
       in
       (* Skip flag chars from p, returning new pos. Records flags in
          shared refs (set above each call). *)
       let parse_flags_loop p left_flag zero_flag =
         let i = ref p in
         let cont = ref true in
         while !cont do
           if !i < n then
             let c = _string_get fmt !i in
             if c = \"-\" then (left_flag := true; i := !i + 1)
             else if c = \"0\" then (zero_flag := true; i := !i + 1)
             else cont := false
           else cont := false
         done;
         !i
       in
       let parse_width_loop p =
         let i = ref p in
         let w = ref 0 in
         let cont = ref true in
         while !cont do
           if !i < n then
             let c = _string_get fmt !i in
             if is_digit c then
               (w := !w * 10 + (_char_code c - 48); i := !i + 1)
             else cont := false
           else cont := false
         done;
         (!w, !i)
       in
       let rec walk pos prefix =
         if pos >= n then prefix
         else if pos + 1 < n && _string_get fmt pos = \"%\" then
           if _string_get fmt (pos + 1) = \"%\" then
             walk (pos + 2) (prefix ^ \"%\")
           else
             let left_flag = ref false in
             let zero_flag = ref false in
             let after_flags = parse_flags_loop (pos + 1) left_flag zero_flag in
             let (width, spec_pos) = parse_width_loop after_flags in
             if spec_pos < n && is_spec (_string_get fmt spec_pos) then
               let spec = _string_get fmt spec_pos in
               let left = !left_flag in
               let zero = !zero_flag in
               (fun arg ->
                  let raw =
                    if spec = \"d\" || spec = \"i\" || spec = \"u\"
                      then _string_of_int arg
                    else if spec = \"f\" then _string_of_float arg
                    else if spec = \"x\" then _int_to_hex_lower arg
                    else if spec = \"X\" then _int_to_hex_upper arg
                    else if spec = \"o\" then _int_to_octal arg
                    else if spec = \"b\" then
                      (if arg then \"true\" else \"false\")
                    else arg
                  in
                  let s = pad raw width left zero in
                  walk (spec_pos + 1) (prefix ^ s))
             else walk (pos + 1) (prefix ^ _string_get fmt pos)
         else walk (pos + 1) (prefix ^ _string_get fmt pos)
       in
       walk 0 \"\"

     let printf fmt = sprintf fmt
   end ;;

   module Format = struct
     (* Thin alias of Printf for pretty-printing parity. The dynamic
        runtime doesn't distinguish boxes/breaks — fmt strings work
        the same as in Printf. *)
     let sprintf fmt = Printf.sprintf fmt
     let printf fmt = Printf.sprintf fmt
     let asprintf fmt = Printf.sprintf fmt
   end ;;

   module Random = struct
     (* Linear-congruential PRNG. Deterministic for testing — same
        seed reproduces the same sequence. Real OCaml's Random uses
        Lagged Fibonacci; ours is simpler but adequate for shuffles
        and Monte Carlo demos in baseline programs. *)
     let _state = ref 1

     let init s = _state := s

     let self_init () = _state := 1

     let int bound =
       _state := (!_state * 1103515245 + 12345) mod 2147483647;
       Int.abs (!_state) mod bound

     let bool () = int 2 = 1

     let float bound =
       let n = int 1000000 in
       float_of_int n /. 1000000.0 *. bound

     let bits () = int 1073741824
   end ;;

   module Seq = struct
     (* Eager list-backed Seq — no laziness. Real OCaml's Seq is a
        thunk producing Cons / Nil; ours is just a list. Adequate for
        most baseline programs that don't rely on infinite sequences. *)
     let empty = []
     let cons x s = x :: s
     let return x = [x]
     let is_empty s = match s with [] -> true | _ -> false

     let rec iter f s =
       match s with
       | [] -> ()
       | h :: t -> f h; iter f t

     let rec iteri f s =
       let rec go i xs =
         match xs with
         | [] -> ()
         | h :: t -> f i h; go (i + 1) t
       in
       go 0 s

     let rec map f s = match s with [] -> [] | h :: t -> f h :: map f t

     let rec filter p s =
       match s with
       | [] -> []
       | h :: t -> if p h then h :: filter p t else filter p t

     let rec filter_map f s =
       match s with
       | [] -> []
       | h :: t ->
         match f h with
         | Some v -> v :: filter_map f t
         | None -> filter_map f t

     let rec fold_left f init s =
       match s with
       | [] -> init
       | h :: t -> fold_left f (f init h) t

     let rec length s =
       match s with [] -> 0 | _ :: t -> 1 + length t

     let rec take n s =
       if n <= 0 then []
       else match s with [] -> [] | h :: t -> h :: take (n - 1) t

     let rec drop n s =
       if n <= 0 then s
       else match s with [] -> [] | _ :: t -> drop (n - 1) t

     let rec append a b =
       match a with [] -> b | h :: t -> h :: append t b

     let to_list s = s
     let of_list xs = xs

     let rec init n f =
       if n = 0 then [] else
       let rec build i = if i = n then [] else f i :: build (i + 1) in
       build 0

     let rec unfold f acc =
       match f acc with
       | None -> []
       | Some (x, acc') -> x :: unfold f acc'
   end ;;

   module Lazy = struct
     let force lz = _lazy_force lz
   end ;;

   module Array = struct
     (* Backed by a ref-of-list. Mutating set! replaces the underlying
        list with a new one in which one cell is changed. O(n) set, but
        good enough for short arrays in baseline programs. *)
     let make n v =
       let rec build i acc =
         if i = 0 then acc else build (i - 1) (v :: acc)
       in
       ref (build n [])

     let length a = List.length !a
     let get a i = List.nth !a i

     let set a i v =
       let rec replace lst k =
         match lst with
         | [] -> []
         | h :: t -> if k = 0 then v :: t else h :: replace t (k - 1)
       in
       a := replace !a i

     let init n f =
       let rec build i acc =
         if i = 0 then acc else build (i - 1) (f (i - 1) :: acc)
       in
       ref (build n [])

     let iter f a = List.iter f !a
     let iteri f a = List.iteri f !a
     let map f a = ref (List.map f !a)
     let mapi f a = ref (List.mapi f !a)
     let fold_left f init a = List.fold_left f init !a
     let to_list a = !a
     let of_list xs = ref xs
     let copy a = ref !a
     let sort cmp a = a := List.sort cmp !a
     let stable_sort = sort
     let fast_sort = sort

     let append a b = ref (List.append !a !b)

     let sub a pos n =
       let rec take xs k =
         if k = 0 then []
         else match xs with
              | [] -> []
              | h :: t -> h :: take t (k - 1)
       in
       let rec drop xs k =
         if k = 0 then xs
         else match xs with
              | [] -> []
              | _ :: t -> drop t (k - 1)
       in
       ref (take (drop !a pos) n)

     let exists p a = List.exists p !a
     let for_all p a = List.for_all p !a
     let mem x a = List.mem x !a

     let blit src si dst di n =
       for k = 0 to n - 1 do
         set dst (di + k) (get src (si + k))
       done
     let fill a pos n v =
       for k = 0 to n - 1 do set a (pos + k) v done
   end ;;

   module Stack = struct
     let create () = ref []
     let push x s = s := x :: !s
     let pop s =
       match !s with
       | [] -> failwith \"Stack.pop: empty\"
       | h :: t -> s := t ; h
     let top s =
       match !s with
       | [] -> failwith \"Stack.top: empty\"
       | h :: _ -> h
     let is_empty s = !s = []
     let length s = List.length !s
     let clear s = s := []
   end ;;

   module Queue = struct
     (* Simple two-list amortized queue: (front, back). pop drains
        front; refill from rev back when front is empty. *)
     let create () = ref ([], [])
     let push x q =
       let p = !q in
       q := (List.append [] (match p with (f, b) -> f), x :: (match p with (_, b) -> b))
     let length q =
       let p = !q in
       let f = match p with (f, _) -> f in
       let b = match p with (_, b) -> b in
       List.length f + List.length b
     let is_empty q = length q = 0
     let pop q =
       let p = !q in
       let f = match p with (f, _) -> f in
       let b = match p with (_, b) -> b in
       match f with
       | h :: t -> q := (t, b) ; h
       | [] ->
         (match List.rev b with
          | [] -> failwith \"Queue.pop: empty\"
          | h :: t -> q := (t, []) ; h)
     let clear q = q := ([], [])
   end ;;

   module Buffer = struct
     let create _ = ref []
     let add_string b s = b := s :: !b
     let add_char b c = b := c :: !b
     let contents b = String.concat \"\" (List.rev !b)
     let length b = String.length (String.concat \"\" (List.rev !b))
     let clear b = b := []
     let reset = clear
   end ;;

   module Sys = struct
     let os_type = \"SX\"
     let word_size = 64
     let max_array_length = 4611686018427387903
     let max_string_length = 4611686018427387903
     let executable_name = \"ocaml-on-sx\"
     let big_endian = false
     let unix = true
     let win32 = false
     let cygwin = false
   end ;;

   module Hashtbl = struct
     let create n = _hashtbl_create n
     let add t k v = _hashtbl_add t k v
     let replace t k v = _hashtbl_replace t k v
     let find_opt t k = _hashtbl_find_opt t k
     let find t k =
       match _hashtbl_find_opt t k with
       | None -> failwith \"Hashtbl.find: not found\"
       | Some v -> v
     let mem t k = _hashtbl_mem t k
     let length t = _hashtbl_length t

     (* iter / fold over (k, v) pairs. Keys come back as their string
        representation since the host coerces all keys via `str`. *)
     let iter f t =
       let rec go xs =
         match xs with
         | [] -> ()
         | (k, v) :: rest -> f k v; go rest
       in
       go (_hashtbl_to_list t)

     let fold f t acc =
       let rec go xs a =
         match xs with
         | [] -> a
         | (k, v) :: rest -> go rest (f k v a)
       in
       go (_hashtbl_to_list t) acc

     (* OCaml's Hashtbl doesn't expose `keys` directly — it offers
        `to_seq_keys` etc. We provide both: a plain list snapshot and
        the keys/values projections that are commonly useful. *)
     let bindings t = _hashtbl_to_list t

     let keys t = List.map (fun (k, _) -> k) (_hashtbl_to_list t)
     let values t = List.map (fun (_, v) -> v) (_hashtbl_to_list t)

     let to_seq t = _hashtbl_to_list t
     let to_seq_keys = keys
     let to_seq_values = values

     let remove t k = _hashtbl_remove t k
     let reset t = _hashtbl_clear t
     let clear t = _hashtbl_clear t

     let copy t =
       let t' = _hashtbl_create 8 in
       List.iter
         (fun (k, v) -> _hashtbl_add t' k v)
         (_hashtbl_to_list t);
       t'
   end ;;

   module Either = struct
     let left x = Left x
     let right x = Right x

     let is_left e = match e with Left _ -> true | Right _ -> false
     let is_right e = match e with Left _ -> false | Right _ -> true

     let find_left e =
       match e with Left x -> Some x | Right _ -> None
     let find_right e =
       match e with Left _ -> None | Right x -> Some x

     let map_left f e =
       match e with Left x -> Left (f x) | Right x -> Right x
     let map_right f e =
       match e with Left x -> Left x | Right x -> Right (f x)

     let fold lf rf e =
       match e with Left x -> lf x | Right x -> rf x

     let equal eq_l eq_r a b =
       match a with
       | Left x ->
         (match b with Left y -> eq_l x y | Right _ -> false)
       | Right x ->
         (match b with Left _ -> false | Right y -> eq_r x y)

     let compare cmp_l cmp_r a b =
       match a with
       | Left x ->
         (match b with Left y -> cmp_l x y | Right _ -> -1)
       | Right x ->
         (match b with Left _ -> 1 | Right y -> cmp_r x y)
   end ;;

   module Map = struct
     module Make (Ord) = struct
       let empty = []

       let rec add k v m =
         match m with
         | [] -> [(k, v)]
         | (k2, v2) :: rest ->
           begin
             let c = Ord.compare k k2 in
             if c = 0 then (k, v) :: rest
             else if c < 0 then (k, v) :: m
             else (k2, v2) :: add k v rest
           end

       let rec find_opt k m =
         match m with
         | [] -> None
         | (k2, v) :: rest ->
           if Ord.compare k k2 = 0 then Some v
           else find_opt k rest

       let find k m =
         match find_opt k m with
         | None -> failwith \"Map.find: not found\"
         | Some v -> v

       let rec mem k m =
         match m with
         | [] -> false
         | (k2, _) :: rest -> if Ord.compare k k2 = 0 then true else mem k rest

       let rec remove k m =
         match m with
         | [] -> []
         | (k2, v) :: rest ->
           if Ord.compare k k2 = 0 then rest else (k2, v) :: remove k rest

       let rec bindings m = m

       let rec cardinal m =
         match m with
         | [] -> 0
         | _ :: t -> 1 + cardinal t

       let rec iter f m =
         match m with
         | [] -> ()
         | (k, v) :: t -> f k v; iter f t

       let rec fold f m acc =
         match m with
         | [] -> acc
         | (k, v) :: t -> fold f t (f k v acc)

       let rec map f m =
         match m with
         | [] -> []
         | (k, v) :: t -> (k, f v) :: map f t

       let rec filter p m =
         match m with
         | [] -> []
         | (k, v) :: t ->
           if p k v then (k, v) :: filter p t else filter p t

       let rec is_empty m =
         match m with
         | [] -> true
         | _ -> false
     end
   end ;;

   module Set = struct
     module Make (Ord) = struct
       let empty = []

       let rec mem x s =
         match s with
         | [] -> false
         | h :: t ->
           let c = Ord.compare x h in
           if c = 0 then true
           else if c < 0 then false
           else mem x t

       let rec add x s =
         match s with
         | [] -> [x]
         | h :: t ->
           let c = Ord.compare x h in
           if c = 0 then s
           else if c < 0 then x :: s
           else h :: add x t

       let rec remove x s =
         match s with
         | [] -> []
         | h :: t ->
           if Ord.compare x h = 0 then t else h :: remove x t

       let rec elements s = s

       let rec cardinal s =
         match s with
         | [] -> 0
         | _ :: t -> 1 + cardinal t

       let rec iter f s =
         match s with
         | [] -> ()
         | h :: t -> f h; iter f t

       let rec fold f s acc =
         match s with
         | [] -> acc
         | h :: t -> fold f t (f h acc)

       let rec filter p s =
         match s with
         | [] -> []
         | h :: t -> if p h then h :: filter p t else filter p t

       let rec is_empty s =
         match s with
         | [] -> true
         | _ -> false

       let rec union a b =
         match b with
         | [] -> a
         | h :: t -> union (add h a) t

       let rec inter a b =
         match a with
         | [] -> []
         | h :: t -> if mem h b then h :: inter t b else inter t b
     end
   end ;;

   let string_of_int n = _string_of_int n
   let string_of_float f = _string_of_float f
   let string_of_bool b = if b then \"true\" else \"false\"
   let int_of_string s = _int_of_string s
   let max_int = 4611686018427387903
   let min_int = -4611686018427387904
   let abs_float f = if f < 0.0 then 0.0 -. f else f
   let float_of_int n = n
   let int_of_float f =
     if f < 0.0 then _float_ceil f else _float_floor f
   ")

(define ocaml-stdlib-loaded false)
(define ocaml-stdlib-env nil)

;; Build a stdlib env once, cache it. ocaml-run / ocaml-run-program both
;; layer the user program on top of this base env.
(define ocaml-load-stdlib!
  (fn ()
    (when (not ocaml-stdlib-loaded)
      (let ((env (ocaml-empty-env)))
        (begin
          (define run-decl
            (fn (decl)
              (let ((tag (ocaml-tag-of decl)))
                (cond
                  ((= tag "module-def")
                    (let ((mn (nth decl 1)) (ds (nth decl 2)))
                      (let ((mv (ocaml-eval-module ds env)))
                        (set! env (ocaml-env-extend env mn mv)))))
                  ((= tag "def")
                    (let ((nm (nth decl 1)) (ps (nth decl 2)) (rh (nth decl 3)))
                      (let ((v (if (= (len ps) 0)
                                   (ocaml-eval rh env)
                                   (ocaml-make-curried ps rh env))))
                        (set! env (ocaml-env-extend env nm v)))))))))
          (let ((prog (ocaml-parse-program ocaml-stdlib-src)))
            (begin
              (define loop
                (fn (xs)
                  (when (not (= xs (list)))
                    (begin (run-decl (first xs)) (loop (rest xs))))))
              (loop (rest prog))
              (set! ocaml-stdlib-env env)
              (set! ocaml-stdlib-loaded true))))))))
