-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexpr.ml
More file actions
451 lines (362 loc) · 14.6 KB
/
expr.ml
File metadata and controls
451 lines (362 loc) · 14.6 KB
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
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
(**
HOT, a Higher-Order Termination prover
See the COPYRIGHTS and LICENSE files.
- Frederic Blanqui, 2010-03-15
*)
open Term;;
open Util;;
open Printf;;
open Lib;;
open Prec;;
(*****************************************************************************)
(** types *)
(*****************************************************************************)
let get_typ_consts, set_typ_consts = get_set StrSet.empty;;
let check_typ_const id =
if not (StrSet.mem id (get_typ_consts())) then error (id ^ " not declared");;
let rec check_typ (ts, id) = check_typ_const id; List.iter check_typ ts;;
(*****************************************************************************)
(** raw lambda expressions provided by parsing: it is not known
whether an identifier is a variable or a function symbol yet *)
(*****************************************************************************)
type expr =
| EIdent of ident
| EAbs of ident * typ * expr
| EApp of expr * expr;;
let rec expr_app e1 = function
| [] -> e1
| e2 :: es -> expr_app (EApp (e1, e2)) es;;
let rec raw_expr b = function
| EIdent id -> bprintf b "%s" id
| EAbs (id, t, e) -> bprintf b "(%s:%a.%a)" id typ t raw_expr e
| EApp (e1, e2) -> bprintf b "(%a %a)" raw_expr e1 raw_expr e2;;
let rec expr b = function
| EIdent id -> bprintf b "%s" id
| EAbs (id, t, e) -> bprintf b "(%s:%a.%a)" id typ t expr e
| EApp (e1, e2) -> bprintf b "%a %a" expr e1 pexpr e2
and pexpr b = function
| EIdent id -> bprintf b "%s" id
| EAbs (id, t, e) -> bprintf b "(%s:%a.%a)" id typ t expr e
| EApp (e1, e2) -> bprintf b "(%a %a)" expr e1 pexpr e2
type expr_rule = expr * expr;;
type expr_rules = expr_rule list;;
let expr_rule = rule_gen expr;;
(*****************************************************************************)
(** map identifier -> symbol * typ *)
(*****************************************************************************)
let get_symb_typ_map, set_symb_typ_map = get_set StrMap.empty;;
let add_global_symb s typ =
let id = ident_of_symb s in
if StrMap.mem id (get_symb_typ_map()) then
error (id ^ " already declared")
else begin
check_typ typ;
set_symb_typ_map (StrMap.add id (s, typ) (get_symb_typ_map()))
end;;
let add_global_fresh ty =
let v = Var (fresh "x") in add_global_symb v ty; symb v;;
let add_global_freshs_typ ty =
let rec aux n = if n <= 0 then [] else add_global_fresh ty :: aux (n-1)
in aux;;
let symb_of_ident id =
try fst (StrMap.find id (get_symb_typ_map()))
with Not_found -> error (id ^ " not declared");;
let typ_of_ident id =
try snd (StrMap.find id (get_symb_typ_map()))
with Not_found -> error (id ^ " not declared");;
let typs_of_idents s =
StrSet.fold
(fun id m -> StrMap.add id (typ_of_ident id) m) s StrMap.empty;;
let arity_fun id = arity_typ (typ_of_ident id);;
(*****************************************************************************)
(** convert a raw expression into a well-formed term *)
(*****************************************************************************)
let term_of_expr =
let rec aux vmap = function
| EIdent id ->
symb (try StrMap.find id vmap with Not_found -> symb_of_ident id)
| EAbs (x, typ, e) -> abs1 x typ (aux (StrMap.add x (Var x) vmap) e)
| EApp (e1, e2) -> app (aux vmap e1) (aux vmap e2)
in aux StrMap.empty;;
(*****************************************************************************)
(** convert rules so that bound variables are pairwise distinct and
distinct from free variables *)
(*****************************************************************************)
let rule_of_expr_rule (e1, e2) =
let l = term_of_expr e1 and r = term_of_expr e2 in
notin (vars l);
let l', r' = rename_bound_vars l, rename_bound_vars r in
if (l, r) <> (l',r') then
(debugf "" (rule_gen expr) (e1,e2);
debugf "renamed into " rule (l',r'));
l', r';;
(*****************************************************************************)
(** termination problem *)
(*****************************************************************************)
type signature = {
sig_typs : StrSet.t;
sig_funs : typ StrMap.t;
sig_vars : typ StrMap.t };;
type expr_problem = signature * expr_rule list;;
type problem = signature * rule list;;
let build_symb_typ_map s =
verbose "build symbol-type map...";
set_typ_consts s.sig_typs;
StrMap.iter (fun id ty -> add_global_symb (Fun id) ty) s.sig_funs;
StrMap.iter (fun id ty -> add_global_symb (Var id) ty) s.sig_vars;;
module Typ = struct type t = typ end;;
module TypOrd = Ord.Make (Typ);;
module TypMap = Map.Make (TypOrd);;
let inverse sm =
StrMap.fold
(fun s t tm ->
TypMap.add t
(s :: try TypMap.find t tm with Not_found -> [])
tm)
sm TypMap.empty;;
let typ_map b =
TypMap.iter
(fun t ss -> bprintf b "%a : %a;\n" (list ", " string) ss typ t);;
let signature b s =
if s.sig_typs <> StrSet.empty then
bprintf b "TYPES\n%a;\n\n" (set ", ") s.sig_typs;
if s.sig_funs <> StrMap.empty then
bprintf b "FUNS\n%a\n" typ_map (inverse s.sig_funs);
if s.sig_vars <> StrMap.empty then
bprintf b "VARS\n%a\n" typ_map (inverse s.sig_vars);;
let problem_gen rule b (s, rs) =
signature b s;
if rs <> [] then
bprintf b "RULES\n%a;\n" (list ";\n" rule) (List.rev rs);;
let expr_problem = problem_gen expr_rule;;
let problem = problem_gen rule;;
let output_file_hot fn = output_file (Util.fprint problem) fn;;
(*****************************************************************************)
(** type of a term *)
(*****************************************************************************)
let typ_symb vmap = function
| Var id ->
(try StrMap.find id vmap with Not_found -> typ_of_ident id)
| Fun id -> typ_of_ident id
let rec typ_head vmap = function
| Symb s -> typ_symb vmap s
| Abs (idtyps, t) ->
let new_vmap =
List.fold_left
(fun map (id, typ) -> StrMap.add id typ map)
vmap
idtyps in
arrows (List.map snd idtyps) (typ_term new_vmap t)
and typ_term vmap (h, ts) =
let typs, tid = typ_head vmap h in typ_app vmap typs tid ts
and typ_app vmap typs tid ts =
match typs, ts with
| _, [] -> typs, tid
| typ :: typs', t :: ts' when typ = typ_term vmap t ->
typ_app vmap typs' tid ts'
| _, _ -> error "typing error";;
let typ_of = typ_term StrMap.empty;;
let preserve_typ_rule (t1, t2) = typ_of t1 = typ_of t2;;
let preserve_typ_rules = List.for_all preserve_typ_rule;;
(*****************************************************************************)
(** type constants necessary for typing a term *)
(*****************************************************************************)
let rec typ_consts_typ (ts, id) =
List.fold_left
(fun set typ -> StrSet.union set (typ_consts_typ typ))
(StrSet.singleton id)
ts;;
let typ_consts_symb s = typ_consts_typ (typ_of_ident (ident_of_symb s));;
let rec typ_consts_head = function
| Symb s -> typ_consts_symb s
| Abs (idtyps, t) ->
List.fold_left
(fun set (_, typ) -> StrSet.union (typ_consts_typ typ) set)
(typ_consts t)
idtyps
and typ_consts (h, ts) =
StrSet.union (typ_consts_head h)
(List.fold_left
(fun set t -> StrSet.union set (typ_consts t))
StrSet.empty
ts);;
let typ_consts_rule (l, r) = StrSet.union (typ_consts l) (typ_consts r);;
let typ_consts_rules =
List.fold_left
(fun set r -> StrSet.union set (typ_consts_rule r)) StrSet.empty;;
(*****************************************************************************)
(** initial set of rules *)
(*****************************************************************************)
let get_rules, set_rules = get_set [];;
let compute_rules rs =
verbose "compute rules...";
set_rules (List.map rule_of_expr_rule rs);;
(*****************************************************************************)
(** set of symbols the termination of which remains to be proved *)
(*****************************************************************************)
let get_funs, set_funs = get_set StrSet.empty;;
(*****************************************************************************)
(** symbols that have been proved computable *)
(*****************************************************************************)
let get_comp_funs, set_comp_funs = get_set StrSet.empty;;
let add_comp_fun f =
verbose (f ^ " is computable");
set_comp_funs (StrSet.add f (get_comp_funs()));;
let add_comp_funs fs =
verbosef "are computable: " (set ",") fs;
set_comp_funs (StrSet.union fs (get_comp_funs()));;
let is_comp f = StrSet.mem f (get_comp_funs());;
(*****************************************************************************)
(** compute the map function ident -> rules and the set of undefined symbols *)
(*****************************************************************************)
let get_rules_map, set_rules_map = get_set StrMap.empty;;
let get_undef_funs, set_undef_funs = get_set StrSet.empty;;
let get_other_rules, set_other_rules = get_set [];;
let is_defined id = StrMap.mem id (get_rules_map());;
let rules_of_ident id =
try StrMap.find id (get_rules_map()) with Not_found -> [];;
let rules_of_idents s =
StrSet.fold (fun id rs -> rules_of_ident id @ rs) s [];;
let build_rules_map() =
verbose "compute (un)defined function symbols...";
(* we first set the set of undefined symbols as the set of all symbols *)
set_undef_funs
(StrMap.fold
(fun id (sy,_) s -> match sy with Fun _ -> StrSet.add id s | Var _ -> s)
(get_symb_typ_map())
StrSet.empty);
(* then, for each rule, we remove the top symbol of its LHS from the
set of undefined symbols and add the rule in the map for defined
symbols *)
List.iter
(fun (((h, _), _) as lr) ->
match h with
| Symb (Fun id) ->
set_undef_funs (StrSet.remove id (get_undef_funs()));
set_rules_map
(StrMap.add id (lr :: rules_of_ident id) (get_rules_map()));
set_funs (StrSet.add id (get_funs()))
| Symb (Var _) | Abs _ ->
set_other_rules (lr :: get_other_rules()))
(get_rules());
(* undefined symbols are computable *)
add_comp_funs (get_undef_funs());
verbosef "undefined function symbols: " (set ",") (get_undef_funs());
verbosef "defined function symbols: "
(map "" (fun _ _ -> ()) ",") (get_rules_map());;
(*****************************************************************************)
(** definition (quasi-)ordering on defined symbols: f >= g if g is a
defined symbol occuring in some defining rule of f *)
(*****************************************************************************)
let get_def_prec, set_def_prec = get_set StrPrec.empty;;
let def_cmp f g = StrPrec.cmp (get_def_prec()) f g;;
let fid_le f g = StrPrec.le (get_def_prec()) f g;;
let fid_lt f g = StrPrec.lt (get_def_prec()) f g;;
let fid_eq f g = StrPrec.eq (get_def_prec()) f g;;
let compute_def_prec =
List.fold_left
(fun p ((h, us), r) ->
match h with
| Symb (Fun id) ->
(*IMPROVE: exclude rules of the form f .. r .. -> r *)
if List.mem r us then p
else
fold_funs
(fun id' _ts p ->
if id <> id' && is_defined id' then StrPrec.add id Ge id' p
else p)
p r
| Symb (Var _) | Abs _ -> p)
StrPrec.empty;;
(*REMARK: because add_rule only adds constraints of the form Ge, the
resulting precedence has only constraints of the form Eq, Ge and, by
symmetry, Le *)
(** add symbols that do not depend on other symbols (they are not
recorded by compute_def_prec) *)
let add_self_dep prec =
StrMap.fold (fun f _ p -> StrPrec.add_elt f p) (get_rules_map()) prec;;
let build_def_prec() =
verbose "compute definition ordering...";
let prec = compute_def_prec (get_rules()) in
(*verbosef "compute_def_prec:\n" (StrPrec.prec string) prec;*)
let prec = StrPrec.strict prec in
(*verbosef "strict:\n" (StrPrec.prec string) prec;*)
let prec = add_self_dep prec in
(*verbosef "add_self_prec:\n" (StrPrec.prec string) prec;*)
verbosef "definition ordering:\n" (StrPrec.prec string) prec;
set_def_prec prec;;
(** tell if a function symbol is recursively defined *)
let is_rec f =
try
List.iter
(fun ((_, us), r) ->
(*IMPROVE: exclude rules of the form f .. r .. -> r *)
if not (List.mem r us) then
iter_funs
(fun g _ts ->
match def_cmp f g with
| Gt | Un -> ()
| Ge | Eq | Le | Lt -> raise Exit)
r)
(rules_of_ident f);
false
with Exit -> true;;
(** symbols smaller or equivalent to f *)
let funs_le fs =
StrMap.fold
(fun g _ gs -> if StrSet.exists (fid_le g) fs then StrSet.add g gs else gs)
(get_rules_map()) (StrSet.union fs (get_undef_funs()));;
(*****************************************************************************)
(** compute the set of constructors and the map typ ident ->
constructors, where a constructor is any symbol used in the lhs of a
rule but the top symbol *)
(*****************************************************************************)
let get_cons_map, set_cons_map = get_set StrMap.empty;;
let get_cons, set_cons = get_set StrSet.empty;;
let is_cons cid = StrSet.mem cid (get_cons());;
let cons tid =
try StrMap.find tid (get_cons_map()) with Not_found -> StrSet.empty;;
let compute_cons_set_map =
List.fold_left (* rules *)
(fun (cs, m) ((_h, ts), _r) ->
List.fold_left (* lhs arguments *)
(fun (cs, m) t ->
fold_funs
(fun id _ts (cs, m) ->
let _typs, typid = typ_of_ident id in
let cons = try StrMap.find typid m
with Not_found -> StrSet.empty in
StrSet.add id cs, StrMap.add typid (StrSet.add id cons) m)
(cs, m)
t)
(cs, m)
ts)
(StrSet.empty, StrMap.empty);;
let build_cons_set_map() =
verbose "compute type-constructor map...";
let cs, m = compute_cons_set_map (get_rules()) in
set_cons cs; set_cons_map m;
verbosef "constructor symbols: " (set ",") cs;;
(*****************************************************************************)
(** map tid -> list of pairs (f, tys) such that typ_of_ident f = tys, tid *)
(*****************************************************************************)
let get_typ_map, set_typ_map = get_set StrMap.empty;;
let compute_typ_map() =
StrMap.fold
(fun f (sy, (tys, tid)) m ->
match sy with
| Fun _ -> ladd tid (f, tys) m
| Var _ -> m)
(get_symb_typ_map())
StrMap.empty;;
let build_typ_map() =
verbose "compute type-symbol map...";
set_typ_map (compute_typ_map());;
(*****************************************************************************)
(** build the various sets and maps *)
(*****************************************************************************)
let build_maps() =
build_rules_map();
build_def_prec();
build_cons_set_map();
build_typ_map();;