/[svn]/types/types.ml
ViewVC logotype

Contents of /types/types.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 156 - (show annotations)
Tue Jul 10 17:11:11 2007 UTC (5 years, 10 months ago) by abate
File size: 37628 byte(s)
[r2002-11-25 23:29:46 by cvscast] Empty log message

Original author: cvscast
Date: 2002-11-25 23:29:47+00:00
1 open Recursive
2 open Printf
3
4
5 let map_sort f l =
6 SortedList.from_list (List.map f l)
7
8 module HashedString =
9 struct
10 type t = string
11 let hash = Hashtbl.hash
12 let equal = (=)
13 end
14
15 module LabelPool = Pool.Make(HashedString)
16 module AtomPool = Pool.Make(HashedString)
17
18 type label = LabelPool.t
19 type atom = AtomPool.t
20
21 type const = Integer of Big_int.big_int | Atom of atom | Char of Chars.Unichar.t
22
23 type pair_kind = [ `Normal | `XML ]
24
25 module I = struct
26 type 'a t = {
27 atoms : atom Atoms.t;
28 ints : Intervals.t;
29 chars : Chars.t;
30 times : ('a * 'a) Boolean.t;
31 xml : ('a * 'a) Boolean.t;
32 arrow : ('a * 'a) Boolean.t;
33 (* record: (label * bool * 'a) Boolean.t; *)
34 record: (bool * (label, (bool * 'a)) SortedMap.t) Boolean.t;
35 }
36
37 let empty = {
38 times = Boolean.empty;
39 xml = Boolean.empty;
40 arrow = Boolean.empty;
41 record= Boolean.empty;
42 ints = Intervals.empty;
43 atoms = Atoms.empty;
44 chars = Chars.empty;
45 }
46
47 let any = {
48 times = Boolean.full;
49 xml = Boolean.full;
50 arrow = Boolean.full;
51 record= Boolean.full;
52 ints = Intervals.any;
53 atoms = Atoms.any;
54 chars = Chars.any;
55 }
56
57
58 let interval i = { empty with ints = i }
59 let times x y = { empty with times = Boolean.atom (x,y) }
60 let xml x y = { empty with xml = Boolean.atom (x,y) }
61 let arrow x y = { empty with arrow = Boolean.atom (x,y) }
62 let record label opt t =
63 { empty with record = Boolean.atom (true,[label,(opt,t)]) }
64 let atom a = { empty with atoms = a }
65 let char c = { empty with chars = c }
66 let constant = function
67 | Integer i -> interval (Intervals.atom i)
68 | Atom a -> atom (Atoms.atom a)
69 | Char c -> char (Chars.atom c)
70
71
72 let cup x y =
73 if x = y then x else {
74 times = Boolean.cup x.times y.times;
75 xml = Boolean.cup x.xml y.xml;
76 arrow = Boolean.cup x.arrow y.arrow;
77 record= Boolean.cup x.record y.record;
78 ints = Intervals.cup x.ints y.ints;
79 atoms = Atoms.cup x.atoms y.atoms;
80 chars = Chars.cup x.chars y.chars;
81 }
82
83 let cap x y =
84 if x = y then x else {
85 times = Boolean.cap x.times y.times;
86 xml = Boolean.cap x.xml y.xml;
87 record= Boolean.cap x.record y.record;
88 arrow = Boolean.cap x.arrow y.arrow;
89 ints = Intervals.cap x.ints y.ints;
90 atoms = Atoms.cap x.atoms y.atoms;
91 chars = Chars.cap x.chars y.chars;
92 }
93
94 let diff x y =
95 if x = y then empty else {
96 times = Boolean.diff x.times y.times;
97 xml = Boolean.diff x.xml y.xml;
98 arrow = Boolean.diff x.arrow y.arrow;
99 record= Boolean.diff x.record y.record;
100 ints = Intervals.diff x.ints y.ints;
101 atoms = Atoms.diff x.atoms y.atoms;
102 chars = Chars.diff x.chars y.chars;
103 }
104
105
106 let rec equal_rec e r1 r2 =
107 match (r1,r2) with
108 | [],[] -> ()
109 | (l1,(o1,x1))::r1,(l2,(o2,x2))::r2 ->
110 if (l1 <> l2) || (o1 <> o2) then raise NotEqual;
111 e x1 x2; equal_rec e r1 r2
112 | _ -> raise NotEqual
113 (* check: faster to reverse the calls to e and to equal_rec ? *)
114
115 let equal e a b =
116 if a.atoms <> b.atoms then raise NotEqual;
117 if a.chars <> b.chars then raise NotEqual;
118 if a.ints <> b.ints then raise NotEqual;
119 Boolean.equal (fun (x1,x2) (y1,y2) -> e x1 y1; e x2 y2) a.times b.times;
120 Boolean.equal (fun (x1,x2) (y1,y2) -> e x1 y1; e x2 y2) a.xml b.xml;
121 Boolean.equal (fun (x1,x2) (y1,y2) -> e x1 y1; e x2 y2) a.arrow b.arrow;
122 Boolean.equal (fun (o1,r1) (o2,r2) ->
123 if (o1 <> o2) then raise NotEqual;
124 equal_rec e r1 r2)
125 a.record b.record
126
127 let map f a =
128 { times = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.times;
129 xml = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.xml;
130 arrow = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.arrow;
131 record= Boolean.map (fun (o,r) ->
132 (o, List.map (fun (l,(o,x)) -> (l,(o,f x))) r))
133 a.record;
134 ints = a.ints;
135 atoms = a.atoms;
136 chars = a.chars;
137 }
138
139 let hash h a =
140 Hashtbl.hash (map h a)
141 (*
142 (Hashtbl.hash { (map h a) with ints = Intervals.empty })
143 + (Intervals.hash a.ints)
144 *)
145
146 let iter f a =
147 ignore (map f a)
148
149 let deep = 4
150 end
151
152
153 module Algebra = Recursive_noshare.Make(I)
154 include I
155 include Algebra
156 module DescrHash =
157 Hashtbl.Make(
158 struct
159 type t = descr
160 let hash = hash_descr
161 let equal = equal_descr
162 end
163 )
164
165 let print_descr = ref (fun _ _ -> assert false)
166
167 (*
168 let define n d = check d; define n d
169 *)
170
171 let cons d =
172 let n = make () in
173 define n d;
174 internalize n
175
176 (*
177 let any_rec = cons { empty with record = Boolean.full }
178 let any_node = make ();;
179 define any_node {
180 times = Boolean.full;
181 xml = Boolean.atom
182 (cons { empty with atoms = Atoms.any },
183 cons (times any_rec any_node));
184 arrow = Boolean.full;
185 record= Boolean.full;
186 ints = Intervals.any;
187 atoms = Atoms.any;
188 chars = Chars.any;
189 };;
190 internalize any_node;;
191 let any = descr any_node
192 *)
193
194 let neg x = diff any x
195
196 (*
197 let get_record r =
198 let add = SortedMap.add (fun (o1,t1) (o2,t2) -> (o1&&o2, cap t1 t2)) in
199 let line (p,n) =
200 let accu = List.fold_left
201 (fun accu (l,o,t) -> add l (o,descr t) accu) [] p in
202 List.fold_left
203 (fun accu (l,o,t) -> add l (not o,neg (descr t)) accu) accu n in
204 List.map line r
205 *)
206
207 module LabelSet = Set.Make(LabelPool)
208
209 let get_record r =
210 let labs accu (_,r) =
211 List.fold_left (fun accu (l,_) -> LabelSet.add l accu) accu r in
212 let extend (opts,descrs) labs (o,r) =
213 let rec aux i labs r =
214 match labs with
215 | [] -> ()
216 | l1::labs ->
217 match r with
218 | (l2,(o,x))::r when l1 = l2 ->
219 descrs.(i) <- cap descrs.(i) (descr x);
220 opts.(i) <- opts.(i) && o;
221 aux (i+1) labs r
222 | r ->
223 if not o then descrs.(i) <- empty;
224 aux (i+1) labs r
225 in
226 aux 0 labs r;
227 o
228 in
229 let line (p,n) =
230 let labels =
231 List.fold_left labs (List.fold_left labs LabelSet.empty p) n in
232 let labels = LabelSet.elements labels in
233 let nlab = List.length labels in
234 let mk () = Array.create nlab true, Array.create nlab any in
235
236 let pos = mk () in
237 let opos = List.fold_left
238 (fun accu x ->
239 (extend pos labels x) && accu)
240 true p in
241 let p = (opos, pos) in
242
243 let n = List.map (fun x ->
244 let neg = mk () in
245 let o = extend neg labels x in
246 (o,neg)
247 ) n in
248 (labels,p,n)
249 in
250 List.map line r
251
252
253 module DescrMap = Map.Make(struct type t = descr let compare = compare end)
254
255 let check d =
256 Boolean.check d.times;
257 Boolean.check d.xml;
258 Boolean.check d.arrow;
259 Boolean.check d.record;
260 ()
261
262
263
264 (* Subtyping algorithm *)
265
266 let diff_t d t = diff d (descr t)
267 let cap_t d t = cap d (descr t)
268 let cup_t d t = cup d (descr t)
269 let cap_product l =
270 List.fold_left
271 (fun (d1,d2) (t1,t2) -> (cap_t d1 t1, cap_t d2 t2))
272 (any,any)
273 l
274
275
276 let cup_product l =
277 List.fold_left
278 (fun (d1,d2) (t1,t2) -> (cup_t d1 t1, cup_t d2 t2))
279 (empty,empty)
280 l
281
282 let rec exists max f =
283 (max > 0) && (f (max - 1) || exists (max - 1) f)
284
285
286 module Assumptions = Set.Make(struct type t = descr let compare = compare end)
287
288 let memo = ref Assumptions.empty
289 let cache_false = ref Assumptions.empty
290
291 exception NotEmpty
292
293 let rec empty_rec d =
294 if Assumptions.mem d !cache_false then false
295 else if Assumptions.mem d !memo then true
296 else if not (Intervals.is_empty d.ints) then false
297 else if not (Atoms.is_empty d.atoms) then false
298 else if not (Chars.is_empty d.chars) then false
299 else (
300 let backup = !memo in
301 memo := Assumptions.add d backup;
302 if
303 (empty_rec_times d.times) &&
304 (empty_rec_times d.xml) &&
305 (empty_rec_arrow d.arrow) &&
306 (empty_rec_record d.record)
307 then true
308 else (
309 memo := backup;
310 cache_false := Assumptions.add d !cache_false;
311 false
312 )
313 )
314
315 and empty_rec_times c =
316 List.for_all empty_rec_times_aux c
317
318 and empty_rec_times_aux (left,right) =
319 let rec aux accu1 accu2 = function
320 | (t1,t2)::right ->
321 (* This avoids explosion with huge rhs (+/- degenerated partitioning)
322 May be slower when List.length right is small; could optimize
323 this case... *)
324 if empty_rec (cap_t accu1 t1) || empty_rec (cap_t accu2 t2) then
325 aux accu1 accu2 right
326 else
327 let accu1' = diff_t accu1 t1 in
328 if not (empty_rec accu1') then aux accu1' accu2 right;
329 let accu2' = diff_t accu2 t2 in
330 if not (empty_rec accu2') then aux accu1 accu2' right
331 | [] -> raise NotEmpty
332 in
333 let (accu1,accu2) = cap_product left in
334 (*
335 let right' = List.filter
336 (fun (t1,t2) ->
337 not
338 (empty_rec (cap_t accu1 t1) || empty_rec (cap_t accu2 t2)
339 )
340 ) right in
341 if List.length right > 15 then (
342 Format.fprintf Format.std_formatter "[%i=>%i]@."
343 (List.length right) (List.length right');
344 Format.fprintf Format.std_formatter "(%a,%a)@."
345 !print_descr accu1
346 !print_descr accu2;
347 List.iter (fun (t1,t2) ->
348 Format.fprintf Format.std_formatter "\ (%a,%a)@."
349 !print_descr (descr t1)
350 !print_descr (descr t2);
351 ) right
352 );
353 let right = right' in
354 *)
355
356 (empty_rec accu1) || (empty_rec accu2) ||
357 (* OPT? It does'nt seem so ... The hope was to return false quickly
358 for large right hand-side *)
359 (
360 (* (if (List.length right > 2) then
361 let (cup1,cup2) = cup_product right in
362 (empty_rec (diff accu1 cup1)) && (empty_rec (diff accu2 cup2))
363 else true)
364 && *)
365 (try aux accu1 accu2 right; true with NotEmpty -> false)
366 )
367
368 and empty_rec_arrow c =
369 List.for_all empty_rec_arrow_aux c
370
371 and empty_rec_arrow_aux (left,right) =
372 let single_right (s1,s2) =
373 let rec aux accu1 accu2 = function
374 | (t1,t2)::left ->
375 let accu1' = diff_t accu1 t1 in
376 if not (empty_rec accu1') then aux accu1 accu2 left;
377 let accu2' = cap_t accu2 t2 in
378 if not (empty_rec accu2') then aux accu1 accu2 left
379 | [] -> raise NotEmpty
380 in
381 let accu1 = descr s1 in
382 (empty_rec accu1) ||
383 (try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false)
384 in
385 List.exists single_right right
386
387 and empty_rec_record_aux (labels,(oleft,(left_opt,left)),rights) =
388 let rec aux = function
389 | [] -> raise NotEmpty
390 | (oright,(right_opt,right))::rights ->
391 let next =
392 (oleft && (not oright)) ||
393 exists (Array.length left)
394 (fun i ->
395 (not (left_opt.(i) && right_opt.(i))) &&
396 (empty_rec (cap left.(i) right.(i))))
397 in
398 if next then aux rights
399 else
400 for i = 0 to Array.length left - 1 do
401 let back = left.(i) in
402 let oback = left_opt.(i) in
403 let odi = oback && (not right_opt.(i)) in
404 let di = diff back right.(i) in
405 if odi || not (empty_rec di) then (
406 left.(i) <- diff back right.(i);
407 left_opt.(i) <- odi;
408 aux rights;
409 left.(i) <- back;
410 left_opt.(i) <- oback;
411 )
412 done
413 in
414 exists (Array.length left)
415 (fun i -> not left_opt.(i) && (empty_rec left.(i)))
416 ||
417 (try aux rights; true with NotEmpty -> false)
418
419
420 and empty_rec_record c =
421 (*
422 let aux = List.exists (fun (_,(opt,t)) -> (not opt) && (empty_rec t)) in
423 *)
424 List.for_all empty_rec_record_aux (get_record c)
425
426 let is_empty d =
427 (* Printf.eprintf "+"; flush stderr; *)
428 let old = !memo in
429 let r = empty_rec d in
430 if not r then memo := old;
431 (* cache_false := Assumptions.empty; *)
432 (* Printf.eprintf "-\n"; flush stderr; *)
433 r
434
435 let non_empty d =
436 not (is_empty d)
437
438 let subtype d1 d2 =
439 is_empty (diff d1 d2)
440
441 module Product =
442 struct
443 type t = (descr * descr) list
444
445 let other ?(kind=`Normal) d =
446 match kind with
447 | `Normal -> { d with times = empty.times }
448 | `XML -> { d with xml = empty.xml }
449
450 let is_product ?kind d = is_empty (other ?kind d)
451
452 let need_second = function _::_::_ -> true | _ -> false
453
454 let normal_aux d =
455 let res = ref [] in
456
457 let add (t1,t2) =
458 let rec loop t1 t2 = function
459 | [] -> res := (ref (t1,t2)) :: !res
460 | ({contents = (d1,d2)} as r)::l ->
461 (*OPT*)
462 if d1 = t1 then r := (d1,cup d2 t2) else
463
464 let i = cap t1 d1 in
465 if is_empty i then loop t1 t2 l
466 else (
467 r := (i, cup t2 d2);
468 let k = diff d1 t1 in
469 if non_empty k then res := (ref (k,d2)) :: !res;
470
471 let j = diff t1 d1 in
472 if non_empty j then loop j t2 l
473 )
474 in
475 loop t1 t2 !res
476 in
477 List.iter add d;
478 List.map (!) !res
479
480 (*
481 This version explodes when dealing with
482 Any - [ t1? t2? t3? ... tn? ]
483 ==> need partitioning
484 *)
485 let get_aux d =
486 let line accu (left,right) =
487 let rec aux accu d1 d2 = function
488 | (t1,t2)::right ->
489 let accu =
490 let d1 = diff_t d1 t1 in
491 if is_empty d1 then accu else aux accu d1 d2 right in
492 let accu =
493 let d2 = diff_t d2 t2 in
494 if is_empty d2 then accu else aux accu d1 d2 right in
495 accu
496 | [] -> (d1,d2) :: accu
497 in
498 let (d1,d2) = cap_product left in
499 if (is_empty d1) || (is_empty d2) then accu else aux accu d1 d2 right
500 in
501 List.fold_left line [] d
502
503 (* Partitioning:
504
505 (t,s) - ((t1,s1) | (t2,s2) | ... | (tn,sn))
506 =
507 (t & t1, s - s1) | ... | (t & tn, s - sn) | (t - (t1|...|tn), s)
508
509 *)
510 let get_aux d =
511 let accu = ref [] in
512 let line (left,right) =
513 let (d1,d2) = cap_product left in
514 if (non_empty d1) && (non_empty d2) then
515 let right = List.map (fun (t1,t2) -> descr t1, descr t2) right in
516 let right = normal_aux right in
517 let resid1 = ref d1 in
518 let () =
519 List.iter
520 (fun (t1,t2) ->
521 let t1 = cap d1 t1 in
522 if (non_empty t1) then
523 let () = resid1 := diff !resid1 t1 in
524 let t2 = diff d2 t2 in
525 if (non_empty t2) then accu := (t1,t2) :: !accu
526 ) right in
527 if non_empty !resid1 then accu := (!resid1, d2) :: !accu
528 in
529 List.iter line d;
530 !accu
531
532 let get ?(kind=`Normal) d =
533 match kind with
534 | `Normal -> get_aux d.times
535 | `XML -> get_aux d.xml
536
537 let pi1 = List.fold_left (fun acc (t1,_) -> cup acc t1) empty
538 let pi2 = List.fold_left (fun acc (_,t2) -> cup acc t2) empty
539
540 let restrict_1 rects pi1 =
541 let aux accu (t1,t2) =
542 let t1 = cap t1 pi1 in if is_empty t1 then accu else (t1,t2)::accu in
543 List.fold_left aux [] rects
544
545 type normal = t
546
547 module Memo = Map.Make(struct
548 type t = (node * node) Boolean.t
549 let compare = compare end)
550
551
552
553 let memo = ref Memo.empty
554 let normal ?(kind=`Normal) d =
555 let d = match kind with `Normal -> d.times | `XML -> d.xml in
556 try Memo.find d !memo
557 with
558 Not_found ->
559 let gd = get_aux d in
560 let n = normal_aux gd in
561 memo := Memo.add d n !memo;
562 n
563
564 let any = { empty with times = any.times }
565 and any_xml = { empty with xml = any.xml }
566 let is_empty d = d = []
567 end
568
569 module Print =
570 struct
571 let rec print_union ppf = function
572 | [] -> Format.fprintf ppf "Empty"
573 | [h] -> h ppf
574 | h::t -> Format.fprintf ppf "@[%t |@ %a@]" h print_union t
575
576 let print_atom ppf a =
577 Format.fprintf ppf "`%s" (AtomPool.value a)
578
579 let print_tag ppf a =
580 match Atoms.is_atom a with
581 | Some a -> Format.fprintf ppf "%s" (AtomPool.value a)
582 | None ->
583 Format.fprintf ppf "(%a)"
584 print_union
585 (Atoms.print "Atom" print_atom a)
586
587 let print_const ppf = function
588 | Integer i -> Format.fprintf ppf "%s" (Big_int.string_of_big_int i)
589 | Atom a -> print_atom ppf a
590 | Char c -> Chars.Unichar.print ppf c
591
592 let named = State.ref "Types.Printf.named" DescrMap.empty
593 let register_global name d =
594 named := DescrMap.add d name !named
595
596 let marks = DescrHash.create 63
597 let wh = ref []
598 let count_name = ref 0
599 let name () =
600 incr count_name;
601 "X" ^ (string_of_int !count_name)
602 (* TODO:
603 check that these generated names does not conflict with declared types *)
604
605 let bool_iter f b =
606 List.iter (fun (p,n) -> List.iter f p; List.iter f n) b
607
608 let trivial b = b = Boolean.empty || b = Boolean.full
609
610 let worth_abbrev d =
611 not (trivial d.times && trivial d.arrow && trivial d.record)
612
613 let rec mark n = mark_descr (descr n)
614 and mark_descr d =
615 if not (DescrMap.mem d !named) then
616 try
617 let r = DescrHash.find marks d in
618 if (!r = None) && (worth_abbrev d) then
619 let na = name () in
620 r := Some na;
621 wh := (na,d) :: !wh
622 with Not_found ->
623 DescrHash.add marks d (ref None);
624 bool_iter (fun (n1,n2) -> mark n1; mark n2) d.times;
625 bool_iter
626 (fun (n1,n2) -> mark n1; mark n2
627 (*
628 List.iter
629 (fun (d1,d2) ->
630 mark_descr d2;
631 bool_iter
632 (fun (o,l) -> List.iter (fun (l,(o,n)) -> mark n) l)
633 d1.record
634 let l = get_record d1.record in
635 List.iter (fun labs,(_,(_,p)),ns ->
636 Array.iter mark_descr p;
637 List.iter (fun (_,(_,n)) ->
638 Array.iter mark_descr n) ns
639 ) l
640 )
641 (Product.normal (descr n2))
642 *)
643 ) d.xml;
644 bool_iter (fun (n1,n2) -> mark n1; mark n2) d.arrow;
645 bool_iter (fun (o,l) -> List.iter (fun (l,(o,n)) -> mark n) l) d.record
646
647
648 let rec print ppf n = print_descr ppf (descr n)
649 and print_descr ppf d =
650 try
651 let name = DescrMap.find d !named in
652 Format.fprintf ppf "%s" name
653 with Not_found ->
654 try
655 match !(DescrHash.find marks d) with
656 | Some n -> Format.fprintf ppf "%s" n
657 | None -> real_print_descr ppf d
658 with
659 Not_found -> assert false
660 and real_print_descr ppf d =
661 if d = any then Format.fprintf ppf "Any" else
662 print_union ppf
663 (Intervals.print d.ints @
664 Chars.print d.chars @
665 Atoms.print "Atom" print_atom d.atoms @
666 Boolean.print "Pair" print_times d.times @
667 Boolean.print "XML" print_xml d.xml @
668 Boolean.print "Arrow" print_arrow d.arrow @
669 Boolean.print "Record" print_record d.record
670 )
671 and print_times ppf (t1,t2) =
672 Format.fprintf ppf "@[(%a,%a)@]" print t1 print t2
673 and print_xml ppf (t1,t2) =
674 Format.fprintf ppf "@[XML(%a,%a)@]" print t1 print t2
675 (*
676 let l = Product.normal (descr t2) in
677 let l = List.map
678 (fun (d1,d2) ppf ->
679 Format.fprintf ppf "@[<><%a%a>%a@]"
680 print_tag (descr t1).atoms
681 print_attribs d1.record
682 print_descr d2) l
683 in
684 print_union ppf l
685 *)
686 and print_arrow ppf (t1,t2) =
687 Format.fprintf ppf "@[(%a -> %a)@]" print t1 print t2
688 and print_record ppf (o,r) =
689 let o = if o then "" else "|" in
690 Format.fprintf ppf "@[{%s" o;
691 let first = ref true in
692 List.iter (fun (l,(o,t)) ->
693 let sep = if !first then (first := false; " ") else ";@ " in
694 Format.fprintf ppf "%s@[%s =%s@] %a" sep
695 (LabelPool.value l) (if o then "?" else "") print t
696 ) r;
697 Format.fprintf ppf " %s}@]" o
698 (*
699 and print_attribs ppf r =
700 let l = get_record r in
701 if l <> [ [] ] then
702 let l = List.map
703 (fun att ppf ->
704 let first = ref true in
705 Format.fprintf ppf "{" ;
706 List.iter (fun (l,(o,d)) ->
707 Format.fprintf ppf "%s%s=%s%a"
708 (if !first then "" else " ")
709 (LabelPool.value l) (if o then "?" else "")
710 print_descr d;
711 first := false
712 ) att;
713 Format.fprintf ppf "}"
714 ) l in
715 print_union ppf l
716 *)
717
718
719 let end_print ppf =
720 (match List.rev !wh with
721 | [] -> ()
722 | (na,d)::t ->
723 Format.fprintf ppf " where@ @[%s = %a" na real_print_descr d;
724 List.iter
725 (fun (na,d) ->
726 Format.fprintf ppf " and@ %s = %a" na real_print_descr d)
727 t;
728 Format.fprintf ppf "@]"
729 );
730 Format.fprintf ppf "@]";
731 count_name := 0;
732 wh := [];
733 DescrHash.clear marks
734
735 let print_descr ppf d =
736 mark_descr d;
737 Format.fprintf ppf "@[%a" print_descr d;
738 end_print ppf
739
740 let print ppf n = print_descr ppf (descr n)
741
742 end
743
744 let () = print_descr := Print.print_descr
745
746 module Positive =
747 struct
748 type rhs = [ `Type of descr | `Cup of v list | `Times of v * v ]
749 and v = { mutable def : rhs; mutable node : node option }
750
751
752 let rec make_descr seen v =
753 if List.memq v seen then empty
754 else
755 let seen = v :: seen in
756 match v.def with
757 | `Type d -> d
758 | `Cup vl ->
759 List.fold_left (fun acc v -> cup acc (make_descr seen v)) empty vl
760 | `Times (v1,v2) -> times (make_node v1) (make_node v2)
761
762 and make_node v =
763 match v.node with
764 | Some n -> n
765 | None ->
766 let n = make () in
767 v.node <- Some n;
768 let d = make_descr [] v in
769 define n d;
770 n
771
772 let forward () = { def = `Cup []; node = None }
773 let def v d = v.def <- d
774 let cons d = let v = forward () in def v d; v
775 let ty d = cons (`Type d)
776 let cup vl = cons (`Cup vl)
777 let times d1 d2 = cons (`Times (d1,d2))
778 let define v1 v2 = def v1 (`Cup [v2])
779
780 let solve v = internalize (make_node v)
781 end
782
783
784
785
786 (* Sample value *)
787 module Sample =
788 struct
789
790 let rec find f = function
791 | [] -> raise Not_found
792 | x::r -> try f x with Not_found -> find f r
793
794 type t =
795 | Int of Big_int.big_int
796 | Atom of atom
797 | Char of Chars.Unichar.t
798 | Pair of (t * t)
799 | Xml of (t * t)
800 | Record of (label * t) list
801 | Fun of (node * node) list
802 | Other
803
804 let rec sample_rec memo d =
805 if (Assumptions.mem d memo) || (is_empty d) then raise Not_found
806 else
807 try Int (Intervals.sample d.ints) with Not_found ->
808 try Atom (Atoms.sample (fun _ -> AtomPool.dummy_min) d.atoms) with
809 Not_found ->
810 (* Here: could create a fresh atom ... *)
811 try Char (Chars.sample d.chars) with Not_found ->
812 try sample_rec_arrow d.arrow with Not_found ->
813
814 let memo = Assumptions.add d memo in
815 try Pair (sample_rec_times memo d.times) with Not_found ->
816 try Xml (sample_rec_times memo d.xml) with Not_found ->
817 try sample_rec_record memo d.record with Not_found ->
818 raise Not_found
819
820
821 and sample_rec_times memo c =
822 find (sample_rec_times_aux memo) c
823
824 and sample_rec_times_aux memo (left,right) =
825 let rec aux accu1 accu2 = function
826 | (t1,t2)::right ->
827 let accu1' = diff_t accu1 t1 in
828 if non_empty accu1' then aux accu1' accu2 right else
829 let accu2' = diff_t accu2 t2 in
830 if non_empty accu2' then aux accu1 accu2' right else
831 raise Not_found
832 | [] -> (sample_rec memo accu1, sample_rec memo accu2)
833 in
834 let (accu1,accu2) = cap_product left in
835 if (is_empty accu1) || (is_empty accu2) then raise Not_found;
836 aux accu1 accu2 right
837
838 and sample_rec_arrow c =
839 find sample_rec_arrow_aux c
840
841 and check_empty_simple_arrow_line left (s1,s2) =
842 let rec aux accu1 accu2 = function
843 | (t1,t2)::left ->
844 let accu1' = diff_t accu1 t1 in
845 if non_empty accu1' then aux accu1 accu2 left;
846 let accu2' = cap_t accu2 t2 in
847 if non_empty accu2' then aux accu1 accu2 left
848 | [] -> raise NotEmpty
849 in
850 let accu1 = descr s1 in
851 (is_empty accu1) ||
852 (try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false)
853
854 and check_empty_arrow_line left right =
855 List.exists (check_empty_simple_arrow_line left) right
856
857 and sample_rec_arrow_aux (left,right) =
858 if (check_empty_arrow_line left right) then raise Not_found
859 else Fun left
860
861
862 and sample_rec_record memo c =
863 Record (find (sample_rec_record_aux memo) (get_record c))
864
865 and sample_rec_record_aux memo fields =
866 (*TODO*)
867 raise Not_found
868 (*
869 let aux acc (l,(o,t)) = if o then acc else (l, sample_rec memo t) :: acc in
870 List.fold_left aux [] fields
871 *)
872
873 let get x = try sample_rec Assumptions.empty x with Not_found -> Other
874
875 let rec print_sep f sep ppf = function
876 | [] -> ()
877 | [x] -> f ppf x
878 | x::rem -> f ppf x; Format.fprintf ppf "%s" sep; print_sep f sep ppf rem
879
880
881 let rec print ppf = function
882 | Int i -> Format.fprintf ppf "%s" (Big_int.string_of_big_int i)
883 | Atom a ->
884 if a = LabelPool.dummy_min then
885 Format.fprintf ppf "(almost any atom)"
886 else
887 Format.fprintf ppf "`%s" (AtomPool.value a)
888 | Char c -> Chars.Unichar.print ppf c
889 | Pair (x1,x2) -> Format.fprintf ppf "(%a,%a)" print x1 print x2
890 | Xml (x1,x2) -> Format.fprintf ppf "XML(%a,%a)" print x1 print x2
891 | Record r ->
892 Format.fprintf ppf "{ %a }"
893 (print_sep
894 (fun ppf (l,x) ->
895 Format.fprintf ppf "%s = %a"
896 (LabelPool.value l)
897 print x
898 )
899 " ; "
900 ) r
901 | Fun iface ->
902 Format.fprintf ppf "(fun ( %a ) x -> ...)"
903 (print_sep
904 (fun ppf (t1,t2) ->
905 Format.fprintf ppf "%a -> %a; "
906 Print.print t1 Print.print t2
907 )
908 " ; "
909 ) iface
910 | Other ->
911 Format.fprintf ppf "[cannot determine value]"
912 end
913
914
915
916 module Record =
917 struct
918 type atom = bool * (label, (bool * node)) SortedMap.t
919 type t = atom Boolean.t
920
921 let get d = d.record
922
923 let restrict_label_absent t l =
924 Boolean.compute_bool
925 (fun (o,r) as x ->
926 try
927 let (lo,_) = List.assoc l r in
928 if lo then Boolean.atom (o,SortedMap.diff r [l])
929 else Boolean.empty
930 with Not_found -> Boolean.atom x
931 )
932 t
933
934 let restrict_field t l d =
935 (* Is it correct ? Do we need to keep track of "first component"
936 (value of l) as in label_present, then filter at the end ... ? *)
937 Boolean.compute_bool
938 (fun (o,r) as x ->
939 try
940 let (lo,lt) = List.assoc l r in
941 if (not lo) && (is_empty (cap d (descr lt))) then Boolean.empty
942 else Boolean.atom (o, SortedMap.diff r [l])
943 with Not_found ->
944 if o then Boolean.atom x else Boolean.empty
945 )
946 t
947
948
949 module T = struct
950 type t = descr
951 let any = any
952 let cap = cap
953 let cup = cup
954 let diff = diff
955 let empty = is_empty
956 end
957 module R = struct
958 type t = atom Boolean.t
959 let any = Boolean.full
960 let cap = Boolean.cap
961 let cup = Boolean.cup
962 let diff = Boolean.diff
963 let empty x = is_empty { empty with record = x }
964 end
965 module TR = Normal.Make(T)(R)
966
967 let label_present (t:t) l : (descr * t) list =
968 let x =
969 Boolean.compute_bool
970 (fun (o,r) as x ->
971 try
972 let (_,lt) = List.assoc l r in
973 Boolean.atom (descr lt, Boolean.atom (o, SortedMap.diff r [l]))
974 with Not_found ->
975 if o then Boolean.atom (any, Boolean.atom x) else Boolean.empty
976 )
977 t
978 in
979 TR.boolean x
980
981 let is_label_present t l =
982 Boolean.compute
983 ~empty:false ~full:true
984 ~cup:(||) ~cap:(&&)
985 ~diff:(fun x y -> x && not y)
986 ~atom:(fun (o,r) ->
987 try let (lo,_) = List.assoc l r in not lo
988 with Not_found -> false
989 )
990 t
991
992 let restrict_label_present t l =
993 t
994 (*
995 let r = label_present t l in
996 List.fold_left (fun accu (_,t) -> Boolean.cup accu t) Boolean.empty r
997 *)
998
999 let project_field t l =
1000 let r = label_present t l in
1001 List.fold_left (fun accu (d,_) -> cup accu d) empty r
1002
1003 let project t l =
1004 let t = get t in
1005 if is_label_present t l then project_field t l else raise Not_found
1006
1007 type normal =
1008 [ `Success
1009 | `Fail
1010 | `Label of label * (descr * normal) list * normal ]
1011
1012 let first_label t =
1013 let min = ref None in
1014 let lab l = match !min with
1015 | Some l' when l >= l' -> ()
1016 | _ -> min := Some l in
1017 let aux = function
1018 | _,[] -> ()
1019 | _,(l,_)::_ -> lab l in
1020 Boolean.iter aux t;
1021 match !min with
1022 | Some l -> `Label l
1023 | None ->
1024 let n =
1025 Boolean.compute
1026 ~empty:0
1027 ~full:3
1028 ~cup:(lor)
1029 ~cap:(land)
1030 ~diff:(fun a b -> a land lnot b)
1031 ~atom:(function (true,[]) -> 3 | (false,[]) -> 1 | _ -> assert false)
1032 t in
1033 match n with
1034 | 0 -> `Fail
1035 | 1 -> `NoField
1036 | 2 -> `SomeField
1037 | _ -> `Success
1038
1039
1040 let rec normal_aux t =
1041 match first_label t with
1042 | `Label l ->
1043 let present = label_present t l
1044 and absent = restrict_label_absent t l in
1045 `Label (l, List.map (fun (d,t) -> d, normal_aux t) present,
1046 normal_aux absent)
1047 | `Fail -> `Fail
1048 | `Success -> `Success
1049 | _ -> assert false
1050
1051 let normal t = normal_aux (get t)
1052
1053
1054
1055 let descr x = { empty with record = x }
1056 let is_empty x = is_empty (descr x)
1057 (*
1058
1059 type t = (label, (bool * descr)) SortedMap.t list
1060
1061 let get d =
1062 let line r = List.for_all (fun (l,(o,d)) -> o || non_empty d) r in
1063 List.filter line (get_record d.record)
1064
1065 let restrict_label_present t l =
1066 let restr = function
1067 | (true, d) -> if non_empty d then (false,d) else raise Exit
1068 | x -> x in
1069 let aux accu r =
1070 try SortedMap.change l restr (false,any) r :: accu
1071 with Exit -> accu in
1072 List.fold_left aux [] t
1073
1074 let restrict_label_absent t l =
1075 let restr = function (true, _) -> (true,empty) | _ -> raise Exit in
1076 let aux accu r =
1077 try SortedMap.change l restr (true,empty) r :: accu
1078 with Exit -> accu in
1079 List.fold_left aux [] t
1080
1081 let restrict_field t l d =
1082 let restr (_,d1) =
1083 let d1 = cap d d1 in
1084 if is_empty d1 then raise Exit else (false,d1) in
1085 let aux accu r =
1086 try SortedMap.change l restr (false,d) r :: accu
1087 with Exit -> accu in
1088 List.fold_left aux [] t
1089
1090 let project_field t l =
1091 let aux accu x =
1092 match List.assoc l x with
1093 | (false,t) -> cup accu t
1094 | _ -> raise Not_found
1095 in
1096 List.fold_left aux empty t
1097
1098 let project d l =
1099 project_field (get_record d.record) l
1100
1101 type normal =
1102 [ `Success
1103 | `Fail
1104 | `Label of label * (descr * normal) list * normal ]
1105
1106 let rec merge_record n r =
1107 match (n, r) with
1108 | (`Success, _) | (_, []) -> `Success
1109 | (`Fail, r) ->
1110 let aux (l,(o,t)) n =
1111 `Label (l, [t,n], if o then n else `Fail) in
1112 List.fold_right aux r `Success
1113 | (`Label (l1,present,absent), (l2,(o,t2))::r') ->
1114 if (l1 < l2) then
1115 let pr = List.map (fun (t,x) -> (t, merge_record x r)) present in
1116 let t = List.fold_left (fun a (t,_) -> diff a t) any present in
1117 let pr =
1118 if non_empty t then (t, merge_record `Fail r) :: pr
1119 else pr in
1120 `Label (l1,pr,merge_record absent r)
1121 else if (l2 < l1) then
1122 let n' = merge_record n r' in
1123 `Label (l2, [t2, n'], if o then n' else n)
1124 else
1125 let res = ref [] in
1126 let aux a (t,x) =
1127 (let t = diff t t2 in
1128 if non_empty t then res := (t,x) :: !res);
1129 (let t = cap t t2 in
1130 if non_empty t then res := (t, merge_record x r') :: !res);
1131 diff a t
1132 in
1133 let t2 = List.fold_left aux t2 present in
1134 let () =
1135 if non_empty t2 then
1136 res := (t2, merge_record `Fail r') :: !res in
1137 let abs = if o then merge_record absent r' else absent in
1138 `Label (l1, !res, abs)
1139
1140 module Unify = Map.Make(struct type t = normal let compare = compare end)
1141
1142 let repository = ref Unify.empty
1143
1144 let rec canonize = function
1145 | `Label (l,pr,ab) as x ->
1146 (try Unify.find x !repository
1147 with Not_found ->
1148 let pr = List.map (fun (t,n) -> canonize n,t) pr in
1149 let pr = SortedMap.from_list cup pr in
1150 let pr = List.map (fun (n,t) -> (t,n)) pr in
1151 let x = `Label (l, pr, canonize ab) in
1152 try Unify.find x !repository
1153 with Not_found -> repository := Unify.add x x !repository; x
1154 )
1155 | x -> x
1156
1157 let normal d =
1158 let r = canonize (List.fold_left merge_record `Fail (get d)) in
1159 repository := Unify.empty;
1160 r
1161
1162 type normal' =
1163 [ `Success
1164 | `Label of label * (descr * descr) list * descr option ] option
1165
1166 (* NOTE: this function relies on the fact that generic order
1167 makes smallest labels appear first *)
1168
1169 let first_label d =
1170 let d = d.record in
1171 let min = ref None in
1172 let lab (l,o,t) = match !min with
1173 | Some l' when l >= l' -> ()
1174 | _ -> if o && (descr t = any) then () else min := Some l in
1175 let line (p,n) =
1176 (match p with f::_ -> lab f | _ -> ());
1177 (match n with f::_ -> lab f | _ -> ()) in
1178 List.iter line d;
1179 match !min with
1180 | None -> if d = [] then `Empty else `Any
1181 | Some l -> `Label l
1182
1183 let normal' (d : descr) l =
1184 let ab = ref empty in
1185 let rec extract f = function
1186 | (l',o,t) :: rem when l = l' ->
1187 f o (descr t); extract f rem
1188 | x :: rem -> x :: (extract f rem)
1189 | [] -> [] in
1190 let line (p,n) =
1191 let ao = ref true and ad = ref any in
1192 let p =
1193 extract (fun o d -> ao := !ao && o; ad := cap !ad d) p
1194 and n =
1195 extract (fun o d -> ao := !ao && not o; ad := diff !ad d) n
1196 in
1197 (* Note: p and n are still sorted *)
1198 let d = { empty with record = [(p,n)] } in
1199 if !ao then ab := cup d !ab;
1200 (!ad, d) in
1201 let pr = List.map line d.record in
1202 let pr = Product.normal_aux pr in
1203 let ab = if is_empty !ab then None else Some !ab in
1204 (pr, ab)
1205
1206 *)
1207
1208 let any = { empty with record = any.record }
1209 (*
1210 let is_empty d = d = []
1211 let descr l =
1212 let line l = map_sort (fun (l,(o,d)) -> (l,o,cons d)) l, [] in
1213 { empty with record = map_sort line l }
1214 *)
1215 end
1216
1217
1218
1219 let memo_normalize = ref DescrMap.empty
1220
1221
1222 let rec rec_normalize d =
1223 try DescrMap.find d !memo_normalize
1224 with Not_found ->
1225 let n = make () in
1226 memo_normalize := DescrMap.add d n !memo_normalize;
1227 let times =
1228 map_sort
1229 (fun (d1,d2) -> [(rec_normalize d1, rec_normalize d2)],[])
1230 (Product.normal d)
1231 in
1232 let xml =
1233 map_sort
1234 (fun (d1,d2) -> [(rec_normalize d1, rec_normalize d2)],[])
1235 (Product.normal ~kind:`XML d)
1236 in
1237 let record = d.record
1238 (*
1239 map_sort
1240 (fun f -> map_sort (fun (l,(o,d)) -> (l,o,rec_normalize d)) f, [])
1241 (Record.get d)
1242 *)
1243 in
1244 define n { d with times = times; xml = xml; record = record };
1245 n
1246
1247 let normalize n =
1248 descr (internalize (rec_normalize n))
1249
1250 module Arrow =
1251 struct
1252 let check_simple left s1 s2 =
1253 let rec aux accu1 accu2 = function
1254 | (t1,t2)::left ->
1255 let accu1' = diff_t accu1 t1 in
1256 if non_empty accu1' then aux accu1 accu2 left;
1257 let accu2' = cap_t accu2 t2 in
1258 if non_empty accu2' then aux accu1 accu2 left
1259 | [] -> raise NotEmpty
1260 in
1261 let accu1 = descr s1 in
1262 (is_empty accu1) ||
1263 (try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false)
1264
1265 let check_strenghten t s =
1266 let left = match t.arrow with [ (p,[]) ] -> p | _ -> assert false in
1267 let rec aux = function
1268 | [] -> raise Not_found
1269 | (p,n) :: rem ->
1270 if (List.for_all (fun (a,b) -> check_simple left a b) p) &&
1271 (List.for_all (fun (a,b) -> not (check_simple left a b)) n) then
1272 { empty with arrow = [ (SortedList.cup left p, n) ] }
1273 else aux rem
1274 in
1275 aux s.arrow
1276
1277 let check_simple_iface left s1 s2 =
1278 let rec aux accu1 accu2 = function
1279 | (t1,t2)::left ->
1280 let accu1' = diff accu1 t1 in
1281 if non_empty accu1' then aux accu1 accu2 left;
1282 let accu2' = cap accu2 t2 in
1283 if non_empty accu2' then aux accu1 accu2 left
1284 | [] -> raise NotEmpty
1285 in
1286 let accu1 = descr s1 in
1287 (is_empty accu1) ||
1288 (try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false)
1289
1290 let check_iface iface s =
1291 let rec aux = function
1292 | [] -> false
1293 | (p,n) :: rem ->
1294 ((List.for_all (fun (a,b) -> check_simple_iface iface a b) p) &&
1295 (List.for_all (fun (a,b) -> not (check_simple_iface iface a b)) n))
1296 || (aux rem)
1297 in
1298 aux s.arrow
1299
1300 type t = descr * (descr * descr) list list
1301
1302 let get t =
1303 List.fold_left
1304 (fun ((dom,arr) as accu) (left,right) ->
1305 if Sample.check_empty_arrow_line left right
1306 then accu
1307 else (
1308 let left =
1309 List.map
1310 (fun (t,s) -> (descr t, descr s)) left in
1311 let d = List.fold_left (fun d (t,_) -> cup d t) empty left in
1312 (cap dom d, left :: arr)
1313 )
1314 )
1315 (any, [])
1316 t.arrow
1317
1318 let domain (dom,_) = dom
1319
1320 let apply_simple t result left =
1321 let rec aux result accu1 accu2 = function
1322 | (t1,s1)::left ->
1323 let result =
1324 let accu1 = diff accu1 t1 in
1325 if non_empty accu1 then aux result accu1 accu2 left
1326 else result in
1327 let result =
1328 let accu2 = cap accu2 s1 in
1329 aux result accu1 accu2 left in
1330 result
1331 | [] ->
1332 if subtype accu2 result
1333 then result
1334 else cup result accu2
1335 in
1336 aux result t any left
1337
1338 let apply (_,arr) t =
1339 List.fold_left (apply_simple t) empty arr
1340
1341 let need_arg (dom, arr) =
1342 List.exists (function [_] -> false | _ -> true) arr
1343
1344 let apply_noarg (_,arr) =
1345 List.fold_left
1346 (fun accu ->
1347 function
1348 | [(t,s)] -> cup accu s
1349 | _ -> assert false
1350 )
1351 empty arr
1352
1353 let any = { empty with arrow = any.arrow }
1354 let is_empty (_,arr) = arr = []
1355 end
1356
1357
1358 module Int = struct
1359 let has_int d i = Intervals.contains i d.ints
1360
1361 let get d = d.ints
1362 let put i = { empty with ints = i }
1363 let is_int d = is_empty { d with ints = Intervals.empty }
1364 let any = { empty with ints = Intervals.any }
1365 end
1366
1367 module Atom = struct
1368 let has_atom d a = Atoms.contains a d.atoms
1369 end
1370
1371 module Char = struct
1372 let has_char d c = Chars.contains c d.chars
1373 let any = { empty with chars = Chars.any }
1374 end
1375
1376 (*
1377 let rec print_normal_record ppf = function
1378 | Success -> Format.fprintf ppf "Yes"
1379 | Fail -> Format.fprintf ppf "No"
1380 | FirstLabel (l,present,absent) ->
1381 Format.fprintf ppf "%s?@[<v>@\n" (label_name l);
1382 List.iter
1383 (fun (t,n) ->
1384 Format.fprintf ppf "(%a)=>@[%a@]@\n"
1385 Print.print_descr t
1386 print_normal_record n
1387 ) present;
1388 if absent <> Fail then
1389 Format.fprintf ppf "(absent)=>@[%a@]@\n" print_normal_record absent;
1390 Format.fprintf ppf "@]"
1391 *)
1392
1393
1394 (*
1395 let pr s = Types.Print.print Format.std_formatter (Syntax.make_type (Syntax.parse s));;
1396
1397 let pr' s = Types.Print.print Format.std_formatter
1398 (Types.normalize (Syntax.make_type (Syntax.parse s)));;
1399
1400 BUG:
1401 pr "'a | 'b where 'a = ('a , 'a) and 'b= ('b , 'b)";;
1402 *)
1403
1404
1405 (*
1406 let nr s =
1407 let t = Types.descr (Syntax.make_type (Syntax.parse s)) in
1408 let n = Types.normal_record' t.Types.record in
1409 Types.print_normal_record Format.std_formatter n;;
1410 *)

CVS Admin">CVS Admin
ViewVC Help
Powered by ViewVC 1.1.5