Source file signature.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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
(** Global Environment *)
open Basic
open Term
open Rule
let d_module = Debug.register_flag "Module"
type file = string
type signature_error =
| UnmarshalBadVersionNumber of loc * string
| UnmarshalSysError of loc * string * string
| UnmarshalUnknown of loc * string
| SymbolNotFound of loc * name
| AlreadyDefinedSymbol of loc * name
| CannotMakeRuleInfos of Rule.rule_error
| CannotBuildDtree of Dtree.dtree_error
| CannotAddRewriteRules of loc * name
| ConfluenceErrorImport of loc * mident * Confluence.confluence_error
| ConfluenceErrorRules of loc * rule_infos list * Confluence.confluence_error
| GuardNotSatisfied of loc * term * term
| CannotExportModule of mident * exn
| PrivateSymbol of loc * name
| ExpectedACUSymbol of loc * name
exception Signature_error of signature_error
module HMd = Hashtbl.Make (struct
type t = mident
let equal = mident_eq
let hash = Hashtbl.hash
end)
module HId = Hashtbl.Make (struct
type t = ident
let equal = ident_eq
let hash = Hashtbl.hash
end)
type staticity = Static | Definable of algebra | Injective
let algebra_of_staticity = function
| Static | Injective -> Free
| Definable a -> a
type scope = Public | Private
(** The pretty printer for the type [staticity] *)
type rw_infos = {
stat : staticity;
ty : term;
scope : scope;
rules : rule_infos list;
decision_tree : Dtree.t option;
}
type t = {
md : mident;
(** [tables] maps module ident to the hastable of their symbols.
It should only contain a single entry for each module.
Each module's hashtable should only contain a single entry
for each of its symbols. *)
tables : rw_infos HId.t HMd.t;
mutable external_rules : rule_infos list list;
get_file : loc -> mident -> string;
}
let make md get_file =
let tables = HMd.create 19 in
HMd.replace tables md (HId.create 251);
{md; tables; external_rules = []; get_file}
let get_name sg = sg.md
let marshal :
mident ->
mident list ->
rw_infos HId.t ->
rule_infos list list ->
out_channel ->
unit =
fun md deps env ext oc ->
try
Marshal.to_channel oc Version.version [];
Marshal.to_channel oc deps [];
Marshal.to_channel oc env [];
Marshal.to_channel oc ext []
with e -> raise @@ Signature_error (CannotExportModule (md, e))
let unmarshal (lc : loc) (file : string) :
mident list * rw_infos HId.t * rule_infos list list =
try
let ic = open_in file in
let ver : string = Marshal.from_channel ic in
if String.compare ver Version.version <> 0 then
raise (Signature_error (UnmarshalBadVersionNumber (lc, file)));
let deps : mident list = Marshal.from_channel ic in
let ctx : rw_infos HId.t = Marshal.from_channel ic in
let ext : rule_infos list list = Marshal.from_channel ic in
close_in ic; (deps, ctx, ext)
with
| Sys_error s -> raise (Signature_error (UnmarshalSysError (lc, file, s)))
| Signature_error s -> raise (Signature_error s)
let fold_symbols f sg =
HMd.fold (fun md table t -> HId.fold (f md) table t) sg.tables
let iter_symbols f sg = fold_symbols (fun md id rw () -> f md id rw) sg ()
let to_rule_infos_aux (r : unit rule) =
try Rule.to_rule_infos r
with Rule_error e -> raise (Signature_error (CannotMakeRuleInfos e))
let comm_rule (name : name) =
to_rule_infos_aux
{
name =
Gamma
( true,
mk_name (md name) (mk_ident ("comm_" ^ string_of_ident (id name)))
);
ctx = [(dloc, mk_ident "x", ()); (dloc, mk_ident "y", ())];
pat =
Pattern
( dloc,
name,
[Var (dloc, mk_ident "x", 0, []); Var (dloc, mk_ident "y", 1, [])]
);
rhs =
mk_App (mk_Const dloc name)
(mk_DB dloc (mk_ident "y") 1)
[mk_DB dloc (mk_ident "x") 0];
}
let asso_rule (name : name) =
to_rule_infos_aux
{
name =
Gamma
( true,
mk_name (md name) (mk_ident ("asso_" ^ string_of_ident (id name)))
);
ctx =
[
(dloc, mk_ident "x", ());
(dloc, mk_ident "y", ());
(dloc, mk_ident "z", ());
];
pat =
Pattern
( dloc,
name,
[
Pattern
( dloc,
name,
[
Var (dloc, mk_ident "x", 0, []);
Var (dloc, mk_ident "y", 1, []);
] );
Var (dloc, mk_ident "z", 2, []);
] );
rhs =
mk_App (mk_Const dloc name)
(mk_DB dloc (mk_ident "x") 0)
[
mk_App (mk_Const dloc name)
(mk_DB dloc (mk_ident "y") 1)
[mk_DB dloc (mk_ident "z") 2];
];
}
let neu1_rule (name : name) (_ : term) =
to_rule_infos_aux
{
name =
Gamma
( true,
mk_name (md name) (mk_ident ("neut_" ^ string_of_ident (id name)))
);
ctx = [(dloc, mk_ident "x", ())];
pat =
Pattern
( dloc,
name,
[
Var (dloc, mk_ident "x", 0, [])
;
] );
rhs = mk_App (mk_Const dloc name) (mk_DB dloc (mk_ident "x") 0) [];
}
let neu2_rule (name : name) (neu : term) =
to_rule_infos_aux
{
name =
Gamma
( true,
mk_name (md name) (mk_ident ("neut_" ^ string_of_ident (id name)))
);
ctx = [(dloc, mk_ident "x", ())];
pat = Pattern (dloc, name, [Var (dloc, mk_ident "x", 0, [])]);
rhs = mk_App (mk_Const dloc name) (mk_DB dloc (mk_ident "x") 0) [neu];
}
let check_confluence_on_import lc (md : mident) (ctx : rw_infos HId.t) : unit =
let open Confluence in
let aux id infos =
let cst = mk_name md id in
add_constant cst;
add_rules infos.rules;
match infos.stat with
| Definable AC -> add_rules [comm_rule cst; asso_rule cst]
| Definable (ACU neu) ->
add_rules
[comm_rule cst; asso_rule cst; neu1_rule cst neu; neu2_rule cst neu]
| _ -> ()
in
HId.iter aux ctx;
Debug.debug d_confluence "Checking confluence after loading module '%a'..."
pp_mident md;
try check ()
with Confluence_error e ->
raise (Signature_error (ConfluenceErrorImport (lc, md, e)))
let add_external_declaration sg lc cst scope stat ty =
try
let env = HMd.find sg.tables (md cst) in
if HId.mem env (id cst) then
raise (Signature_error (AlreadyDefinedSymbol (lc, cst)))
else
HId.replace env (id cst)
{stat; ty; scope; rules = []; decision_tree = None}
with Not_found ->
HMd.replace sg.tables (md cst) (HId.create 11);
let env = HMd.find sg.tables (md cst) in
HId.replace env (id cst) {stat; ty; scope; rules = []; decision_tree = None}
let rec import sg lc md =
if HMd.mem sg.tables md then
Debug.(
debug d_warn "Trying to import the already loaded module %s."
(string_of_mident md))
else
let deps, ctx, ext = unmarshal lc (sg.get_file lc md) in
HMd.replace sg.tables md ctx;
List.iter
(fun dep -> if not (HMd.mem sg.tables dep) then import sg lc dep)
deps;
Debug.(debug d_module "Loading module '%a'..." pp_mident md);
List.iter (fun rs -> add_rule_infos sg rs) ext;
check_confluence_on_import lc md ctx
and add_rule_infos sg (lst : rule_infos list) : unit =
match lst with
| [] -> ()
| r :: _ as rs ->
let infos, env = get_info_env sg r.l r.cst in
if infos.stat = Static then
raise (Signature_error (CannotAddRewriteRules (r.l, r.cst)));
HId.replace env (id r.cst)
{
infos with
rules = List.rev_append rs infos.rules;
decision_tree = None;
}
and compute_dtree sg (lc : Basic.loc) (cst : Basic.name) : Dtree.t =
let infos, env = get_info_env sg lc cst in
match (infos.decision_tree, infos.rules) with
| None, rules ->
let trees =
try Dtree.of_rules cst (get_algebra sg dloc) (List.rev rules)
with Dtree.Dtree_error e ->
raise (Signature_error (CannotBuildDtree e))
in
HId.replace env (id cst) {infos with decision_tree = Some trees};
trees
| Some t, _ -> t
and get_info_env sg lc cst =
let md = md cst in
let env =
try HMd.find sg.tables md
with Not_found -> import sg lc md; HMd.find sg.tables md
in
try (HId.find env (id cst), env)
with Not_found -> raise (Signature_error (SymbolNotFound (lc, cst)))
and get_infos sg lc cst = fst (get_info_env sg lc cst)
and get_staticity sg lc name = (get_infos sg lc name).stat
and get_algebra sg lc name = algebra_of_staticity (get_staticity sg lc name)
and is_AC sg lc name = Term.is_AC (get_algebra sg lc name)
let get_deps sg : mident list =
HMd.fold
(fun md _ lst -> if mident_eq md sg.md then lst else md :: lst)
sg.tables []
let import_signature sg sg_ext =
HMd.iter
(fun m hid ->
if not (HMd.mem sg.tables m) then HMd.replace sg.tables m (HId.copy hid))
sg_ext.tables;
List.iter (fun rs -> add_rule_infos sg rs) sg_ext.external_rules
let export sg oc =
let mod_table = HMd.find sg.tables sg.md in
marshal sg.md (get_deps sg) mod_table sg.external_rules oc
let is_static sg lc cst =
match (get_infos sg lc cst).stat with
| Static -> true
| Definable _ | Injective -> false
let stat_code = function
| Static -> 0
| Definable Free -> 1
| Definable AC -> 2
| Definable (ACU _) -> 3
| Injective -> 4
let get_id_comparator sg cst cst' =
compare
(stat_code (get_staticity sg dloc cst), cst)
(stat_code (get_staticity sg dloc cst'), cst')
let get_neutral sg lc cst =
match get_algebra sg lc cst with
| ACU neu -> neu
| _ -> raise (Signature_error (ExpectedACUSymbol (lc, cst)))
let get_env sg lc cst =
let md = md cst in
try HMd.find sg.tables md
with Not_found -> import sg lc md; HMd.find sg.tables md
let get_infos sg lc cst =
try HId.find (get_env sg lc cst) (id cst)
with Not_found -> raise (Signature_error (SymbolNotFound (lc, cst)))
let is_injective sg lc cst =
match (get_infos sg lc cst).stat with
| Static | Injective -> true
| Definable _ -> false
let get_type sg lc cst =
let infos = get_infos sg lc cst in
if infos.scope = Public || md cst = sg.md then infos.ty
else raise (Signature_error (PrivateSymbol (lc, cst)))
let get_rules sg lc cst = (get_infos sg lc cst).rules
let get_dtree sg lc cst = compute_dtree sg lc cst
let add_declaration sg lc v st ty =
let cst = mk_name sg.md v in
add_external_declaration sg lc cst st ty
let add_rules sg = function
| [] -> ()
| r :: _ as rs -> (
try
add_rule_infos sg rs;
if not (mident_eq sg.md (md r.cst)) then
sg.external_rules <- rs :: sg.external_rules;
Confluence.add_rules rs;
Debug.(
debug Confluence.d_confluence
"Checking confluence after adding rewrite rules on symbol '%a'"
pp_name r.cst);
try Confluence.check ()
with Confluence.Confluence_error e ->
raise (Signature_error (ConfluenceErrorRules (r.l, rs, e)))
with Rule_error e -> raise (Signature_error (CannotMakeRuleInfos e)))
let get_rw_infos sg md id =
if HMd.mem sg.tables md then
let sig_md = HMd.find sg.tables md in
if HId.mem sig_md id then Some (HId.find sig_md id) else None
else None