Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
Both take an inner predicate / comparator and walk both lists in
lockstep:
equal eq a b short-circuits on first mismatch
compare cmp a b -1 if a is a strict prefix
1 if b is
0 if both empty
otherwise first non-zero element comparison
Mirrors real OCaml's signatures.
List.equal (=) [1;2;3] [1;2;3] = true
List.equal (=) [1;2;3] [1;2;4] = false
List.compare compare [1;2;3] [1;2;4] = -1
List.compare compare [1;2] [1;2;3] = -1
List.compare compare [] [] = 0
1183 lines
32 KiB
Plaintext
1183 lines
32 KiB
Plaintext
;; 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
|
|
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 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
|
|
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
|
|
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 = 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))))))))
|