From 346c3650d750ba3dc48d5b42c0eeb1d125a8cbb5 Mon Sep 17 00:00:00 2001 From: Mathieu Barbin Date: Mon, 16 Mar 2026 14:19:37 +0100 Subject: [PATCH 1/2] Flatten stdlib modules into individual ${name}0 files Extract each module from volgo_stdlib into its own file (absolute_path0, array0, bool0, char0, fsegment0, hashtbl0, int0, list0, option0, ordering0, queue0, relative_path0, result0, sexp0, string0), introduce stdlib0 as the alias aggregator, and reduce volgo_stdlib to `include Stdlib0`. This matches the pattern used in mdexp. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/stdlib/absolute_path0.ml | 9 + src/stdlib/absolute_path0.mli | 11 + src/stdlib/array0.ml | 49 ++++ src/stdlib/array0.mli | 14 ++ src/stdlib/bool0.ml | 9 + src/stdlib/bool0.mli | 11 + src/stdlib/char0.ml | 17 ++ src/stdlib/char0.mli | 10 + src/stdlib/fsegment0.ml | 9 + src/stdlib/fsegment0.mli | 11 + src/stdlib/hashtbl0.ml | 59 +++++ src/stdlib/hashtbl0.mli | 22 ++ src/stdlib/int0.ml | 42 ++++ src/stdlib/int0.mli | 14 ++ src/stdlib/list0.ml | 27 ++ src/stdlib/list0.mli | 21 ++ src/stdlib/option0.ml | 12 + src/stdlib/option0.mli | 12 + src/stdlib/ordering0.ml | 13 + src/stdlib/ordering0.mli | 11 + src/stdlib/queue0.ml | 10 + src/stdlib/queue0.mli | 10 + src/stdlib/relative_path0.ml | 9 + src/stdlib/relative_path0.mli | 11 + src/stdlib/result0.ml | 31 +++ src/stdlib/result0.mli | 19 ++ src/stdlib/sexp0.ml | 12 + src/stdlib/sexp0.mli | 11 + src/stdlib/stdlib0.ml | 89 +++++++ src/stdlib/stdlib0.mli | 67 +++++ src/stdlib/string0.ml | 95 +++++++ src/stdlib/string0.mli | 20 ++ src/stdlib/volgo_stdlib.ml | 452 +--------------------------------- src/stdlib/volgo_stdlib.mli | 213 +--------------- 34 files changed, 770 insertions(+), 662 deletions(-) create mode 100644 src/stdlib/absolute_path0.ml create mode 100644 src/stdlib/absolute_path0.mli create mode 100644 src/stdlib/array0.ml create mode 100644 src/stdlib/array0.mli create mode 100644 src/stdlib/bool0.ml create mode 100644 src/stdlib/bool0.mli create mode 100644 src/stdlib/char0.ml create mode 100644 src/stdlib/char0.mli create mode 100644 src/stdlib/fsegment0.ml create mode 100644 src/stdlib/fsegment0.mli create mode 100644 src/stdlib/hashtbl0.ml create mode 100644 src/stdlib/hashtbl0.mli create mode 100644 src/stdlib/int0.ml create mode 100644 src/stdlib/int0.mli create mode 100644 src/stdlib/list0.ml create mode 100644 src/stdlib/list0.mli create mode 100644 src/stdlib/option0.ml create mode 100644 src/stdlib/option0.mli create mode 100644 src/stdlib/ordering0.ml create mode 100644 src/stdlib/ordering0.mli create mode 100644 src/stdlib/queue0.ml create mode 100644 src/stdlib/queue0.mli create mode 100644 src/stdlib/relative_path0.ml create mode 100644 src/stdlib/relative_path0.mli create mode 100644 src/stdlib/result0.ml create mode 100644 src/stdlib/result0.mli create mode 100644 src/stdlib/sexp0.ml create mode 100644 src/stdlib/sexp0.mli create mode 100644 src/stdlib/stdlib0.ml create mode 100644 src/stdlib/stdlib0.mli create mode 100644 src/stdlib/string0.ml create mode 100644 src/stdlib/string0.mli diff --git a/src/stdlib/absolute_path0.ml b/src/stdlib/absolute_path0.ml new file mode 100644 index 0000000..1d4043e --- /dev/null +++ b/src/stdlib/absolute_path0.ml @@ -0,0 +1,9 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Absolute_path + +let to_dyn t = Dyn.string (Absolute_path.to_string t) diff --git a/src/stdlib/absolute_path0.mli b/src/stdlib/absolute_path0.mli new file mode 100644 index 0000000..7a26c54 --- /dev/null +++ b/src/stdlib/absolute_path0.mli @@ -0,0 +1,11 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of struct + include Absolute_path +end + +val to_dyn : t -> Dyn.t diff --git a/src/stdlib/array0.ml b/src/stdlib/array0.ml new file mode 100644 index 0000000..1648c21 --- /dev/null +++ b/src/stdlib/array0.ml @@ -0,0 +1,49 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include ArrayLabels + +let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_array +let create ~len a = make len a + +let filter_mapi t ~f = + let out_count = ref 0 in + let out = ref [] in + iteri t ~f:(fun i a -> + match f i a with + | None -> () + | Some e -> + incr out_count; + out := e :: !out); + match !out with + | [] -> [||] + | hd :: _ -> + let out_count = !out_count in + let res = create ~len:out_count hd in + List.iteri (fun i a -> res.(out_count - 1 - i) <- a) !out; + res +;; + +let rev a = + let len = length a in + let res = create ~len a.(0) in + iteri a ~f:(fun i x -> res.(len - 1 - i) <- x); + res +;; + +let sort t ~compare = sort t ~cmp:compare + +let[@tail_mod_cons] rec to_list_mapi_aux t ~f ~index ~len = + if index >= len + then [] + else ( + let elt = Array.unsafe_get t index in + (* Coverage is off in the second part of the expression because the + instrumentation breaks [@tail_mod_cons], triggering warning 71. *) + f index elt :: (to_list_mapi_aux t ~f ~index:(index + 1) ~len [@coverage off])) +;; + +let to_list_mapi t ~f = to_list_mapi_aux t ~f ~index:0 ~len:(Array.length t) diff --git a/src/stdlib/array0.mli b/src/stdlib/array0.mli new file mode 100644 index 0000000..258584f --- /dev/null +++ b/src/stdlib/array0.mli @@ -0,0 +1,14 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of ArrayLabels + +val to_list_mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b list +val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t +val create : len:int -> 'a -> 'a array +val filter_mapi : 'a array -> f:(int -> 'a -> 'b option) -> 'b array +val rev : 'a array -> 'a array +val sort : 'a array -> compare:('a -> 'a -> int) -> unit diff --git a/src/stdlib/bool0.ml b/src/stdlib/bool0.ml new file mode 100644 index 0000000..a9ecb76 --- /dev/null +++ b/src/stdlib/bool0.ml @@ -0,0 +1,9 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Bool + +let to_dyn = Dyn.bool diff --git a/src/stdlib/bool0.mli b/src/stdlib/bool0.mli new file mode 100644 index 0000000..7b00eec --- /dev/null +++ b/src/stdlib/bool0.mli @@ -0,0 +1,11 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of struct + include Stdlib.Bool +end + +val to_dyn : t -> Dyn.t diff --git a/src/stdlib/char0.ml b/src/stdlib/char0.ml new file mode 100644 index 0000000..8833d53 --- /dev/null +++ b/src/stdlib/char0.ml @@ -0,0 +1,17 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Char + +let is_alphanum = function + | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' -> true + | _ -> false +;; + +let is_whitespace = function + | '\t' | '\n' | '\011' (* vertical tab *) | '\012' (* form feed *) | '\r' | ' ' -> true + | _ -> false +;; diff --git a/src/stdlib/char0.mli b/src/stdlib/char0.mli new file mode 100644 index 0000000..04baf5c --- /dev/null +++ b/src/stdlib/char0.mli @@ -0,0 +1,10 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of Char + +val is_alphanum : char -> bool +val is_whitespace : char -> bool diff --git a/src/stdlib/fsegment0.ml b/src/stdlib/fsegment0.ml new file mode 100644 index 0000000..543ad21 --- /dev/null +++ b/src/stdlib/fsegment0.ml @@ -0,0 +1,9 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Fsegment + +let to_dyn t = Dyn.string (Fsegment.to_string t) diff --git a/src/stdlib/fsegment0.mli b/src/stdlib/fsegment0.mli new file mode 100644 index 0000000..3f279b2 --- /dev/null +++ b/src/stdlib/fsegment0.mli @@ -0,0 +1,11 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of struct + include Fsegment +end + +val to_dyn : t -> Dyn.t diff --git a/src/stdlib/hashtbl0.ml b/src/stdlib/hashtbl0.ml new file mode 100644 index 0000000..398ca3c --- /dev/null +++ b/src/stdlib/hashtbl0.ml @@ -0,0 +1,59 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include ( + MoreLabels.Hashtbl : + module type of MoreLabels.Hashtbl with module Make := MoreLabels.Hashtbl.Make) + +module type S_extended = sig + include MoreLabels.Hashtbl.S + + val add_exn : 'a t -> key:key -> data:'a -> unit + val add_multi : 'a list t -> key:key -> data:'a -> unit + val find : 'a t -> key -> 'a option + val set : 'a t -> key:key -> data:'a -> unit +end + +exception E of Sexp.t + +let () = + Sexplib0.Sexp_conv.Exn_converter.add [%extension_constructor E] (function + | E sexp -> sexp + | _ -> assert false) +;; + +module Make (H : sig + include Hashtbl.HashedType + + val sexp_of_t : t -> Sexp.t + end) = +struct + include MoreLabels.Hashtbl.Make (H) + + let add_exn t ~key ~data = + if mem t key + then + raise + (E + (List + [ Atom "Hashtbl.add_exn: key already present" + ; Sexp.List [ Atom "key"; H.sexp_of_t key ] + ])) + else add t ~key ~data + ;; + + let add_multi t ~key ~data = + let data = + match find_opt t key with + | None -> [ data ] + | Some l -> data :: l + in + replace t ~key ~data + ;; + + let find = find_opt + let set = replace +end diff --git a/src/stdlib/hashtbl0.mli b/src/stdlib/hashtbl0.mli new file mode 100644 index 0000000..65aff93 --- /dev/null +++ b/src/stdlib/hashtbl0.mli @@ -0,0 +1,22 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of MoreLabels.Hashtbl with module Make := MoreLabels.Hashtbl.Make + +module type S_extended = sig + include MoreLabels.Hashtbl.S + + val add_exn : 'a t -> key:key -> data:'a -> unit + val add_multi : 'a list t -> key:key -> data:'a -> unit + val find : 'a t -> key -> 'a option + val set : 'a t -> key:key -> data:'a -> unit +end + +module Make (H : sig + include Hashtbl.HashedType + + val sexp_of_t : t -> Sexp.t + end) : S_extended with type key = H.t diff --git a/src/stdlib/int0.ml b/src/stdlib/int0.ml new file mode 100644 index 0000000..3d29628 --- /dev/null +++ b/src/stdlib/int0.ml @@ -0,0 +1,42 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +open! Stdlib_compat +include Int + +let incr = incr +let max_value = max_int +let of_string_opt = int_of_string_opt + +let to_string_hum n = + let s = string_of_int n in + let len = String.length s in + let is_negative = n < 0 in + let sign_count = if is_negative then 1 else 0 in + let absolute_digit_count = if is_negative then len - 1 else len in + let separator_count = absolute_digit_count / 3 in + let initial_skip_count = + let digit_skip = absolute_digit_count mod 3 in + sign_count + if digit_skip > 0 then digit_skip else 3 + in + let buffer = Buffer.create (len + separator_count) in + let rec aux i count = + if i < len + then + if count = 0 + then ( + Buffer.add_char buffer '_'; + aux i 3) + else ( + Buffer.add_char buffer s.[i]; + aux (i + 1) (count - 1)) + in + aux 0 initial_skip_count; + Buffer.contents buffer +;; + +let to_dyn t = Dyn.Int t +let sexp_of_t t = Sexp.Atom (to_string_hum t) diff --git a/src/stdlib/int0.mli b/src/stdlib/int0.mli new file mode 100644 index 0000000..30b7230 --- /dev/null +++ b/src/stdlib/int0.mli @@ -0,0 +1,14 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of Int + +val sexp_of_t : t -> Sexp.t +val to_dyn : t -> Dyn.t +val incr : int ref -> unit +val max_value : int +val of_string_opt : string -> int option +val to_string_hum : int -> string diff --git a/src/stdlib/list0.ml b/src/stdlib/list0.ml new file mode 100644 index 0000000..f256c09 --- /dev/null +++ b/src/stdlib/list0.ml @@ -0,0 +1,27 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +open! Stdlib_compat +include ListLabels + +let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_list +let concat_map t ~f = concat_map ~f t +let dedup_and_sort t ~compare = sort_uniq t ~cmp:compare + +let hd = function + | [] -> None + | hd :: _ -> Some hd +;; + +let filter_opt t = filter_map t ~f:Fun.id +let find t ~f = find_opt t ~f +let find_map t ~f = find_map ~f t +let fold t ~init ~f = fold_left ~f ~init t +let iter t ~f = iter t ~f +let map t ~f = map ~f t +let mapi t ~f = mapi ~f t +let sort t ~compare = sort t ~cmp:compare +let count t ~f = fold t ~init:0 ~f:(fun acc e -> acc + if f e then 1 else 0) diff --git a/src/stdlib/list0.mli b/src/stdlib/list0.mli new file mode 100644 index 0000000..3456529 --- /dev/null +++ b/src/stdlib/list0.mli @@ -0,0 +1,21 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of ListLabels + +val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t +val concat_map : 'a list -> f:('a -> 'b list) -> 'b list +val count : 'a list -> f:('a -> bool) -> int +val dedup_and_sort : 'a list -> compare:('a -> 'a -> int) -> 'a list +val filter_opt : 'a option list -> 'a list +val find : 'a list -> f:('a -> bool) -> 'a option +val find_map : 'a list -> f:('a -> 'b option) -> 'b option +val fold : 'a list -> init:'b -> f:('b -> 'a -> 'b) -> 'b +val hd : 'a list -> 'a option +val iter : 'a list -> f:('a -> unit) -> unit +val map : 'a list -> f:('a -> 'b) -> 'b list +val mapi : 'a list -> f:(int -> 'a -> 'b) -> 'b list +val sort : 'a list -> compare:('a -> 'a -> int) -> 'a list diff --git a/src/stdlib/option0.ml b/src/stdlib/option0.ml new file mode 100644 index 0000000..7abd792 --- /dev/null +++ b/src/stdlib/option0.ml @@ -0,0 +1,12 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Option + +let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_option +let iter t ~f = iter f t +let map t ~f = map f t +let some_if cond a = if cond then Some a else None diff --git a/src/stdlib/option0.mli b/src/stdlib/option0.mli new file mode 100644 index 0000000..c43fbde --- /dev/null +++ b/src/stdlib/option0.mli @@ -0,0 +1,12 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of Option + +val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t +val iter : 'a t -> f:('a -> unit) -> unit +val map : 'a option -> f:('a -> 'b) -> 'b option +val some_if : bool -> 'a -> 'a option diff --git a/src/stdlib/ordering0.ml b/src/stdlib/ordering0.ml new file mode 100644 index 0000000..764fbde --- /dev/null +++ b/src/stdlib/ordering0.ml @@ -0,0 +1,13 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Ordering + +let to_dyn = function + | Lt -> Dyn.Variant ("Lt", []) + | Eq -> Dyn.Variant ("Eq", []) + | Gt -> Dyn.Variant ("Gt", []) +;; diff --git a/src/stdlib/ordering0.mli b/src/stdlib/ordering0.mli new file mode 100644 index 0000000..361eb6d --- /dev/null +++ b/src/stdlib/ordering0.mli @@ -0,0 +1,11 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of struct + include Ordering +end + +val to_dyn : t -> Dyn.t diff --git a/src/stdlib/queue0.ml b/src/stdlib/queue0.ml new file mode 100644 index 0000000..c48281d --- /dev/null +++ b/src/stdlib/queue0.ml @@ -0,0 +1,10 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Queue + +let enqueue t a = push a t +let to_list t = t |> to_seq |> List.of_seq diff --git a/src/stdlib/queue0.mli b/src/stdlib/queue0.mli new file mode 100644 index 0000000..9c1bb0b --- /dev/null +++ b/src/stdlib/queue0.mli @@ -0,0 +1,10 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of Queue + +val enqueue : 'a t -> 'a -> unit +val to_list : 'a t -> 'a list diff --git a/src/stdlib/relative_path0.ml b/src/stdlib/relative_path0.ml new file mode 100644 index 0000000..195daad --- /dev/null +++ b/src/stdlib/relative_path0.ml @@ -0,0 +1,9 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Relative_path + +let to_dyn t = Dyn.string (Relative_path.to_string t) diff --git a/src/stdlib/relative_path0.mli b/src/stdlib/relative_path0.mli new file mode 100644 index 0000000..d9aaca7 --- /dev/null +++ b/src/stdlib/relative_path0.mli @@ -0,0 +1,11 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of struct + include Relative_path +end + +val to_dyn : t -> Dyn.t diff --git a/src/stdlib/result0.ml b/src/stdlib/result0.ml new file mode 100644 index 0000000..08f2b01 --- /dev/null +++ b/src/stdlib/result0.ml @@ -0,0 +1,31 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +type ('a, 'b) t = ('a, 'b) Result.t = + | Ok of 'a + | Error of 'b + +let sexp_of_t sexp_of_a sexp_of_b = function + | Ok a -> Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "Ok"; sexp_of_a a ] + | Error b -> Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "Error"; sexp_of_b b ] +;; + +include (Result : module type of Result with type ('a, 'b) t := ('a, 'b) t) + +module Syntax = struct + let ( let* ) = Result.bind +end + +let map t ~f = map f t +let map_error t ~f = map_error f t + +let of_option t ~error = + match t with + | Some v -> Ok v + | None -> Error error +;; + +let return = ok diff --git a/src/stdlib/result0.mli b/src/stdlib/result0.mli new file mode 100644 index 0000000..b59d7b1 --- /dev/null +++ b/src/stdlib/result0.mli @@ -0,0 +1,19 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of Result + +module Syntax : sig + (*_ This is in the stdlib but only since [5.4]. We export it here to support + older versions. *) + val ( let* ) : ('a, 'e) t -> ('a -> ('b, 'e) t) -> ('b, 'e) t +end + +val sexp_of_t : ('a -> Sexp.t) -> ('b -> Sexp.t) -> ('a, 'b) Result.t -> Sexp.t +val map : ('a, 'e) Result.t -> f:('a -> 'b) -> ('b, 'e) Result.t +val map_error : ('a, 'e1) Result.t -> f:('e1 -> 'e2) -> ('a, 'e2) Result.t +val of_option : 'a option -> error:'e -> ('a, 'e) Result.t +val return : 'a -> ('a, _) Result.t diff --git a/src/stdlib/sexp0.ml b/src/stdlib/sexp0.ml new file mode 100644 index 0000000..6a01810 --- /dev/null +++ b/src/stdlib/sexp0.ml @@ -0,0 +1,12 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +include Sexp + +let rec to_dyn = function + | Sexp.Atom s -> Dyn.variant "Atom" [ Dyn.string s ] + | Sexp.List l -> Dyn.variant "List" [ Dyn.list to_dyn l ] +;; diff --git a/src/stdlib/sexp0.mli b/src/stdlib/sexp0.mli new file mode 100644 index 0000000..9cd1e6f --- /dev/null +++ b/src/stdlib/sexp0.mli @@ -0,0 +1,11 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of struct + include Sexp +end + +val to_dyn : t -> Dyn.t diff --git a/src/stdlib/stdlib0.ml b/src/stdlib/stdlib0.ml new file mode 100644 index 0000000..41f8b6b --- /dev/null +++ b/src/stdlib/stdlib0.ml @@ -0,0 +1,89 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +module Absolute_path = Absolute_path0 +module Array = Array0 +module Bool = Bool0 +module Char = Char0 +module Code_error = Code_error +module Dyn = Dyn0 +module Fsegment = Fsegment0 +module Hashtbl = Hashtbl0 +module Int = Int0 +module List = List0 +module Option = Option0 +module Ordering = Ordering0 +module Queue = Queue0 +module Relative_path = Relative_path0 +module Result = Result0 +module Sexp = Sexp0 +module String = String0 + +module Dynable = struct + module type S = sig + type t + + val to_dyn : t -> Dyn.t + end +end + +module type To_sexpable = sig + type t + + val sexp_of_t : t -> Sexp.t +end + +let sexp_field' (type a) (sexp_of_a : a -> Sexp.t) field a = + Sexp.List [ Atom field; sexp_of_a a ] +;; + +let sexp_field (type a) (module M : To_sexpable with type t = a) field a = + sexp_field' M.sexp_of_t field a +;; + +module With_equal_and_dyn = struct + module type S = sig + type t + + val equal : t -> t -> bool + val to_dyn : t -> Dyn.t + end +end + +let print pp = Format.printf "%a@." Pp.to_fmt pp +let print_dyn dyn = print (Dyn.pp dyn) +let phys_equal a b = a == b +let require cond = if not cond then failwith "Required condition does not hold." + +let require_does_raise f = + match f () with + | _ -> Code_error.raise "Did not raise." [] + | exception e -> print_endline (Printexc.to_string e) +;; + +let require_equal + (type a) + (module M : With_equal_and_dyn.S with type t = a) + (v1 : a) + (v2 : a) + = + if not (M.equal v1 v2) + then Code_error.raise "Values are not equal." [ "v1", M.to_dyn v1; "v2", M.to_dyn v2 ] +;; + +let require_not_equal + (type a) + (module M : With_equal_and_dyn.S with type t = a) + (v1 : a) + (v2 : a) + = + if M.equal v1 v2 + then Code_error.raise "Values are equal." [ "v1", M.to_dyn v1; "v2", M.to_dyn v2 ] +;; + +(* {1 Transition API} *) + +let print_s sexp = print_endline (Sexp.to_string_hum sexp) diff --git a/src/stdlib/stdlib0.mli b/src/stdlib/stdlib0.mli new file mode 100644 index 0000000..33ba7ca --- /dev/null +++ b/src/stdlib/stdlib0.mli @@ -0,0 +1,67 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +module Absolute_path = Absolute_path0 +module Array = Array0 +module Bool = Bool0 +module Char = Char0 +module Code_error = Code_error +module Dyn = Dyn0 +module Fsegment = Fsegment0 +module Hashtbl = Hashtbl0 +module Int = Int0 +module List = List0 +module Option = Option0 +module Ordering = Ordering0 +module Queue = Queue0 +module Relative_path = Relative_path0 +module Result = Result0 +module Sexp = Sexp0 +module String = String0 + +module Dynable : sig + module type S = sig + type t + + val to_dyn : t -> Dyn.t + end +end + +val print_dyn : Dyn.t -> unit +val phys_equal : 'a -> 'a -> bool + +module type To_sexpable = sig + type t + + val sexp_of_t : t -> Sexp.t +end + +val sexp_field : (module To_sexpable with type t = 'a) -> string -> 'a -> Sexp.t +val sexp_field' : ('a -> Sexp.t) -> string -> 'a -> Sexp.t + +module With_equal_and_dyn : sig + module type S = sig + type t + + val equal : t -> t -> bool + val to_dyn : t -> Dyn.t + end +end + +(** {1 Test helpers} *) + +val require : bool -> unit +val require_does_raise : (unit -> 'a) -> unit +val require_equal : (module With_equal_and_dyn.S with type t = 'a) -> 'a -> 'a -> unit +val require_not_equal : (module With_equal_and_dyn.S with type t = 'a) -> 'a -> 'a -> unit + +(** {1 Transition API} + + Functions in this section are exported to smooth transitions and refactor as + we rework the exact set of third-party dependencies for the volgo project. + They may be removed or renamed in the future. *) + +val print_s : Sexp.t -> unit diff --git a/src/stdlib/string0.ml b/src/stdlib/string0.ml new file mode 100644 index 0000000..ffd2fc6 --- /dev/null +++ b/src/stdlib/string0.ml @@ -0,0 +1,95 @@ +(*********************************************************************************) +(* Volgo - A Versatile OCaml Library for Git Operations *) +(* SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*********************************************************************************) + +(* Some functions are copied from [Base] version [v0.17] which is released + under MIT and may be found at [https://github.com/janestreet/base]. + + See [volgo_stdlib.ml] for the full MIT license notice from Jane Street. + + When this is the case, we clearly indicate it next to the copied function. *) + +open! Stdlib_compat +module Char = Char0 +include StringLabels + +let to_dyn = Dyn.string +let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_string +let to_string t = t + +let chop_prefix t ~prefix = + if starts_with ~prefix t + then ( + let prefix_len = length prefix in + Some (sub t ~pos:prefix_len ~len:(length t - prefix_len))) + else None +;; + +let chop_suffix t ~suffix = + if ends_with ~suffix t + then Some (sub t ~pos:0 ~len:(length t - length suffix)) + else None +;; + +let is_empty t = length t = 0 + +let lsplit2 t ~on = + match index_from_opt t 0 on with + | None -> None + | Some i -> Some (sub t ~pos:0 ~len:i, sub t ~pos:(i + 1) ~len:(length t - i - 1)) +;; + +let rsplit2 t ~on = + let len = length t in + match rindex_from_opt t (len - 1) on with + | None -> None + | Some i -> Some (sub t ~pos:0 ~len:i, sub t ~pos:(i + 1) ~len:(len - i - 1)) +;; + +(* The function [split_lines] below was copied from [Base.String0.split_lines] + version [v0.17] which is released under MIT and may be found at + [https://github.com/janestreet/base]. + + The changes we made were minimal: + + - Changed references to [Char0] to [Char]. + + See notice at the top of the file and project global notice for licensing + information. *) + +let split_lines = + let back_up_at_newline ~t ~pos ~eol = + pos := !pos - if !pos > 0 && Char.equal t.[!pos - 1] '\r' then 2 else 1; + eol := !pos + 1 + in + fun t -> + let n = length t in + if n = 0 + then [] + else ( + (* Invariant: [-1 <= pos < eol]. *) + let pos = ref (n - 1) in + let eol = ref n in + let ac = ref [] in + (* We treat the end of the string specially, because if the string ends with a + newline, we don't want an extra empty string at the end of the output. *) + if Char.equal t.[!pos] '\n' then back_up_at_newline ~t ~pos ~eol; + while !pos >= 0 do + if not (Char.equal t.[!pos] '\n') + then decr pos + else ( + (* Because [pos < eol], we know that [start <= eol]. *) + let start = !pos + 1 in + ac := sub t ~pos:start ~len:(!eol - start) :: !ac; + back_up_at_newline ~t ~pos ~eol) + done; + sub t ~pos:0 ~len:!eol :: !ac) +;; + +(* ---------------------------------------------------------------------------- *) + +let split t ~on = split_on_char ~sep:on t +let strip = trim +let uncapitalize = uncapitalize_ascii diff --git a/src/stdlib/string0.mli b/src/stdlib/string0.mli new file mode 100644 index 0000000..1d39e04 --- /dev/null +++ b/src/stdlib/string0.mli @@ -0,0 +1,20 @@ +(*_********************************************************************************) +(*_ Volgo - A Versatile OCaml Library for Git Operations *) +(*_ SPDX-FileCopyrightText: 2024-2026 Mathieu Barbin *) +(*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) +(*_********************************************************************************) + +include module type of StringLabels + +val to_dyn : t -> Dyn.t +val sexp_of_t : t -> Sexp.t +val to_string : string -> string +val chop_prefix : string -> prefix:string -> string option +val chop_suffix : string -> suffix:string -> string option +val is_empty : string -> bool +val lsplit2 : string -> on:char -> (string * string) option +val rsplit2 : string -> on:char -> (string * string) option +val split_lines : string -> string list +val split : string -> on:char -> string list +val strip : string -> string +val uncapitalize : string -> string diff --git a/src/stdlib/volgo_stdlib.ml b/src/stdlib/volgo_stdlib.ml index cafcc82..c138451 100644 --- a/src/stdlib/volgo_stdlib.ml +++ b/src/stdlib/volgo_stdlib.ml @@ -4,454 +4,4 @@ (* SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) (*********************************************************************************) -(* Some functions are copied from [Base] version [v0.17] which is released - under MIT and may be found at [https://github.com/janestreet/base]. - - See Base's LICENSE below: - - ---------------------------------------------------------------------------- - - The MIT License - - Copyright (c) 2016--2024 Jane Street Group, LLC - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - ---------------------------------------------------------------------------- - - When this is the case, we clearly indicate it next to the copied function. *) - -open! Stdlib_compat -module Code_error = Code_error -module Dyn = Dyn0 - -module Dynable = struct - module type S = sig - type t - - val to_dyn : t -> Dyn.t - end -end - -let print pp = Format.printf "%a@." Pp.to_fmt pp -let print_dyn dyn = print (Dyn.pp dyn) -let phys_equal a b = a == b - -module Ordering = struct - include Ordering - - let to_dyn = function - | Lt -> Dyn.Variant ("Lt", []) - | Eq -> Dyn.Variant ("Eq", []) - | Gt -> Dyn.Variant ("Gt", []) - ;; -end - -module Sexp = struct - include Sexp - - let rec to_dyn = function - | Sexp.Atom s -> Dyn.variant "Atom" [ Dyn.string s ] - | Sexp.List l -> Dyn.variant "List" [ Dyn.list to_dyn l ] - ;; -end - -module type To_sexpable = sig - type t - - val sexp_of_t : t -> Sexp.t -end - -let sexp_field' (type a) (sexp_of_a : a -> Sexp.t) field a = - Sexp.List [ Atom field; sexp_of_a a ] -;; - -let sexp_field (type a) (module M : To_sexpable with type t = a) field a = - sexp_field' M.sexp_of_t field a -;; - -module Absolute_path = struct - include Absolute_path - - let to_dyn t = Dyn.string (Absolute_path.to_string t) -end - -module Array = struct - include ArrayLabels - - let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_array - let create ~len a = make len a - - let filter_mapi t ~f = - let out_count = ref 0 in - let out = ref [] in - iteri t ~f:(fun i a -> - match f i a with - | None -> () - | Some e -> - incr out_count; - out := e :: !out); - match !out with - | [] -> [||] - | hd :: _ -> - let out_count = !out_count in - let res = create ~len:out_count hd in - List.iteri (fun i a -> res.(out_count - 1 - i) <- a) !out; - res - ;; - - let rev a = - let len = length a in - let res = create ~len a.(0) in - iteri a ~f:(fun i x -> res.(len - 1 - i) <- x); - res - ;; - - let sort t ~compare = sort t ~cmp:compare - - let[@tail_mod_cons] rec to_list_mapi_aux t ~f ~index ~len = - if index >= len - then [] - else ( - let elt = Array.unsafe_get t index in - (* Coverage is off in the second part of the expression because the - instrumentation breaks [@tail_mod_cons], triggering warning 71. *) - f index elt :: (to_list_mapi_aux t ~f ~index:(index + 1) ~len [@coverage off])) - ;; - - let to_list_mapi t ~f = to_list_mapi_aux t ~f ~index:0 ~len:(Array.length t) -end - -module Bool = struct - include Bool - - let to_dyn = Dyn.bool -end - -module Char = struct - include Char - - let is_alphanum = function - | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' -> true - | _ -> false - ;; - - let is_whitespace = function - | '\t' | '\n' | '\011' (* vertical tab *) | '\012' (* form feed *) | '\r' | ' ' -> - true - | _ -> false - ;; -end - -module Fsegment = struct - include Fsegment - - let to_dyn t = Dyn.string (Fsegment.to_string t) -end - -module Hashtbl = struct - include ( - MoreLabels.Hashtbl : - module type of MoreLabels.Hashtbl with module Make := MoreLabels.Hashtbl.Make) - - module type S_extended = sig - include MoreLabels.Hashtbl.S - - val add_exn : 'a t -> key:key -> data:'a -> unit - val add_multi : 'a list t -> key:key -> data:'a -> unit - val find : 'a t -> key -> 'a option - val set : 'a t -> key:key -> data:'a -> unit - end - - exception E of Sexp.t - - let () = - Sexplib0.Sexp_conv.Exn_converter.add [%extension_constructor E] (function - | E sexp -> sexp - | _ -> assert false) - ;; - - module Make (H : sig - include Hashtbl.HashedType - - val sexp_of_t : t -> Sexp.t - end) = - struct - include MoreLabels.Hashtbl.Make (H) - - let add_exn t ~key ~data = - if mem t key - then - raise - (E - (List - [ Atom "Hashtbl.add_exn: key already present" - ; sexp_field (module H) "key" key - ])) - else add t ~key ~data - ;; - - let add_multi t ~key ~data = - let data = - match find_opt t key with - | None -> [ data ] - | Some l -> data :: l - in - replace t ~key ~data - ;; - - let find = find_opt - let set = replace - end -end - -module Int = struct - include Int - - let incr = incr - let max_value = max_int - let of_string_opt = int_of_string_opt - - let to_string_hum n = - let s = string_of_int n in - let len = String.length s in - let is_negative = n < 0 in - let sign_count = if is_negative then 1 else 0 in - let absolute_digit_count = if is_negative then len - 1 else len in - let separator_count = absolute_digit_count / 3 in - let initial_skip_count = - let digit_skip = absolute_digit_count mod 3 in - sign_count + if digit_skip > 0 then digit_skip else 3 - in - let buffer = Buffer.create (len + separator_count) in - let rec aux i count = - if i < len - then - if count = 0 - then ( - Buffer.add_char buffer '_'; - aux i 3) - else ( - Buffer.add_char buffer s.[i]; - aux (i + 1) (count - 1)) - in - aux 0 initial_skip_count; - Buffer.contents buffer - ;; - - let to_dyn t = Dyn.Int t - let sexp_of_t t = Sexp.Atom (to_string_hum t) -end - -module List = struct - include ListLabels - - let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_list - let concat_map t ~f = concat_map ~f t - let dedup_and_sort t ~compare = sort_uniq t ~cmp:compare - - let hd = function - | [] -> None - | hd :: _ -> Some hd - ;; - - let filter_opt t = filter_map t ~f:Fun.id - let find t ~f = find_opt t ~f - let find_map t ~f = find_map ~f t - let fold t ~init ~f = fold_left ~f ~init t - let iter t ~f = iter t ~f - let map t ~f = map ~f t - let mapi t ~f = mapi ~f t - let sort t ~compare = sort t ~cmp:compare - let count t ~f = fold t ~init:0 ~f:(fun acc e -> acc + if f e then 1 else 0) -end - -module Option = struct - include Option - - let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_option - let iter t ~f = iter f t - let map t ~f = map f t - let some_if cond a = if cond then Some a else None -end - -module Queue = struct - include Queue - - let enqueue t a = push a t - let to_list t = t |> to_seq |> List.of_seq -end - -module Relative_path = struct - include Relative_path - - let to_dyn t = Dyn.string (Relative_path.to_string t) -end - -module Result = struct - type ('a, 'b) t = ('a, 'b) Result.t = - | Ok of 'a - | Error of 'b - - let sexp_of_t sexp_of_a sexp_of_b = function - | Ok a -> Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "Ok"; sexp_of_a a ] - | Error b -> Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "Error"; sexp_of_b b ] - ;; - - include (Result : module type of Result with type ('a, 'b) t := ('a, 'b) t) - - module Syntax = struct - let ( let* ) = Result.bind - end - - let map t ~f = map f t - let map_error t ~f = map_error f t - - let of_option t ~error = - match t with - | Some v -> Ok v - | None -> Error error - ;; - - let return = ok -end - -module String = struct - include StringLabels - - let to_dyn = Dyn.string - let sexp_of_t = Sexplib0.Sexp_conv.sexp_of_string - let to_string t = t - - let chop_prefix t ~prefix = - if starts_with ~prefix t - then ( - let prefix_len = length prefix in - Some (sub t ~pos:prefix_len ~len:(length t - prefix_len))) - else None - ;; - - let chop_suffix t ~suffix = - if ends_with ~suffix t - then Some (sub t ~pos:0 ~len:(length t - length suffix)) - else None - ;; - - let is_empty t = length t = 0 - - let lsplit2 t ~on = - match index_from_opt t 0 on with - | None -> None - | Some i -> Some (sub t ~pos:0 ~len:i, sub t ~pos:(i + 1) ~len:(length t - i - 1)) - ;; - - let rsplit2 t ~on = - let len = length t in - match rindex_from_opt t (len - 1) on with - | None -> None - | Some i -> Some (sub t ~pos:0 ~len:i, sub t ~pos:(i + 1) ~len:(len - i - 1)) - ;; - - (* The function [split_lines] below was copied from [Base.String0.split_lines] - version [v0.17] which is released under MIT and may be found at - [https://github.com/janestreet/base]. - - The changes we made were minimal: - - - Changed references to [Char0] to [Char]. - - See notice at the top of the file and project global notice for licensing - information. *) - - let split_lines = - let back_up_at_newline ~t ~pos ~eol = - pos := !pos - if !pos > 0 && Char.equal t.[!pos - 1] '\r' then 2 else 1; - eol := !pos + 1 - in - fun t -> - let n = length t in - if n = 0 - then [] - else ( - (* Invariant: [-1 <= pos < eol]. *) - let pos = ref (n - 1) in - let eol = ref n in - let ac = ref [] in - (* We treat the end of the string specially, because if the string ends with a - newline, we don't want an extra empty string at the end of the output. *) - if Char.equal t.[!pos] '\n' then back_up_at_newline ~t ~pos ~eol; - while !pos >= 0 do - if not (Char.equal t.[!pos] '\n') - then decr pos - else ( - (* Because [pos < eol], we know that [start <= eol]. *) - let start = !pos + 1 in - ac := sub t ~pos:start ~len:(!eol - start) :: !ac; - back_up_at_newline ~t ~pos ~eol) - done; - sub t ~pos:0 ~len:!eol :: !ac) - ;; - - (* ---------------------------------------------------------------------------- *) - - let split t ~on = split_on_char ~sep:on t - let strip = trim - let uncapitalize = uncapitalize_ascii -end - -module With_equal_and_dyn = struct - module type S = sig - type t - - val equal : t -> t -> bool - val to_dyn : t -> Dyn.t - end -end - -let require cond = if not cond then failwith "Required condition does not hold." - -let require_does_raise f = - match f () with - | _ -> Code_error.raise "Did not raise." [] - | exception e -> print_endline (Printexc.to_string e) -;; - -let require_equal - (type a) - (module M : With_equal_and_dyn.S with type t = a) - (v1 : a) - (v2 : a) - = - if not (M.equal v1 v2) - then Code_error.raise "Values are not equal." [ "v1", M.to_dyn v1; "v2", M.to_dyn v2 ] -;; - -let require_not_equal - (type a) - (module M : With_equal_and_dyn.S with type t = a) - (v1 : a) - (v2 : a) - = - if M.equal v1 v2 - then Code_error.raise "Values are equal." [ "v1", M.to_dyn v1; "v2", M.to_dyn v2 ] -;; - -(* {1 Transition API} *) - -let print_s sexp = print_endline (Sexp.to_string_hum sexp) +include Stdlib0 diff --git a/src/stdlib/volgo_stdlib.mli b/src/stdlib/volgo_stdlib.mli index 1c3b9e6..5497689 100644 --- a/src/stdlib/volgo_stdlib.mli +++ b/src/stdlib/volgo_stdlib.mli @@ -18,215 +18,6 @@ without following semver or any other stability and backward compatibility guidelines. *) -open! Stdlib_compat -module Code_error = Code_error -module Dyn = Dyn0 - -module Dynable : sig - module type S = sig - type t - - val to_dyn : t -> Dyn.t - end -end - -val print_dyn : Dyn.t -> unit -val phys_equal : 'a -> 'a -> bool - -module Ordering : sig - include module type of struct - include Ordering - end - - val to_dyn : t -> Dyn.t -end - -module Absolute_path : sig - include module type of struct - include Absolute_path - end - - val to_dyn : t -> Dyn.t -end - -module Array : sig - include module type of ArrayLabels - - val to_list_mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b list - val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t - val create : len:int -> 'a -> 'a array - val filter_mapi : 'a array -> f:(int -> 'a -> 'b option) -> 'b array - val rev : 'a array -> 'a array - val sort : 'a array -> compare:('a -> 'a -> int) -> unit -end - -module Bool : sig - include module type of struct - include Stdlib.Bool - end - - val to_dyn : t -> Dyn.t -end - -module Char : sig - include module type of Char - - val is_alphanum : char -> bool - val is_whitespace : char -> bool -end - -module Fsegment : sig - include module type of struct - include Fsegment - end - - val to_dyn : t -> Dyn.t -end - -module Hashtbl : sig - include module type of MoreLabels.Hashtbl with module Make := MoreLabels.Hashtbl.Make - - module type S_extended = sig - include MoreLabels.Hashtbl.S - - val add_exn : 'a t -> key:key -> data:'a -> unit - val add_multi : 'a list t -> key:key -> data:'a -> unit - val find : 'a t -> key -> 'a option - val set : 'a t -> key:key -> data:'a -> unit - end - - module Make (H : sig - include Hashtbl.HashedType - - val sexp_of_t : t -> Sexp.t - end) : S_extended with type key = H.t -end - -module Int : sig - include module type of Int - - val sexp_of_t : t -> Sexp.t - val to_dyn : t -> Dyn.t - val incr : int ref -> unit - val max_value : int - val of_string_opt : string -> int option - val to_string_hum : int -> string -end - -module List : sig - include module type of ListLabels - - val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t - val concat_map : 'a list -> f:('a -> 'b list) -> 'b list - val count : 'a list -> f:('a -> bool) -> int - val dedup_and_sort : 'a list -> compare:('a -> 'a -> int) -> 'a list - val filter_opt : 'a option list -> 'a list - val find : 'a list -> f:('a -> bool) -> 'a option - val find_map : 'a list -> f:('a -> 'b option) -> 'b option - val fold : 'a list -> init:'b -> f:('b -> 'a -> 'b) -> 'b - val hd : 'a list -> 'a option - val iter : 'a list -> f:('a -> unit) -> unit - val map : 'a list -> f:('a -> 'b) -> 'b list - val mapi : 'a list -> f:(int -> 'a -> 'b) -> 'b list - val sort : 'a list -> compare:('a -> 'a -> int) -> 'a list +include module type of struct + include Stdlib0 end - -module Option : sig - include module type of Option - - val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t - val iter : 'a t -> f:('a -> unit) -> unit - val map : 'a option -> f:('a -> 'b) -> 'b option - val some_if : bool -> 'a -> 'a option -end - -module Queue : sig - include module type of Queue - - val enqueue : 'a t -> 'a -> unit - val to_list : 'a t -> 'a list -end - -module Relative_path : sig - include module type of struct - include Relative_path - end - - val to_dyn : t -> Dyn.t -end - -module Result : sig - include module type of Result - - module Syntax : sig - (*_ This is in the stdlib but only since [5.4]. We export it here to support - older versions. *) - val ( let* ) : ('a, 'e) t -> ('a -> ('b, 'e) t) -> ('b, 'e) t - end - - val sexp_of_t : ('a -> Sexp.t) -> ('b -> Sexp.t) -> ('a, 'b) Result.t -> Sexp.t - val map : ('a, 'e) Result.t -> f:('a -> 'b) -> ('b, 'e) Result.t - val map_error : ('a, 'e1) Result.t -> f:('e1 -> 'e2) -> ('a, 'e2) Result.t - val of_option : 'a option -> error:'e -> ('a, 'e) Result.t - val return : 'a -> ('a, _) Result.t -end - -module String : sig - include module type of StringLabels - - val to_dyn : t -> Dyn.t - val sexp_of_t : t -> Sexp.t - val to_string : string -> string - val chop_prefix : string -> prefix:string -> string option - val chop_suffix : string -> suffix:string -> string option - val is_empty : string -> bool - val lsplit2 : string -> on:char -> (string * string) option - val rsplit2 : string -> on:char -> (string * string) option - val split_lines : string -> string list - val split : string -> on:char -> string list - val strip : string -> string - val uncapitalize : string -> string -end - -(** {1 Sexp helper} *) - -module type To_sexpable = sig - type t - - val sexp_of_t : t -> Sexp.t -end - -val sexp_field : (module To_sexpable with type t = 'a) -> string -> 'a -> Sexp.t -val sexp_field' : ('a -> Sexp.t) -> string -> 'a -> Sexp.t - -module Sexp : sig - include module type of struct - include Sexp - end - - val to_dyn : t -> Dyn.t -end - -(** {1 Test helpers} *) - -module With_equal_and_dyn : sig - module type S = sig - type t - - val equal : t -> t -> bool - val to_dyn : t -> Dyn.t - end -end - -val require : bool -> unit -val require_does_raise : (unit -> 'a) -> unit -val require_equal : (module With_equal_and_dyn.S with type t = 'a) -> 'a -> 'a -> unit -val require_not_equal : (module With_equal_and_dyn.S with type t = 'a) -> 'a -> 'a -> unit - -(** {1 Transition API} - - Functions in this section are exported to smooth transitions and refactor as - we rework the exact set of third-party dependencies for the volgo project. - They may be removed or renamed in the future. *) - -val print_s : Sexp.t -> unit From c9b72ee0d841a2ba1d7aaa4f548f39b1d851574a Mon Sep 17 00:00:00 2001 From: Mathieu Barbin Date: Tue, 17 Mar 2026 16:08:09 +0100 Subject: [PATCH 2/2] Retrieve missing compatibility annotations lost during the code move --- src/stdlib/int0.mli | 1 + src/stdlib/list0.mli | 1 + src/stdlib/string0.mli | 1 + 3 files changed, 3 insertions(+) diff --git a/src/stdlib/int0.mli b/src/stdlib/int0.mli index 30b7230..cb65457 100644 --- a/src/stdlib/int0.mli +++ b/src/stdlib/int0.mli @@ -4,6 +4,7 @@ (*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) (*_********************************************************************************) +open! Stdlib_compat include module type of Int val sexp_of_t : t -> Sexp.t diff --git a/src/stdlib/list0.mli b/src/stdlib/list0.mli index 3456529..2734b51 100644 --- a/src/stdlib/list0.mli +++ b/src/stdlib/list0.mli @@ -4,6 +4,7 @@ (*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) (*_********************************************************************************) +open! Stdlib_compat include module type of ListLabels val sexp_of_t : ('a -> Sexp.t) -> 'a t -> Sexp.t diff --git a/src/stdlib/string0.mli b/src/stdlib/string0.mli index 1d39e04..bfa95e4 100644 --- a/src/stdlib/string0.mli +++ b/src/stdlib/string0.mli @@ -4,6 +4,7 @@ (*_ SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception *) (*_********************************************************************************) +open! Stdlib_compat include module type of StringLabels val to_dyn : t -> Dyn.t