diff options
Diffstat (limited to 'lib/rites')
| -rw-r--r-- | lib/rites/rite_of/precedence_of.ml | 97 | ||||
| -rw-r--r-- | lib/rites/rite_of/precedence_of.mli | 40 |
2 files changed, 137 insertions, 0 deletions
diff --git a/lib/rites/rite_of/precedence_of.ml b/lib/rites/rite_of/precedence_of.ml new file mode 100644 index 0000000..bca6ca9 --- /dev/null +++ b/lib/rites/rite_of/precedence_of.ml @@ -0,0 +1,97 @@ +(* The Tabula dierum liturgicorum secundum ordinem praecedentiae disposita + (Missale Romanum, editio typica tertia 2002; "Normae universales de anno + liturgico et de calendario", printed immediately before it) -- 13 numbered + entries in three parts. This module transcribes it, one [band] branch per + entry, the same discipline Rite_ef.Precedence_ef applies to RG 91's 28. + + CITATION DISCIPLINE: the 2002 Missal PDF carries BOTH the Normae universales + AND the Institutio Generalis Missalis Romani, each independently numbered + from 1. Every citation below therefore names its document: "Normae n. N" or + "IGMR n. N". A bare "n. N" is ambiguous and must not appear. + + ENTRY VALUES ARE THE TABLE'S OWN NUMBER TIMES TEN (entry 1 -> 10, entry 13 + -> 130). Identical to Precedence_ef's own convention and adopted for the + identical reason: a future sub-rank (a movable/fixed split of one row, the + shape RG 91 entry 14 forced on the EF side) becomes an ordinary position + BETWEEN neighbours, with no rescale of every other branch. Do NOT express a + sub-rank as a negative sentinel: Precedence_ef's own history records that as + a defect, because a negative value avoids collision but inverts ORDERING. *) + +open Colitur_kernel + +let unclassified = max_int + +(* Not a Normae citation. The Tabula distinguishes universal-calendar entries + (3, 7, 10) from proper-calendar ones (4, 8, 11), and nothing in + Celebration.t marks that distinction except [layer]. Same mechanism, and + same naming, as Precedence_ef.{universal_layer,indult_prefix}. *) +let universal_layer = "of-universal" +let proper_prefix = "proper:" +let is_universal layer = String.equal layer universal_layer +let is_proper layer = String.starts_with ~prefix:proper_prefix layer + +(* Days measured from Easter, so the Triduum and the Easter Octave are + identified STRUCTURALLY rather than by slug. Temporal_of emits Good Friday + and Holy Saturday as ordinary Lent week-6 ferias + ("of-lent-6-friday"/"of-lent-6-saturday"), so there is no slug to key on -- + the same situation Precedence_ef.band faces for RG 91 entry 2, resolved the + same way. *) +let easter_offset (ctx : Vocab_of.season Precedence.context) = + let y = Date.year ctx.date in + Date.to_rata ctx.date - Date.to_rata (Computus.gregorian_easter y) + +let slug_of (c : Vocab_of.rank Precedence.candidate) = Slug.to_string c.cel.slug + +(* Tabula I.1: "Triduum paschale Passionis et Resurrectionis Domini." + + HOLY THURSDAY IS DELIBERATELY NOT HERE. The Tabula's own entry 2 reads + "Feriae Hebdomadae sanctae, a feria II ad feriam V inclusive" -- Monday + through THURSDAY inclusive -- and the Paschal Triduum begins with the + evening Mass of the Lord's Supper, an event INSIDE Holy Thursday's civil + day. At colitur's civil-day granularity (one office per date, never a + sub-day boundary) the day itself therefore stays with the Holy Week ferias + at entry 2. This is the SAME granularity decision, on the precedence axis, + that data/of/expected-divergences-litcal.sexp's own L1 records on the season + axis (Normae nn. 28/30) -- one decision with two visible consequences, not + two independent judgements. *) +let is_triduum ctx = List.mem (easter_offset ctx) [ -2; -1; 0 ] + +(* Tabula I.2, five clauses in one entry. *) +let entry_2_named = + [ "of-nativity"; "of-epiphany"; "of-ascension"; "of-pentecost"; "of-ash-wednesday" ] + +let is_privileged_sunday (ctx : Vocab_of.season Precedence.context) c = + ctx.weekday = Date.Sun + && (match ctx.season with + | Vocab_of.Advent | Vocab_of.Lent | Vocab_of.Easter -> true + | Vocab_of.Christmas | Vocab_of.Ordinary_time -> false) + && c.Precedence.origin = Precedence.Temporal + +(* "Feriae Hebdomadae sanctae, a feria II ad feriam V inclusive": Easter-6 + (Monday) through Easter-3 (Thursday). Palm Sunday (Easter-7) is a Sunday of + Lent, covered by [is_privileged_sunday] in the same entry. *) +let is_holy_week_feria ctx = List.mem (easter_offset ctx) [ -6; -5; -4; -3 ] + +(* "Dies infra octavam Paschae": Easter+1 .. Easter+7. Easter Sunday itself is + entry 1. *) +let is_easter_octave_day ctx = + let o = easter_offset ctx in + o >= 1 && o <= 7 + +let band (ctx : Vocab_of.season Precedence.context) + (c : Vocab_of.rank Precedence.candidate) : int = + let temporal = c.Precedence.origin = Precedence.Temporal in + let layer = c.cel.layer in + if temporal && is_triduum ctx then 10 (* Tabula I.1 *) + else if + temporal + && (List.mem (slug_of c) entry_2_named + || is_privileged_sunday ctx c + || is_holy_week_feria ctx + || is_easter_octave_day ctx) + then 20 (* Tabula I.2 *) + else if c.cel.rank = Vocab_of.Sollemnitas && is_universal layer then + 30 (* Tabula I.3 *) + else if c.cel.rank = Vocab_of.Sollemnitas && is_proper layer then + 40 (* Tabula I.4 *) + else unclassified diff --git a/lib/rites/rite_of/precedence_of.mli b/lib/rites/rite_of/precedence_of.mli new file mode 100644 index 0000000..dfee504 --- /dev/null +++ b/lib/rites/rite_of/precedence_of.mli @@ -0,0 +1,40 @@ +(** The Tabula dierum liturgicorum of the 2002 Missale Romanum -- 13 numbered + entries in three parts -- plus Normae n. 60's occurrence and transfer + rules. The OF counterpart of {!Rite_ef.Precedence_ef}, and deliberately + the same shape. + + Every citation names its document ("Normae n. N" or "IGMR n. N"): the + 2002 Missal carries both, independently numbered from 1. *) + +open Colitur_kernel + +(** Returned for a candidate shape the Tabula has no row for. [max_int], so an + unclassified candidate always loses. Task 4's property asserts this is + never reached by anything {!Rite_of.Temporal_of} constructs. *) +val unclassified : int + +(** The universal (General Roman Calendar) layer id. Not a Normae citation: + the Tabula distinguishes universal entries (3, 7, 10) from proper ones + (4, 8, 11), and [Celebration.t.layer] is the only field carrying that + distinction. *) +val universal_layer : string + +(** Prefix marking a candidate as belonging to a PROPER (diocesan, national or + religious) calendar -- Tabula entries 4, 8 and 11. + + NO SHIPPED DATA PRODUCES THIS. Phase 3 transcribes the General Roman + Calendar only (the spec's own universal-calendar-only discipline), so + entries 4, 8 and 11 are unreachable on shipped data and are exercised in + tests by synthetic candidates alone. They are transcribed anyway for two + reasons: the transcription of a 13-entry table should be complete rather + than silently 10 entries long, and a user [--overlay] carrying a local + patron becomes correct without a later edit here. *) +val proper_prefix : string + +(** [band ctx c]: the Tabula's own entry number for [c], TIMES TEN (entry 1 -> + 10, entry 13 -> 130); lower wins. {!unclassified} for a shape with no row. + + The ×10 scaling matches {!Rite_ef.Precedence_ef.band} and exists for the + same reason: a future sub-rank fits between neighbours without rescaling + the table. *) +val band : Vocab_of.season Precedence.context -> Vocab_of.rank Precedence.candidate -> int |
