forked from let-def/ocaml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
patterns.ml
254 lines (222 loc) · 7.59 KB
/
patterns.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
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Gabriel Scherer, projet Partout, INRIA Paris-Saclay *)
(* Thomas Refis, Jane Street Europe *)
(* *)
(* Copyright 2019 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
open Asttypes
open Types
open Typedtree
(* useful pattern auxiliary functions *)
let omega = {
pat_desc = Tpat_any;
pat_loc = Location.none;
pat_extra = [];
pat_type = Ctype.none;
pat_env = Env.empty;
pat_attributes = [];
}
let rec omegas i =
if i <= 0 then [] else omega :: omegas (i-1)
let omega_list l = List.map (fun _ -> omega) l
module Non_empty_row = struct
type 'a t = 'a * Typedtree.pattern list
let of_initial = function
| [] -> assert false
| pat :: patl -> (pat, patl)
let map_first f (p, patl) = (f p, patl)
end
(* "views" on patterns are polymorphic variants
that allow to restrict the set of pattern constructors
statically allowed at a particular place *)
module Simple = struct
type view = [
| `Any
| `Constant of constant
| `Tuple of pattern list
| `Construct of
Longident.t loc * constructor_description * pattern list
| `Variant of label * pattern option * row_desc ref
| `Record of
(Longident.t loc * label_description * pattern) list * closed_flag
| `Array of pattern list
| `Lazy of pattern
]
type pattern = view pattern_data
let omega = { omega with pat_desc = `Any }
end
module Half_simple = struct
type view = [
| Simple.view
| `Or of pattern * pattern * row_desc option
]
type pattern = view pattern_data
end
module General = struct
type view = [
| Half_simple.view
| `Var of Ident.t * string loc
| `Alias of pattern * Ident.t * string loc
]
type pattern = view pattern_data
let view_desc = function
| Tpat_any ->
`Any
| Tpat_var (id, str) ->
`Var (id, str)
| Tpat_alias (p, id, str) ->
`Alias (p, id, str)
| Tpat_constant cst ->
`Constant cst
| Tpat_tuple ps ->
`Tuple ps
| Tpat_construct (cstr, cstr_descr, args, _) ->
`Construct (cstr, cstr_descr, args)
| Tpat_variant (cstr, arg, row_desc) ->
`Variant (cstr, arg, row_desc)
| Tpat_record (fields, closed) ->
`Record (fields, closed)
| Tpat_array ps -> `Array ps
| Tpat_or (p, q, row_desc) -> `Or (p, q, row_desc)
| Tpat_lazy p -> `Lazy p
let view p : pattern =
{ p with pat_desc = view_desc p.pat_desc }
let erase_desc = function
| `Any -> Tpat_any
| `Var (id, str) -> Tpat_var (id, str)
| `Alias (p, id, str) -> Tpat_alias (p, id, str)
| `Constant cst -> Tpat_constant cst
| `Tuple ps -> Tpat_tuple ps
| `Construct (cstr, cst_descr, args) ->
Tpat_construct (cstr, cst_descr, args, None)
| `Variant (cstr, arg, row_desc) ->
Tpat_variant (cstr, arg, row_desc)
| `Record (fields, closed) ->
Tpat_record (fields, closed)
| `Array ps -> Tpat_array ps
| `Or (p, q, row_desc) -> Tpat_or (p, q, row_desc)
| `Lazy p -> Tpat_lazy p
let erase p : Typedtree.pattern =
{ p with pat_desc = erase_desc p.pat_desc }
let rec strip_vars (p : pattern) : Half_simple.pattern =
match p.pat_desc with
| `Alias (p, _, _) -> strip_vars (view p)
| `Var _ -> { p with pat_desc = `Any }
| #Half_simple.view as view -> { p with pat_desc = view }
end
(* the head constructor of a simple pattern *)
module Head : sig
type desc =
| Any
| Construct of constructor_description
| Constant of constant
| Tuple of int
| Record of label_description list
| Variant of
{ tag: label; has_arg: bool;
cstr_row: row_desc ref;
type_row : unit -> row_desc; }
| Array of int
| Lazy
type t = desc pattern_data
val arity : t -> int
(** [deconstruct p] returns the head of [p] and the list of sub patterns. *)
val deconstruct : Simple.pattern -> t * pattern list
(** reconstructs a pattern, putting wildcards as sub-patterns. *)
val to_omega_pattern : t -> pattern
val omega : t
end = struct
type desc =
| Any
| Construct of constructor_description
| Constant of constant
| Tuple of int
| Record of label_description list
| Variant of
{ tag: label; has_arg: bool;
cstr_row: row_desc ref;
type_row : unit -> row_desc; }
(* the row of the type may evolve if [close_variant] is called,
hence the (unit -> ...) delay *)
| Array of int
| Lazy
type t = desc pattern_data
let deconstruct (q : Simple.pattern) =
let deconstruct_desc = function
| `Any -> Any, []
| `Constant c -> Constant c, []
| `Tuple args ->
Tuple (List.length args), args
| `Construct (_, c, args) ->
Construct c, args
| `Variant (tag, arg, cstr_row) ->
let has_arg, pats =
match arg with
| None -> false, []
| Some a -> true, [a]
in
let type_row () =
match get_desc (Ctype.expand_head q.pat_env q.pat_type) with
| Tvariant type_row -> type_row
| _ -> assert false
in
Variant {tag; has_arg; cstr_row; type_row}, pats
| `Array args ->
Array (List.length args), args
| `Record (largs, _) ->
let lbls = List.map (fun (_,lbl,_) -> lbl) largs in
let pats = List.map (fun (_,_,pat) -> pat) largs in
Record lbls, pats
| `Lazy p ->
Lazy, [p]
in
let desc, pats = deconstruct_desc q.pat_desc in
{ q with pat_desc = desc }, pats
let arity t =
match t.pat_desc with
| Any -> 0
| Constant _ -> 0
| Construct c -> c.cstr_arity
| Tuple n | Array n -> n
| Record l -> List.length l
| Variant { has_arg; _ } -> if has_arg then 1 else 0
| Lazy -> 1
let to_omega_pattern t =
let pat_desc =
let mkloc x = Location.mkloc x t.pat_loc in
match t.pat_desc with
| Any -> Tpat_any
| Lazy -> Tpat_lazy omega
| Constant c -> Tpat_constant c
| Tuple n -> Tpat_tuple (omegas n)
| Array n -> Tpat_array (omegas n)
| Construct c ->
let lid_loc = mkloc (Longident.Lident c.cstr_name) in
Tpat_construct (lid_loc, c, omegas c.cstr_arity, None)
| Variant { tag; has_arg; cstr_row } ->
let arg_opt = if has_arg then Some omega else None in
Tpat_variant (tag, arg_opt, cstr_row)
| Record lbls ->
let lst =
List.map (fun lbl ->
let lid_loc = mkloc (Longident.Lident lbl.lbl_name) in
(lid_loc, lbl, omega)
) lbls
in
Tpat_record (lst, Closed)
in
{ t with
pat_desc;
pat_extra = [];
}
let omega = { omega with pat_desc = Any }
end