summaryrefslogtreecommitdiff
path: root/src/lib/process.ml
blob: 01c6d4aacd7af108e028bc409b3501e9384ea3c9 (plain)
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
open StdLabels
module M(T:Sounds.T) = struct

  type voyel = (T.t * T.t )

  type consonants =
    { ending : T.t option option
    ; opening : T.t list
    ; following : T.t option }

  type group = voyel * consonants option

  type modifier = (group * T.t option option)  -> (group * T.t option option)

  (** Apply all the modifiers to the syllabic group in order to correct the
      relation between the elements

      This is just a fold_left list, and the order matter : for example
      nasalisation shall be applied after the S vocalisation

  *)
  let apply_modifiers
    : group * T.t option option -> modifier list -> group * T.t option option
    = fun e m ->
      List.fold_left m
        ~init:e
        ~f:(fun e f -> f e)

  (** The Nasal modifier transform a voyel followed by N and a consonant
      into a nasal voyel.

      Does this min that nasal voyel are not a distinct element, but just a
      merge from two distinct elements ? *)
  let nasal
    : modifier
    = fun init ->
      let (((v1, v2), c) , ending) = init in
      let ending = Option.bind ending (fun x -> x) in
      match ending with
      | None -> init
      | Some ending ->
        match T.is_nasal ending with
        | false -> init
        | true ->
          (* Remove the ending consonant, and transform the voyel into
             the nasal form  *)
          ( ( (T.nasal v1, T.nasal v2)
            , c )
          , None )

  (** Transform the S into Z if the S is the opening consonant and
      there is no ending consonant before *)
  let vocalize_s
    : modifier
    = fun init ->
      let (((v1, v2), c) , ending) = init in

      match c with
      | None -> init
      | Some op ->
        (* The voyel may be none in case of ending word. In such case, we shall
           not trnasform the S into Z *)
        let is_voyel = T.is_voyel v1 && T.is_voyel v2 in
        match is_voyel, op.opening, op.ending with
        | true, hd::[], None when T.code hd = T.SZ ->
          let c = Some { op with opening = [T.z ()] } in
          (((v1, v2), c) , ending)
        | _ -> init

  (** Mute the last consonant if there is no voyel in the syllabus.

      This modifier is only applied in the first step, and not repeated anymore.
  *)
  let mute_consonant
    : modifier
    = fun init ->
      let (((v1, v2), c) , ending) = init in
      let is_voyel = T.is_voyel v1 && T.is_voyel v2 in
      match is_voyel, c with
      | false, Some c ->
        let c = { c with opening = List.map ~f:T.muted c.opening } in
        (((v1, v2), Some c) , ending)
      | _ -> init

  let change_voyel
    = fun init ->
      let (((v1, v2), _) , ending) = init in
      match ending with
      | None -> v2
      | Some _ -> v1

  let rec _rebuild ~(m:modifier list) acc ending_consonant : group list -> T.t list
    = function
      | [] -> acc
      | hd::tl ->

        let modifier = vocalize_s :: nasal :: m in
        let (voyel, consonants), ending_consonant =
          apply_modifiers
            (hd, ending_consonant)
            modifier  in
        let voyel = change_voyel ((voyel, consonants), ending_consonant) in

        (* Add the last consonant and the voyel *)
        let m, acc = match ending_consonant with
          | None -> modifier, voyel::acc
          | Some s ->
            let default = modifier, voyel :: acc in
            match s with
            | None -> default
            | Some s ->

              modifier, voyel :: s::acc  in

        match consonants with
        | None -> _rebuild ~m acc None tl
        | Some {ending; opening; following} ->

          let acc = match following with
            | None -> acc
            | Some s -> s::acc in

          match opening with
          | [] ->_rebuild ~m acc ending tl
          | opening -> _rebuild ~m (opening @ acc) ending tl

  (** Rebuild the list in the normal order

      The voyels have to be choosen, depending either they are followed by a
      consonant or not

      Some consonants may be changed depending of the following voyel

      The list has to be reversed

      and so one

  *)
  let rebuild
    : consonants option -> group list -> T.t list
    = fun  ending elems ->
      let elems' = match ending with
        | None -> elems
        | Some _ -> ((T.none, T.none), ending)::elems in
      _rebuild ~m:[mute_consonant] [] None elems'

end