Source file thompson_nfa.ml
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
open! Core
module Make (G : Grammar_module_types.S) = struct
module Action = Action.Make (G)
module Types (Key : T1) = struct
type !'a node = |
type (!'src, !'dst) eps_edge = |
type !'src token_edge = Token_edge
let _ = Token_edge
module Eps_edge_data = struct
type ('src, 'dst) t =
{ action : ('src, 'dst) Action.Epsilon.t
; src : 'src node Key.t
; dst : 'dst node Key.t
}
end
module Token_edge_data = struct
type 'src t =
{ src : 'src node Key.t
; dst : 'src node Key.t
}
end
module Outward_eps_edge = struct
type 'src t = T : ('src, 'dst) eps_edge Key.t -> 'src t
end
module Node_data = struct
type 'a t =
{ epsilon : 'a Outward_eps_edge.t Reversed_list.t
; by_terminal : (G.terminal * 'a token_edge Key.t) Reversed_list.t
}
let empty () = { epsilon = []; by_terminal = [] }
let add_eps_edge t ~edge = { t with epsilon = edge :: t.epsilon }
let add_token_edge t ~edge ~terminal =
{ t with by_terminal = (terminal, edge) :: t.by_terminal }
;;
end
module Data = struct
type 'a t =
| Eps_edge : ('src, 'dst) Eps_edge_data.t -> ('src, 'dst) eps_edge t
| Token_edge : 'src Token_edge_data.t -> 'src token_edge t
| Node : 'a Node_data.t -> 'a node t
let add_eps_edge (Node data : _ node t) ~edge : _ node t =
Node (Node_data.add_eps_edge data ~edge)
;;
let add_token_edge (Node data : _ node t) ~edge ~terminal : _ node t =
Node (Node_data.add_token_edge data ~edge ~terminal)
;;
end
end
module State = Typed_indexer.Make (struct
module Make (Key : T1) = struct
module Types = Types (Key)
include Types.Data
end
end)
include Types (State.Key)
module Key = State.Key
let fresh_node () = State.Builder.add (Node (Node_data.empty ()))
let new_eps_edge
(type src dst)
~(src : src node Key.t)
~(dst : dst node Key.t)
~(action : (src, dst) Action.Epsilon.t)
: (src, dst) eps_edge Key.t State.Builder.t
=
let%bind.State.Builder edge = State.Builder.add (Eps_edge { action; src; dst }) in
let%map.State.Builder () =
State.Builder.update src ~f:(Data.add_eps_edge ~edge:(T edge))
in
edge
;;
let new_token_edge (type src) ~(src : src node Key.t) ~(dst : src node Key.t) ~terminal
: src token_edge Key.t State.Builder.t
=
let%bind.State.Builder edge = State.Builder.add (Token_edge { src; dst }) in
let%map.State.Builder () =
State.Builder.update src ~f:(Data.add_token_edge ~edge ~terminal)
in
edge
;;
let new_node ~src ~action =
let%bind.State.Builder dst = fresh_node () in
let%map.State.Builder () = new_eps_edge ~src ~dst ~action |> State.Builder.ignore_m in
dst
;;
let rec of_grammar
: type a stack. stack node Key.t -> a G.t -> (a -> stack) node Key.t State.Builder.t
=
fun entrance ->
let default_unit t =
let%bind.State.Builder exit = of_grammar_unit entrance t in
new_node ~src:exit ~action:(Push ())
in
function
| Return x -> new_node ~src:entrance ~action:(Push x)
| Map (t, f) ->
let%bind.State.Builder exit = of_grammar entrance t in
new_node ~src:exit ~action:(Map f)
| Capture (t, capture) ->
let%bind.State.Builder entrance = new_node ~src:entrance ~action:Start_capture in
let%bind.State.Builder exit = of_grammar_unit entrance t in
new_node ~src:exit ~action:(Capture capture)
| Capture_also (t, capture) ->
let%bind.State.Builder entrance = new_node ~src:entrance ~action:Start_capture in
let%bind.State.Builder exit = of_grammar entrance t in
new_node ~src:exit ~action:(Capture_also capture)
| Union ts ->
let%bind.State.Builder exits =
List.map ts ~f:(of_grammar entrance) |> State.Builder.all
in
let%bind.State.Builder final_exit = fresh_node () in
let%map.State.Builder () =
List.map exits ~f:(fun src ->
new_eps_edge ~src ~dst:final_exit ~action:No_op |> State.Builder.ignore_m)
|> State.Builder.all_unit
in
final_exit
| Append (a, b, f) ->
let%bind.State.Builder mid = of_grammar entrance a in
let%bind.State.Builder exit = of_grammar mid b in
new_node ~src:exit ~action:(Map2 f)
| Star (t, { init; f }) ->
let%bind.State.Builder star_entrance = new_node ~src:entrance ~action:(Push init) in
let%bind.State.Builder star_exit = of_grammar star_entrance t in
let%map.State.Builder () =
new_eps_edge ~src:star_exit ~dst:star_entrance ~action:(Map2 f)
|> State.Builder.ignore_m
in
star_entrance
| Concat_unit _ as t -> default_unit t
| Terminal _ as t -> default_unit t
| Star_unit _ as t -> default_unit t
and of_grammar_unit
: type stack. stack node Key.t -> unit G.t -> stack node Key.t State.Builder.t
=
fun entrance ->
let default t =
let%bind.State.Builder exit = of_grammar entrance t in
new_node ~src:exit ~action:Pop_unit
in
function
| Return () -> State.Builder.return entrance
| Terminal terminal ->
let%bind.State.Builder exit = fresh_node () in
let%map.State.Builder () =
new_token_edge ~src:entrance ~dst:exit ~terminal |> State.Builder.ignore_m
in
exit
| Union ts ->
let%bind.State.Builder exits =
List.map ts ~f:(of_grammar_unit entrance) |> State.Builder.all
in
let%bind.State.Builder final_exit = fresh_node () in
let%map.State.Builder () =
List.map exits ~f:(fun src ->
new_eps_edge ~src ~dst:final_exit ~action:No_op |> State.Builder.ignore_m)
|> State.Builder.all_unit
in
final_exit
| Concat_unit ts ->
List.fold ts ~init:(State.Builder.return entrance) ~f:(fun acc t ->
let%bind.State.Builder entrance = acc in
of_grammar_unit entrance t)
| Star_unit t ->
let%bind.State.Builder star_entrance = new_node ~src:entrance ~action:No_op in
let%bind.State.Builder star_exit = of_grammar_unit star_entrance t in
let%map.State.Builder () =
new_eps_edge ~src:star_exit ~dst:star_entrance ~action:No_op
|> State.Builder.ignore_m
in
star_entrance
| Map _ as t -> default t
| Capture _ as t -> default t
| Capture_also _ as t -> default t
| Append _ as t -> default t
| Star _ as t -> default t
;;
module Eps_edge = struct
type ('src, 'dst) t = ('src, 'dst) eps_edge Key.t
type 'src packed = Packed : ('src, _) t -> 'src packed
end
module Token_edge = struct
type 'src t = ('src token_edge[@opaque]) Key.t [@@deriving sexp_of]
let compare (type a b) (a : a t) (b : b t) : (a, b) Typed_comparable.Ordering.t =
match Key.compare a b with
| Less -> Less
| Greater -> Greater
| Equal T -> Equal T
;;
type packed = Packed : _ t -> packed
let sexp_of_packed (Packed t) = [%sexp_of: _ t] t
end
module Node = struct
type 'a t = ('a node[@opaque]) Key.t [@@deriving sexp_of]
let compare (type a b) (a : a t) (b : b t) : (a, b) Typed_comparable.Ordering.t =
match Key.compare a b with
| Less -> Less
| Greater -> Greater
| Equal T -> Equal T
;;
type packed = Packed : _ t -> packed
let sexp_of_packed (Packed t) = [%sexp_of: _ t] t
end
type t = State.t
let create grammar =
let (start_node, end_node), state =
State.build
(let%bind.State.Builder start_node = fresh_node () in
let%map.State.Builder end_node = of_grammar start_node grammar in
start_node, end_node)
in
state, ~start:start_node, ~end_:end_node
;;
let token_edges t =
let (type a) : a Key.t -> a Data.t -> Token_edge.packed option =
fun key data ->
match data with
| Node _ -> None
| Eps_edge _ -> None
| Token_edge _ -> Some (Packed key)
in
State.to_alist t extract |> List.filter_opt
;;
let follow_eps (type a) (t : t) (node : a Node.t) : a Eps_edge.packed list =
let (Node { epsilon; _ }) = State.find t node in
Reversed_list.rev_map epsilon ~f:(fun (T edge) -> Eps_edge.Packed edge)
;;
let follow_token (type a) (t : t) (node : a Node.t) : (G.terminal * a Token_edge.t) list
=
let (Node { by_terminal; _ }) = State.find t node in
Reversed_list.rev by_terminal
;;
let eps_edge_data (type src dst) (t : t) (eps_edge : (src, dst) Eps_edge.t)
: (src, dst) Eps_edge_data.t
=
let (Eps_edge data) = State.find t eps_edge in
data
;;
let token_edge_data (type src) (t : t) (token_edge : src Token_edge.t)
: src Token_edge_data.t
=
let (Token_edge data) = State.find t token_edge in
data
;;
end