aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-20 15:44:29 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-20 15:44:29 +0200
commit987175105ead0ea78b960c0e638a81c6fd2384cf (patch)
tree15411786075824f2f7c4154fc23493d225963080 /lib
parentec70286daa72fd2a2a78a1cbab0fe2c268e5c743 (diff)
downloadcolitur-987175105ead0ea78b960c0e638a81c6fd2384cf.tar.gz
colitur-987175105ead0ea78b960c0e638a81c6fd2384cf.zip
feat(citation): the Sigla facade, total by construction
format never raises and returns an unparseable citation unchanged, so a gap degrades to today's behaviour rather than to a crash. The coverage test asserts separately that no shipped citation takes that path. verbatim is what --raw uses: an identity name table would still reformat punctuation and renumber, which would break byte-exact diffing against lectio. The existing citation-coverage walk (1970-2070) now also drives a round-trip check in the same pass: parse -> render -> parse must reach the same structure, using Book.default_spelling for names (Book.to_string returns the internal id, which is not a registered token and cannot be read back). Proved with a mutation: changing the default style's part_sep to a separator the parser does not accept reddened the round-trip case on 31 multi-part citations and nothing else; reverted.
Diffstat (limited to 'lib')
-rw-r--r--lib/citation/sigla.ml22
-rw-r--r--lib/citation/sigla.mli30
2 files changed, 52 insertions, 0 deletions
diff --git a/lib/citation/sigla.ml b/lib/citation/sigla.ml
new file mode 100644
index 0000000..a4f4555
--- /dev/null
+++ b/lib/citation/sigla.ml
@@ -0,0 +1,22 @@
+(* SPDX-License-Identifier: AGPL-3.0-or-later *)
+
+type t =
+ | Verbatim
+ | Styled of {
+ style : Render.style;
+ tradition : Book.tradition;
+ names : Book.id -> [ `Full | `Abbr ] -> string;
+ }
+
+let verbatim = Verbatim
+let make ~style ~tradition ~names = Styled { style; tradition; names }
+
+let format t s =
+ match t with
+ | Verbatim -> s
+ | Styled { style; tradition; names } -> (
+ match Parse.parse s with
+ | Error _ -> s
+ | Ok c ->
+ let c = { c with Parse.book = Book.map tradition c.Parse.book } in
+ Render.render style ~names c)
diff --git a/lib/citation/sigla.mli b/lib/citation/sigla.mli
new file mode 100644
index 0000000..d21877a
--- /dev/null
+++ b/lib/citation/sigla.mli
@@ -0,0 +1,30 @@
+(* SPDX-License-Identifier: AGPL-3.0-or-later *)
+
+(** The whole citation pipeline as one TOTAL function, so a call site needs
+ one value and one call rather than a parse/map/render dance.
+
+ {!format} never raises and never drops text: a citation that does not
+ parse is returned UNCHANGED. That combination is deliberate -- graceful
+ in production, while [test_citation_coverage.ml] asserts strictly that
+ no shipped citation actually takes that path. *)
+
+type t
+
+val make :
+ style:Render.style ->
+ tradition:Book.tradition ->
+ names:(Book.id -> [ `Full | `Abbr ] -> string) ->
+ t
+
+(** Returns every citation exactly as given. This is what [--raw] uses, the
+ same shape as {!Colitur_naming.Lang.raw}: raw output is one value passed
+ around, not a special case threaded through every call site.
+
+ [--raw] must NOT merely use an identity name table -- that would still
+ reformat punctuation and apply a tradition. Byte-exact output is what
+ makes [--raw] usable for diffing against lectio, and it also keeps the
+ raw view independent of the parser, so a parser bug cannot corrupt the
+ output used to diagnose it. *)
+val verbatim : t
+
+val format : t -> string -> string