summaryrefslogtreecommitdiff
path: root/lib/kernel/names.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 11:37:32 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 11:37:32 +0200
commit57322e766a0ece579dafcddcfe2572676a98fca8 (patch)
tree0e6ca11d29000b956a2c4bb65e436b0eb9251809 /lib/kernel/names.ml
parent270be2561ae440cea814566b74712750352e56e4 (diff)
downloadcolitur-57322e766a0ece579dafcddcfe2572676a98fca8.tar.gz
colitur-57322e766a0ece579dafcddcfe2572676a98fca8.zip
kernel: Names, Citation and Date_spec
Names is an open language-keyed assoc kept in canonical order so equal name sets serialise identically. Citation carries references only, never text. Date_spec ships the one form the EF sanctoral needs; 29 February is constructible and resolves to None in common years.
Diffstat (limited to 'lib/kernel/names.ml')
-rw-r--r--lib/kernel/names.ml31
1 files changed, 31 insertions, 0 deletions
diff --git a/lib/kernel/names.ml b/lib/kernel/names.ml
new file mode 100644
index 0000000..5f433ce
--- /dev/null
+++ b/lib/kernel/names.ml
@@ -0,0 +1,31 @@
+(* 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
+
+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 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
+let rec find_first t = function
+ | [] -> None
+ | 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