aboutsummaryrefslogtreecommitdiff
path: root/tools/bootstrap_lectionary_of.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 23:53:49 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 23:53:58 +0200
commit90584d87e763789808329847c46dbaa8e22dca47 (patch)
tree6b5e7c29adc0d1cf5fdfb71cfb8f097867bf04b5 /tools/bootstrap_lectionary_of.ml
parent9ebb06983b7a26db5564302253f2551dfbcf834e (diff)
downloadcolitur-90584d87e763789808329847c46dbaa8e22dca47.tar.gz
colitur-90584d87e763789808329847c46dbaa8e22dca47.zip
fix(citation): represent chapter-crossing verse ranges (W4)
Parse.verse_range's [last] endpoint gains an optional chapter (Parse.verse_end: { chapter : int option; verse : verse_num }), so a hyphen range whose two endpoints lie in different chapters ("1 John 1:5-2:2") can be represented at all. Rejected: a bare [int option] living alongside [last] as a second field on verse_range -- that would let 'a chapter with no verse' exist as a constructible value. parse_part now splits a part's leading "chapter:" at the FIRST colon only (not every colon), so the verses side can itself carry a second colon from a crossing range. parse_range detects a crossing by checking whether the range's right-hand side contains ':', and skips the same-chapter descending-range guard for that case (a later chapter is always "ahead", whatever its own verse numbers are). Handles the compound shape too -- a crossing range followed by further, same-chapter verse references in the same comma list ("Matthew 9:35-10:1,5a,6-8") -- since those trailing pieces parse as ordinary bare verses/ranges, unaffected by the preceding crossing. Render's one_range renders a crossing [last] through the same chapter_verse template one_part already uses for the part's own leading "chapter:verses", so a style that reconfigures the chapter/verse separator renders a crossing endpoint in that same convention rather than a hardcoded ':'. This closes the W4 known-wrong: 41 (now 49, after an intervening Second-reading extraction) of the OF lectionary's citations printed unconverted, every one this exact shape. test_citation_coverage_of.ml's pinned residual is now empty and asserted exactly, over the full 1725-field data/of/lectionary.sexp population, including the round-trip check (parse -> render -> parse structural equality). test_citation.ml gains direct parse-suite cases for the basic crossing, the compound shape, a mid-list crossing, a crossing with a sub-verse letter, and a malformed-crossing rejection. data/of/lectionary.sexp is regenerated via its own generator (tools/bootstrap_lectionary_of.ml, whose own embedded header text is updated to match); only comment lines change, confirmed by diff -- no lectionary entry differs. test_lectionary_of.ml's whole-file SHA-256 pin is updated to match. EF is unaffected: data/ef/ is untouched since v1.0.0, and a direct byte comparison of `colitur day`/`colitur readings` for 2026, 1583 and 9999 against a git-worktree build of 1c0137d is identical on all six outputs.
Diffstat (limited to 'tools/bootstrap_lectionary_of.ml')
-rw-r--r--tools/bootstrap_lectionary_of.ml51
1 files changed, 27 insertions, 24 deletions
diff --git a/tools/bootstrap_lectionary_of.ml b/tools/bootstrap_lectionary_of.ml
index 83019b1..3ba54df 100644
--- a/tools/bootstrap_lectionary_of.ml
+++ b/tools/bootstrap_lectionary_of.ml
@@ -904,14 +904,17 @@ let temporal_day_gap ~lectionary ~year_start =
-> {!Colitur_citation.Parse.parse} on a miss). Disclosed here, at
generation time, rather than left for a reader to discover as a silent
"- | -"-shaped surprise or an unconverted English fragment sitting next
- to Latin ones -- this is what I2's own review finding asked for as the
- minimum acceptable fix if full conversion could not be reached, and it
- was not: see test/test_citation_coverage_of.ml for the pinned, exact
- residual and book.ml's own citation for why it remains (chapter-crossing
- hyphen ranges -- "2:29-3:6" -- a {!Colitur_citation.Parse.t} shape this
- parser does not represent, deliberately not built this task; every OTHER
- shape this file's data used to expose, including 345 previously-
- unregistered book names, is now fixed at the source). *)
+ to Latin ones.
+
+ W4 (this task): the residual I2/I7 found here -- a hyphenated verse
+ range whose two endpoints lie in different chapters ("2:29-3:6") -- is
+ now CLOSED. {!Colitur_citation.Parse.verse_end} lets a range's [last]
+ name its own, later chapter, and {!Colitur_citation.Render} renders it
+ back through the part's own [chapter_verse] template; the compound
+ shape (a crossing range followed by further same-chapter verses in the
+ same comma list, "Matthew 9:35-10:1,5a,6-8") is handled too. See
+ test/test_citation_coverage_of.ml for the (now empty) pinned residual,
+ still asserted exactly rather than merely "at least these fail". *)
let citation_conversion_census lect =
let total = ref 0 and bad = ref [] in
List.iter
@@ -1055,20 +1058,21 @@ pairs -> %d colitur slugs mapped, %d ini bases genuinely excluded (structurally\
; ferial (Lectionary_of.readings' own step 2 -> step 3) -- this is\n\
; OLM norms working as designed for a saint with no proper of\n\
; their own, not a gap in this data.\n\
- ; (4) Citation-siglum conversion (fix wave I2, 2026-08-26 review): of\n\
- ; %d emitted (First, Second, Gospel) citation fields, %d distinct\n\
- ; references (out of the full %d) do not parse -- every one a\n\
- ; hyphen range that crosses a chapter boundary (\"2:29-3:6\"), a\n\
- ; {!Colitur_citation.Parse.t} shape this parser's [part]/\n\
- ; [verse_range] types do not represent, deliberately not built\n\
- ; this task (see book.ml's own [is_single_chapter] neighbourhood\n\
- ; for what WAS fixed: 345 previously-unregistered book names and\n\
- ; verse sub-letter markers, both closed at the parser/book-table\n\
- ; level, not here). Such a reference still prints, verbatim,\n\
- ; never a crash or a dropped citation -- {!Colitur_citation.Sigla\n\
- ; .format}'s own documented contract on a parse miss. Pinned\n\
- ; exactly, both directions, by test/test_citation_coverage_of.ml.\n\
- ; Named below.\n\
+ ; (4) Citation-siglum conversion (fix wave I2, 2026-08-26 review;\n\
+ ; CLOSED by W4): of %d emitted (First, Second, Gospel) citation\n\
+ ; fields, %d distinct references (out of the full %d) do not\n\
+ ; parse. I2/I7 left 49 unconverted here, every one a hyphen\n\
+ ; range crossing a chapter boundary (\"2:29-3:6\"); W4 gave\n\
+ ; {!Colitur_citation.Parse.t} a [verse_end] so a range's [last]\n\
+ ; can name its own, later chapter (see book.ml's own\n\
+ ; [is_single_chapter] neighbourhood for the other, earlier fix:\n\
+ ; 345 previously-unregistered book names and verse sub-letter\n\
+ ; markers, closed at the parser/book-table level). A reference\n\
+ ; that still fails to parse would still print verbatim, never a\n\
+ ; crash or a dropped citation -- {!Colitur_citation.Sigla\n\
+ ; .format}'s own documented contract on a parse miss -- but none\n\
+ ; does today. Pinned exactly, both directions, by\n\
+ ; test/test_citation_coverage_of.ml. Named below (if any).\n\
; (5) Second-reading coverage (fix wave I7, 2026-08-26): %d of the\n\
; %d emitted citation fields above are a Second reading -- every\n\
; one from a SUNDAY-CYCLE (-A/-B/-C, i.e. Sunday/solemnity)\n\
@@ -1092,8 +1096,7 @@ pairs -> %d colitur slugs mapped, %d ini bases genuinely excluded (structurally\
cit_total (List.length cit_bad) cit_total second_count cit_total src dst;
Printf.fprintf oc "; Unmapped lectio bases (%d):\n" (List.length report.unmapped);
List.iter (fun b -> Printf.fprintf oc "; %s\n" b) report.unmapped;
- Printf.fprintf oc "; Citations that do not parse (%d distinct, all chapter-crossing ranges):\n"
- (List.length cit_bad);
+ Printf.fprintf oc "; Citations that do not parse (%d distinct):\n" (List.length cit_bad);
List.iter (fun r -> Printf.fprintf oc "; %s\n" r) cit_bad;
Printf.fprintf oc "; Temporal_of slugs (2004-2051) with no lectionary entry (%d, informational --\n\
; most are the Christmas-season/late-Advent date-vs-weekday gap named above):\n"