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
|
(** This module is used to extract the pure ASTs to various theorem provers.
It defines utilities and helpers to make the work as easy as possible:
we try to factorize as much as possible the different extractions to the
backends we target.
*)
open Errors
open Pure
open TranslateCore
module C = Contexts
module RegionVarId = T.RegionVarId
(** The local logger *)
let log = L.pure_to_extract_log
type extraction_ctx = {
type_context : C.type_context;
fun_context : C.fun_context;
}
(** Extraction context.
Note that the extraction context contains information coming from the
CFIM AST (not only the pure AST). This is useful for naming, for instance:
we use the region information to generate the names of the backward
functions, etc.
*)
(** We use identifiers to look for name clashes *)
type id =
| FunId of FunDefId.id * RegionGroupId.id option
| TypeId of TypeDefId.id
| VarId of VarId.id
| UnknownId
(** Used for stored various strings like keywords, definitions which
should always be in context, etc. and which can't be linked to one
of the above.
*)
[@@deriving show, ord]
type region_group_info = {
id : RegionGroupId.id;
(** The id of the region group.
Note that a simple way of generating unique names for backward
functions is to use the region group ids.
*)
region_names : string option list;
(** The names of the region variables included in this group.
Note that names are not always available...
*)
}
type name = Identifiers.name
type name_formatter = {
bool_name : string;
char_name : string;
int_name : integer_type -> string;
str_name : string;
type_name : name -> string; (** Provided a basename, compute a type name. *)
fun_name : A.fun_id -> name -> int -> region_group_info option -> string;
(** Inputs:
- function id: this is especially useful to identify whether the
function is an assumed function or a local function
- function basename
- number of region groups
- region group information in case of a backward function
(`None` if forward function)
*)
var_basename : name -> string;
(** Generates a variable basename.
Note that once the formatter generated a basename, we add an index
if necessary to prevent name clashes.
*)
}
(** A name formatter's role is to come up with name suggestions.
For instance, provided some information about a function (its basename,
information about the region group, etc.) it should come up with an
appropriate name for the forward/backward function.
It can of course apply many transformations, like changing to camel case/
snake case, adding prefixes/suffixes, etc.
*)
let compute_type_def_name (fmt : name_formatter) (def : type_def) : string =
fmt.type_name def.name
(** A helper function: generates a function suffix from a region group
information.
TODO: move all those helpers.
*)
let default_fun_suffix (num_region_groups : int) (rg : region_group_info option)
: string =
(* There are several cases:
- [rg] is `Some`: this is a forward function:
- if there are no region groups (i.e., no backward functions) we don't
add any suffix
- if there are region gruops, we add "_fwd"
- [rg] is `None`: this is a backward function:
- this function has one region group: we add "_back"
- this function has several backward function: we add "_back" and an
additional suffix to identify the precise backward function
*)
match rg with
| None -> if num_region_groups = 0 then "" else "_fwd"
| Some rg ->
assert (num_region_groups > 0);
if num_region_groups = 1 then (* Exactly one backward function *)
"_back"
else if
(* Several region groups/backward functions:
- if all the regions in the group have names, we use those names
- otherwise we use an index
*)
List.for_all Option.is_some rg.region_names
then
(* Concatenate the region names *)
"_back" ^ String.concat "" (List.map Option.get rg.region_names)
else (* Use the region index *)
"_back" ^ RegionGroupId.to_string rg.id
(** Extract information from a function, and give this information to a
[name_formatter] to generate a function's name.
Note that we need region information coming from CFIM (when generating
the name for a backward function, we try to use the names of the regions
to
*)
let compute_fun_def_name (ctx : extraction_ctx) (fmt : name_formatter)
(fun_id : A.fun_id) (rg_id : RegionGroupId.id option) : string =
(* Lookup the function CFIM signature (we need the region information) *)
let sg = CfimAstUtils.lookup_fun_sig fun_id ctx.fun_context.fun_defs in
let basename = CfimAstUtils.lookup_fun_name fun_id ctx.fun_context.fun_defs in
(* Compute the regions information *)
let num_region_groups = List.length sg.regions_hierarchy in
let rg_info =
match rg_id with
| None -> None
| Some rg_id ->
let rg = RegionGroupId.nth sg.regions_hierarchy rg_id in
let regions =
List.map (fun rid -> RegionVarId.nth sg.region_params rid) rg.regions
in
let region_names =
List.map (fun (r : T.region_var) -> r.name) regions
in
Some { id = rg.id; region_names }
in
fmt.fun_name fun_id basename num_region_groups rg_info
(*
let name_to_string (n : name) : string = show_name n
module NameOrderedType = struct
type t = name
let compare = compare_name
let to_string = name_to_string
let pp_t = pp_name
let show_t = show_name
end
module NameMap = Collections.MakeMapInj (NameOrderedType) (Id.NameOrderedType)
(** Notice that we use the *injective* map to map identifiers to names.
Of course, even if those names (which are string lists) don't collide,
when converting them to strings we can still introduce collisions: we
check that later.
Note that we use injective maps for sanity: though we write the name
generation with collision in mind, it is always good to have such checks.
*)*)
(*let translate_fun_name (fdef : A.fun_def) (bid : T.RegionGroupId.id option) :
Id.name =
let sg = fdef.signature in
(* General function to generate a suffix for a region group
* (i.e., an abstraction)*)
let rg_to_string (rg : T.region_var_group) : string =
(* We are just a little bit smart:
- if there is exactly one region id in the region group and this region
has a name, we use this name
- otherwise, we use the region number (note that region names shouldn't
start with numbers)
*)
match rg.T.regions with
| [ rid ] -> (
let rvar = T.RegionVarId.nth sg.region_params rid in
match rvar.name with
| None -> T.RegionGroupId.to_string rg.T.id
| Some name -> name)
| _ -> T.RegionGroupId.to_string rg.T.id
in
(* There are several cases:
- this is a forward function: we add "_fwd"
- this is a backward function:
- this function has one backward function: we add "_back"
- this function has several backward function: we add "_back" and an
additional suffix to identify the precise backward function
*)
let suffix =
match bid with
| None -> "_fwd"
| Some bid -> (
match sg.regions_hierarchy with
| [] ->
failwith "Unreachable"
(* we can't get there if we ask for a back function *)
| [ _ ] ->
(* Exactly one backward function *)
"_back"
| _ ->
(* Several backward functions *)
let rg = T.RegionGroupId.nth sg.regions_hierarchy bid in
"_back" ^ rg_to_string rg)
in
(* Final name *)
let rec add_to_last (n : Id.name) : Id.name =
match n with
| [] -> failwith "Unreachable"
| [ x ] -> [ x ^ suffix ]
| x :: n -> x :: add_to_last n
in
add_to_last fdef.name
(** Generates a name for a type (simply reuses the name in the definition) *)
let translate_type_name (def : T.type_def) : Id.name = def.T.name
*)
|