summaryrefslogtreecommitdiff
path: root/lib/kernel/names.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 11:54:16 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 11:54:16 +0200
commit8b6c0036cb6c7f0e48a9370f53be25fd2bb243f4 (patch)
tree64fd346b9893fe9870785e3f91e440c952cd237d /lib/kernel/names.ml
parent57322e766a0ece579dafcddcfe2572676a98fca8 (diff)
downloadcolitur-8b6c0036cb6c7f0e48a9370f53be25fd2bb243f4.tar.gz
colitur-8b6c0036cb6c7f0e48a9370f53be25fd2bb243f4.zip
kernel: fix sexp deriving, add missing tests, canonicalize remove
Use [@@deriving sexp] with open Sexplib0.Sexp_conv instead of hand-rolling converters (fixes non-standard Citation shape and missing field validation). Names.t_of_sexp wraps derived version to enforce canonical sort on load. Add tests: - Names of_list duplicate handling - Names sexp canonical sort guarantee (identical serialization) - Names and Date_spec sexp roundtrips Fix Names.remove to canonicalize output (defensive against non-canonical input).
Diffstat (limited to 'lib/kernel/names.ml')
-rw-r--r--lib/kernel/names.ml24
1 files changed, 7 insertions, 17 deletions
diff --git a/lib/kernel/names.ml b/lib/kernel/names.ml
index 5f433ce..513d497 100644
--- a/lib/kernel/names.ml
+++ b/lib/kernel/names.ml
@@ -1,11 +1,13 @@
+open Sexplib0.Sexp_conv
+
(* Celebration names by language. An open assoc list rather than a fixed record,
so an overlay can add a language purely as data (spec ยง2.1). Kept sorted by
language code so sexp output is byte-stable. *)
-type t = (Lang.t * string) list
+type t = (Lang.t * string) list [@@deriving sexp]
let empty = []
let canonical t = List.sort (fun (a, _) (b, _) -> Lang.compare a b) t
-let remove t lang = List.filter (fun (l, _) -> not (Lang.equal l lang)) t
+let remove t lang = canonical (List.filter (fun (l, _) -> not (Lang.equal l lang)) t)
let set t lang name = canonical ((lang, name) :: remove t lang)
let of_list l = List.fold_left (fun acc (lang, name) -> set acc lang name) empty l
let find t lang = List.find_map (fun (l, n) -> if Lang.equal l lang then Some n else None) t
@@ -14,18 +16,6 @@ let rec find_first t = function
| lang :: rest -> ( match find t lang with Some n -> Some n | None -> find_first t rest)
let to_list t = t
-let sexp_of_t t =
- Sexplib0.Sexp_conv.sexp_of_list (fun (lang, name) ->
- Sexplib0.Sexp.List [ Lang.sexp_of_t lang; Sexplib0.Sexp_conv.sexp_of_string name ])
- t
-
-let t_of_sexp sexp =
- let list = Sexplib0.Sexp_conv.list_of_sexp (fun sexp ->
- match sexp with
- | Sexplib0.Sexp.List [ lang_sexp; name_sexp ] ->
- let lang = Lang.t_of_sexp lang_sexp in
- let name = Sexplib0.Sexp_conv.string_of_sexp name_sexp in
- (lang, name)
- | _ -> Sexplib0.Sexp_conv.of_sexp_error "Names.t_of_sexp: expected [lang_sexp name_sexp]" sexp)
- sexp in
- canonical list
+(* Wrap the derived t_of_sexp to enforce canonical sorting on load. *)
+let t_of_sexp_derived = t_of_sexp
+let t_of_sexp sexp = canonical (t_of_sexp_derived sexp)