aboutsummaryrefslogtreecommitdiff
path: root/lib/kernel/overlay_ini.mli
blob: bace93b7e26902402847f940fa80efee4985ed08 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(** A flat INI front end for overlay files.

    This is a CONVENIENCE FORMAT, not a second data model. It parses to exactly
    the {!Overlay.t} the S-expression form parses to, and everything downstream
    -- merge, diagnostics, validation -- is the same code on the same values.
    There is deliberately no second semantics to keep in step.

    It is also deliberately LESS EXPRESSIVE than the sexp form. It covers [Add],
    [Suppress] and single-field [Edit], which is what a diocesan or parish
    calendar needs; [Replace], multi-field edits and citation edits are not
    expressible and the parser says so by name rather than failing obscurely.
    Anything it cannot say is a reason to write sexp, not a reason to grow this.

    {1 Format}

    Section names are slugs. A [\[overlay\]] section carries the file's id.

    {v
    [overlay]
    id = my-parish

    [our-patron]
    date    = 07-11
    rank    = class-3
    colour  = white
    name.en = St Example, Patron

    [some-universal-slug]
    suppress = yes
    v}

    Dates take three forms, matching {!Date_spec}: [MM-DD], [easter+N] or
    [easter-N], and [mon/day/nth] such as [oct/sun/1] or [oct/sun/-1]. *)

(** [parse ~rank_of_string text] is the overlay [text] denotes.

    [rank_of_string] is supplied by the rite, exactly as [Overlay.load] takes
    [rank_of_sexp]: the kernel does not know one rite's rank vocabulary from
    another's.

    Errors carry the section name and the offending value, never a source-file
    path -- this format exists for people who are not reading the source. *)
val parse :
  rank_of_string:(string -> 'r option) -> string -> ('r Overlay.t, string) result

(** [to_sexp_string t] renders [t] as the S-expression form, with a header
    noting that it was generated. *)
val to_sexp_string : ('r -> Sexplib0.Sexp.t) -> 'r Overlay.t -> string

(** [convert ~rank_of_string ~rank_to_sexp ~rank_of_sexp text] parses [text],
    renders it, and PROVES the rendering before returning it: the emitted text
    is parsed back with the very function the engine uses to load an overlay,
    and the result must equal what the INI denoted.

    That check is the point of this module. A transpiler that emits
    syntactically valid but semantically wrong output is the failure mode a
    convenience format invites, and it is one [colitur check] could not catch,
    since the emitted file would parse cleanly and simply mean something else.
    Verifying the round trip here makes that class of bug impossible to ship
    rather than merely unlikely.

    [Error] on a parse failure, and on a round-trip mismatch -- which is a bug
    in this module, and says so. *)
val convert :
  rank_of_string:(string -> 'r option) ->
  rank_to_sexp:('r -> Sexplib0.Sexp.t) ->
  rank_of_sexp:(Sexplib0.Sexp.t -> 'r) ->
  string ->
  (string, string) result