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
open Options
open Format
open Sig
module Sy = Symbols
module E = Expr
module Hs = Hstring
type 'a abstract =
| Constr of { c_name : Hs.t ; c_ty : Ty.t ; c_args : (Hs.t * 'a) list }
| Select of { d_name : Hs.t ; d_ty : Ty.t ; d_arg : 'a }
| Tester of { t_name : Hs.t ; t_arg : 'a }
| Alien of 'a
module type ALIEN = sig
include Sig.X
val embed : r abstract -> r
end
let constr_of_destr ty dest =
if debug_adt () then fprintf fmt "ty = %a@." Ty.print ty;
match ty with
| Ty.Tadt (s, params) ->
let bdy = Ty.type_body s params in
begin match bdy with
| Ty.Adt cases ->
try
List.find
(fun { Ty.destrs; _ } ->
List.exists (fun (d, _) -> Hstring.equal dest d) destrs
)cases
with Not_found -> assert false
end
| _ -> assert false
module Shostak (X : ALIEN) = struct
type t = X.r abstract
type r = X.r
module SX = Set.Make(struct type t = r let compare = X.hash_cmp end)
let name = "Adt"
[@@ocaml.ppwarning "XXX: IsConstr not interpreted currently. Maybe \
it's OK"]
let is_mine_symb sy ty =
not (Options.disable_adts ()) &&
match sy, ty with
| Sy.Op (Sy.Constr _), Ty.Tadt _ -> true
| Sy.Op Sy.Destruct _, _ -> true
| _ -> false
let embed r =
match X.extract r with
| Some c -> c
| None -> Alien r
let print fmt = function
| Alien x ->
fprintf fmt "%a" X.print x
| Constr { c_name; c_args; _ } ->
fprintf fmt "%a" Hs.print c_name;
begin
match c_args with
[] -> ()
| (lbl, v) :: l ->
fprintf fmt "(%a : %a " Hs.print lbl X.print v;
List.iter
(fun (lbl, v) ->
fprintf fmt "; %a : %a" Hs.print lbl X.print v) l;
fprintf fmt ")"
end
| Select d ->
fprintf fmt "%a#!!%a" X.print d.d_arg Hs.print d.d_name
| Tester t ->
fprintf fmt "(%a ? %a)" X.print t.t_arg Hs.print t.t_name
let is_mine u =
match u with
| Alien r -> r
| Constr _ | Tester _ ->
X.embed u
[@ocaml.ppwarning "TODO: canonize Constr(list of selects)"]
| Select { d_arg; d_name; _ } ->
match embed d_arg with
| Constr c ->
begin
try snd @@ List.find (fun (lbl, _) -> Hs.equal d_name lbl) c.c_args
with Not_found ->
fprintf fmt "is_mine %a failed@." print u;
assert false
end
| _ -> X.embed u
let equal s1 s2 =
match s1, s2 with
| Alien r1, Alien r2 -> X.equal r1 r2
| Constr c1, Constr c2 ->
Hstring.equal c1.c_name c2.c_name &&
Ty.equal c1.c_ty c2.c_ty &&
begin
try
List.iter2
(fun (hs1, v1) (hs2, v2) ->
assert (Hs.equal hs1 hs2);
if not (X.equal v1 v2) then raise Exit
)c1.c_args c2.c_args;
true
with
| Exit -> false
| _ -> assert false
end
| Select d1, Select d2 ->
Hstring.equal d1.d_name d2.d_name &&
Ty.equal d1.d_ty d2.d_ty &&
X.equal d1.d_arg d2.d_arg
| Tester t1, Tester t2 ->
Hstring.equal t1.t_name t2.t_name &&
X.equal t1.t_arg t2.t_arg
| _ -> false
let make t =
assert (not (Options.disable_adts ()));
if debug_adt () then eprintf "[ADTs] make %a@." E.print t;
let { E.f; xs; ty; _ } = match E.term_view t with
| E.Term t -> t
| E.Not_a_term _ -> assert false
in
let sx, ctx =
List.fold_left
(fun (args, ctx) s ->
let rs, ctx' = X.make s in
rs :: args, List.rev_append ctx' ctx
)([], []) xs
in
let xs = List.rev sx in
match f, xs, ty with
| Sy.Op Sy.Constr hs, _, Ty.Tadt (name, params) ->
let cases =
match Ty.type_body name params with
| Ty.Adt cases -> cases
in
let case_hs =
try Ty.assoc_destrs hs cases with Not_found -> assert false
in
let c_args =
try
List.rev @@
List.fold_left2
(fun c_args v (lbl, _) -> (lbl, v) :: c_args)
[] xs case_hs
with Invalid_argument _ -> assert false
in
is_mine @@ Constr {c_name = hs; c_ty = ty; c_args}, ctx
| Sy.Op Sy.Destruct (hs, guarded), [e], _ ->
if not guarded then
let sel = Select {d_name = hs ; d_arg = e ; d_ty = ty} in
is_mine sel, ctx
else
X.term_embed t, ctx
| _ ->
assert false
let hash x =
abs @@ match x with
| Alien r ->
X.hash r
| Constr { c_name ; c_ty ; c_args } ->
List.fold_left
(fun acc (_, r) -> acc * 7 + X.hash r)
(Hstring.hash c_name + 7 * Ty.hash c_ty) c_args
| Select { d_name ; d_ty ; d_arg } ->
((Hstring.hash d_name + 11 * Ty.hash d_ty)) * 11 + X.hash d_arg
| Tester { t_name ; t_arg } ->
Hstring.hash t_name * 13 + X.hash t_arg
let leaves r =
let l = match r with
| Alien r -> [Hs.empty, r]
| Constr { c_args ; _ } -> c_args
| Select { d_arg ; _ } -> [Hs.empty, d_arg]
| Tester { t_arg ; _ } -> [Hs.empty, t_arg]
in
SX.elements @@
List.fold_left
(fun sx (_, r) ->
List.fold_left (fun sx x -> SX.add x sx) sx (X.leaves r)
)SX.empty l
[@@ocaml.ppwarning "TODO: not sure"]
let fully_interpreted _ =
false
let type_info = function
| Alien r -> X.type_info r
| Constr { c_ty ; _ } -> c_ty
| Select { d_ty ; _ } -> d_ty
| Tester _ -> Ty.Tbool
let compare s1 s2 =
match embed s1, embed s2 with
| Alien r1, Alien r2 -> X.str_cmp r1 r2
| Alien _, _ -> 1
| _, Alien _ -> -1
| Constr c1, Constr c2 ->
let c = Hstring.compare c1.c_name c2.c_name in
if c <> 0 then c
else
let c = Ty.compare c1.c_ty c2.c_ty in
if c <> 0 then c
else
begin
try
List.iter2
(fun (hs1, v1) (hs2, v2) ->
assert (Hs.equal hs1 hs2);
let c = X.str_cmp v1 v2 in
if c <> 0 then raise (Util.Cmp c);
)c1.c_args c2.c_args;
0
with
| Util.Cmp c -> c
| _ -> assert false
end
| Constr _, _ -> 1
| _, Constr _ -> -1
| Select d1, Select d2 ->
let c = Hstring.compare d1.d_name d2.d_name in
if c <> 0 then c
else
let c = Ty.compare d1.d_ty d2.d_ty in
if c <> 0 then c
else X.str_cmp d1.d_arg d2.d_arg
| Select _, _ -> 1
| _, Select _ -> -1
| Tester t1, Tester t2 ->
let c = Hstring.compare t1.t_name t2.t_name in
if c <> 0 then c
else
X.str_cmp t1.t_arg t2.t_arg
let abstract_selectors p acc =
match p with
| Alien _ -> assert false
| Constr { c_args; _ } ->
let same = ref true in
let acc, _ =
List.fold_left (fun (acc, l) (lbl, x) ->
let y, acc = X.abstract_selectors x acc in
same := !same && x == y;
acc, (lbl, y) :: l
) (acc, []) c_args
in
if !same then is_mine p, acc
else
is_mine p, acc
[@ocaml.ppwarning "TODO: abstract Selectors: case to test"]
| Tester { t_arg; _ } ->
let s_arg, acc = X.abstract_selectors t_arg acc in
if not (X.equal s_arg t_arg)
[@ocaml.ppwarning "TODO: abstract Selectors: case to test"] then
assert false;
is_mine p, acc
| Select ({ d_arg; _ } as s)
[@ocaml.ppwarning "TODO: abstract Selectors"] ->
let s_arg, acc = X.abstract_selectors d_arg acc in
if not (X.equal s_arg d_arg)
[@ocaml.ppwarning "TODO: abstract Selectors"] then
assert false;
let x = is_mine @@ Select {s with d_arg=s_arg} in
begin match embed x with
| Select ({ d_name; d_arg; _ } as s) ->
let {Ty.constr ; destrs} =
constr_of_destr (X.type_info d_arg) d_name
in
let xs = List.map (fun (_, ty) -> E.fresh_name ty) destrs in
let cons =
E.mk_term (Sy.constr (Hs.view constr)) xs (X.type_info d_arg)
in
if debug_adt () then
fprintf fmt "abstr with equality %a == %a@."
X.print d_arg E.print cons;
let cons, _ = make cons in
let acc = (d_arg, cons) :: acc in
let xx = is_mine @@ Select {s with d_arg = cons} in
if debug_adt () then
fprintf fmt "%a becomes %a@." X.print x X.print xx;
xx, acc
| _ ->
x, acc
end
let is_alien_of e x =
List.exists (fun y -> X.equal x y) (X.leaves e)
let solve r1 r2 pb =
if debug_adt () then
Format.eprintf "[ADTs] solve %a = %a@." X.print r1 X.print r2;
assert (not (Options.disable_adts ()));
match embed r1, embed r2 with
| Select _, _ | _, Select _ -> assert false
| Tester _, _ | _, Tester _ -> assert false
| Alien _, Alien _ ->
{ pb with
sbt = (if X.str_cmp r1 r2 > 0 then r1, r2 else r2, r1) :: pb.sbt }
| Alien r, Constr _ ->
if is_alien_of r2 r then raise Util.Unsolvable;
{ pb with sbt = (r, r2) :: pb.sbt }
| Constr _, Alien r ->
if is_alien_of r1 r then raise Util.Unsolvable;
{ pb with sbt = (r, r1) :: pb.sbt }
| Constr c1, Constr c2 ->
if not (Hstring.equal c1.c_name c2.c_name) then raise Util.Unsolvable;
try
{pb with
eqs =
List.fold_left2
(fun eqs (hs1, v1) (hs2, v2) ->
assert (Hstring.equal hs1 hs2);
(v1, v2) :: eqs
)pb.eqs c1.c_args c2.c_args
}
with Invalid_argument _ -> assert false
let subst p v s =
assert (not (Options.disable_adts ()));
match s with
| Alien r -> if X.equal p r then v else X.subst p v r
| Constr c ->
is_mine @@
Constr
{ c with
c_args = List.map (fun (lbl, u) -> lbl, X.subst p v u) c.c_args }
| Select d ->
is_mine @@ Select { d with d_arg = X.subst p v d.d_arg }
| Tester t ->
is_mine @@ Tester { t with t_arg = X.subst p v t.t_arg }
let color _ = assert false
let _ = None, false
let assign_value _ _ _ =
fprintf fmt "[ADTs.models] assign_value currently not implemented";
assert false
let choose_adequate_model _ _ _ =
fprintf fmt "[ADTs.models] choose_adequate_model currently not implemented";
assert false
end