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

Contents of /types/types.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1488 - (show annotations)
Tue Jul 10 18:54:55 2007 UTC (5 years, 10 months ago) by abate
File size: 54152 byte(s)
[r2005-02-25 13:23:48 by afrisch] xsi:nil

Original author: afrisch
Date: 2005-02-25 13:23:49+00:00
1 open Ident
2 open Encodings
3
4 (* TODO:
5 - I store hash in types to avoid computing it several times.
6 Does not seem to help a lot.
7 *)
8
9 (*
10 To be sure not to use generic comparison ...
11 *)
12 let (=) : int -> int -> bool = (==)
13 let (<) : int -> int -> bool = (<)
14 let (<=) : int -> int -> bool = (<=)
15 let (<>) : int -> int -> bool = (<>)
16 let compare = 1
17
18
19 module CompUnit = struct
20 include Pool.Make(Utf8)
21 module Tbl = Inttbl
22
23 let pervasives = mk (U.mk "Pervasives")
24 let current = ref dummy_min
25
26 let close_serialize_ref = ref (fun () -> assert false)
27
28 let depend = Inttbl.create ()
29
30 let serialize t cu =
31 if (cu != pervasives) && (cu != !current) then Inttbl.add depend cu ();
32 serialize t cu
33
34 let close_serialize () =
35 !close_serialize_ref ();
36 let deps = Inttbl.fold depend (fun cu () l -> cu :: l) [] in
37 Inttbl.clear depend;
38 deps
39
40
41 let stack = ref []
42
43 let enter i =
44 stack := !current :: !stack; current := i
45
46 let leave () =
47 match !stack with
48 | hd::tl -> current := hd; stack := tl
49 | _ -> assert false
50
51
52 let () = enter pervasives
53 end
54
55
56 type const =
57 | Integer of Intervals.V.t
58 | Atom of Atoms.V.t
59 | Char of Chars.V.t
60 | Pair of const * const
61 | Xml of const * const
62 | Record of const label_map
63 | String of U.uindex * U.uindex * U.t * const
64
65 module Const = struct
66 type t = const
67
68 let rec check = function
69 | Integer i -> Intervals.V.check i
70 | Atom i -> Atoms.V.check i
71 | Char i -> Chars.V.check i
72 | Pair (x,y) | Xml (x,y) -> check x; check y
73 | Record l -> LabelMap.iter check l
74 | String (i,j,s,q) -> U.check s; check q
75
76 let dump ppf _ =
77 Format.fprintf ppf "<Types.Const.t>"
78
79 let rec serialize s = function
80 | Integer x ->
81 Serialize.Put.bits 3 s 0;
82 Intervals.V.serialize s x
83 | Atom x ->
84 Serialize.Put.bits 3 s 1;
85 Atoms.V.serialize s x
86 | Char x ->
87 Serialize.Put.bits 3 s 2;
88 Chars.V.serialize s x
89 | Pair (x,y) ->
90 Serialize.Put.bits 3 s 3;
91 serialize s x;
92 serialize s y
93 | Xml (x,y) ->
94 Serialize.Put.bits 3 s 4;
95 serialize s x;
96 serialize s y
97 | Record r ->
98 Serialize.Put.bits 3 s 5;
99 LabelMap.serialize serialize s r
100 | String (i,j,st,q) ->
101 Serialize.Put.bits 3 s 6;
102 U.serialize_sub s st i j;
103 serialize s q
104
105 let rec deserialize s =
106 match Serialize.Get.bits 3 s with
107 | 0 ->
108 Integer (Intervals.V.deserialize s)
109 | 1 ->
110 Atom (Atoms.V.deserialize s)
111 | 2 ->
112 Char (Chars.V.deserialize s)
113 | 3 ->
114 let x = deserialize s in
115 let y = deserialize s in
116 Pair (x,y)
117 | 4 ->
118 let x = deserialize s in
119 let y = deserialize s in
120 Xml (x,y)
121 | 5 ->
122 Record (LabelMap.deserialize deserialize s)
123 | 6 ->
124 let st = U.deserialize s in
125 let q = deserialize s in
126 String (U.start_index st, U.end_index st, st, q)
127 | _ ->
128 assert false
129
130 let rec compare c1 c2 = match (c1,c2) with
131 | Integer x, Integer y -> Intervals.V.compare x y
132 | Integer _, _ -> -1
133 | _, Integer _ -> 1
134 | Atom x, Atom y -> Atoms.V.compare x y
135 | Atom _, _ -> -1
136 | _, Atom _ -> 1
137 | Char x, Char y -> Chars.V.compare x y
138 | Char _, _ -> -1
139 | _, Char _ -> 1
140 | Pair (x1,x2), Pair (y1,y2) ->
141 let c = compare x1 y1 in
142 if c <> 0 then c else compare x2 y2
143 | Pair (_,_), _ -> -1
144 | _, Pair (_,_) -> 1
145 | Xml (x1,x2), Xml (y1,y2) ->
146 let c = compare x1 y1 in
147 if c <> 0 then c else compare x2 y2
148 | Xml (_,_), _ -> -1
149 | _, Xml (_,_) -> 1
150 | Record x, Record y ->
151 LabelMap.compare compare x y
152 | Record _, _ -> -1
153 | _, Record _ -> 1
154 | String (i1,j1,s1,r1), String (i2,j2,s2,r2) ->
155 let c = Pervasives.compare i1 i2 in if c <> 0 then c
156 else let c = Pervasives.compare j1 j2 in if c <> 0 then c
157 else let c = U.compare s1 s2 in if c <> 0 then c (* Should compare
158 only the substring *)
159 else compare r1 r2
160
161 let rec hash = function
162 | Integer x -> 1 + 17 * (Intervals.V.hash x)
163 | Atom x -> 2 + 17 * (Atoms.V.hash x)
164 | Char x -> 3 + 17 * (Chars.V.hash x)
165 | Pair (x,y) -> 4 + 17 * (hash x) + 257 * (hash y)
166 | Xml (x,y) -> 5 + 17 * (hash x) + 257 * (hash y)
167 | Record x -> 6 + 17 * (LabelMap.hash hash x)
168 | String (i,j,s,r) -> 7 + 17 * (U.hash s) + 257 * hash r
169 (* Note: improve hash for String *)
170
171 let equal c1 c2 = compare c1 c2 = 0
172 end
173
174 module Abstract =
175 struct
176 module T = Custom.String
177 type abs = T.t
178
179 module V =
180 struct
181 type t = abs * Obj.t
182 end
183
184 include SortedList.FiniteCofinite(T)
185
186 let print = function
187 | Finite l -> List.map (fun x ppf -> Format.fprintf ppf "!%s" x) l
188 | Cofinite l ->
189 [ fun ppf ->
190 Format.fprintf ppf "@[Abstract";
191 List.iter (fun x -> Format.fprintf ppf " \\@ !%s" x) l;
192 Format.fprintf ppf "@]" ]
193
194 end
195
196
197 type pair_kind = [ `Normal | `XML ]
198
199
200 module rec Descr :
201 sig
202 (*
203 Want to write:
204 type s = { ... }
205 include Custom.T with type t = s
206 but a bug (?) in OCaml 3.07 makes it impossible
207 *)
208 type t = {
209 mutable hash: int;
210 atoms : Atoms.t;
211 ints : Intervals.t;
212 chars : Chars.t;
213 times : BoolPair.t;
214 xml : BoolPair.t;
215 arrow : BoolPair.t;
216 record: BoolRec.t;
217 abstract: Abstract.t;
218 absent: bool
219 }
220 val empty: t
221 val dump: Format.formatter -> t -> unit
222 val check: t -> unit
223 val equal: t -> t -> bool
224 val hash: t -> int
225 val compare:t -> t -> int
226 val serialize: t Serialize.Put.f
227 val deserialize: t Serialize.Get.f
228 end =
229 struct
230 type t = {
231 mutable hash: int;
232 atoms : Atoms.t;
233 ints : Intervals.t;
234 chars : Chars.t;
235 times : BoolPair.t;
236 xml : BoolPair.t;
237 arrow : BoolPair.t;
238 record: BoolRec.t;
239 abstract: Abstract.t;
240 absent: bool
241 }
242
243 let dump ppf _ =
244 Format.fprintf ppf "<Types.Descr.t>"
245
246 let empty = {
247 hash = 0;
248 times = BoolPair.empty;
249 xml = BoolPair.empty;
250 arrow = BoolPair.empty;
251 record= BoolRec.empty;
252 ints = Intervals.empty;
253 atoms = Atoms.empty;
254 chars = Chars.empty;
255 abstract = Abstract.empty;
256 absent= false;
257 }
258
259 let equal a b =
260 (a == b) || (
261 (Atoms.equal a.atoms b.atoms) &&
262 (Chars.equal a.chars b.chars) &&
263 (Intervals.equal a.ints b.ints) &&
264 (BoolPair.equal a.times b.times) &&
265 (BoolPair.equal a.xml b.xml) &&
266 (BoolPair.equal a.arrow b.arrow) &&
267 (BoolRec.equal a.record b.record) &&
268 (Abstract.equal a.abstract b.abstract) &&
269 (a.absent == b.absent)
270 )
271
272 let compare a b =
273 if a == b then 0
274 else let c = Atoms.compare a.atoms b.atoms in if c <> 0 then c
275 else let c = Chars.compare a.chars b.chars in if c <> 0 then c
276 else let c = Intervals.compare a.ints b.ints in if c <> 0 then c
277 else let c = BoolPair.compare a.times b.times in if c <> 0 then c
278 else let c = BoolPair.compare a.xml b.xml in if c <> 0 then c
279 else let c = BoolPair.compare a.arrow b.arrow in if c <> 0 then c
280 else let c = BoolRec.compare a.record b.record in if c <> 0 then c
281 else let c = Abstract.compare a.abstract b.abstract in if c <> 0 then c
282 else if a.absent && not b.absent then -1
283 else if b.absent && not a.absent then 1
284 else 0
285
286 let hash a =
287 if a.hash <> 0 then a.hash else (
288 let accu = Chars.hash a.chars in
289 let accu = 17 * accu + Intervals.hash a.ints in
290 let accu = 17 * accu + Atoms.hash a.atoms in
291 let accu = 17 * accu + BoolPair.hash a.times in
292 let accu = 17 * accu + BoolPair.hash a.xml in
293 let accu = 17 * accu + BoolPair.hash a.arrow in
294 let accu = 17 * accu + BoolRec.hash a.record in
295 let accu = 17 * accu + Abstract.hash a.abstract in
296 let accu = if a.absent then accu+5 else accu in
297 a.hash <- accu;
298 accu
299 )
300
301 let check a =
302 Chars.check a.chars;
303 Intervals.check a.ints;
304 Atoms.check a.atoms;
305 BoolPair.check a.times;
306 BoolPair.check a.xml;
307 BoolPair.check a.arrow;
308 BoolRec.check a.record;
309 Abstract.check a.abstract;
310 ()
311
312
313 let serialize t a =
314 Chars.serialize t a.chars;
315 Intervals.serialize t a.ints;
316 Atoms.serialize t a.atoms;
317 BoolPair.serialize t a.times;
318 BoolPair.serialize t a.xml;
319 BoolPair.serialize t a.arrow;
320 BoolRec.serialize t a.record;
321 Abstract.serialize t a.abstract;
322 Serialize.Put.bool t a.absent
323
324 let deserialize t =
325 let chars = Chars.deserialize t in
326 let ints = Intervals.deserialize t in
327 let atoms = Atoms.deserialize t in
328 let times = BoolPair.deserialize t in
329 let xml = BoolPair.deserialize t in
330 let arrow = BoolPair.deserialize t in
331 let record = BoolRec.deserialize t in
332 let abstract = Abstract.deserialize t in
333 let absent = Serialize.Get.bool t in
334 let d = { hash=0;
335 chars = chars; ints = ints; atoms = atoms; times = times; xml = xml;
336 arrow = arrow; record = record; abstract = abstract; absent = absent } in
337 check d;
338 d
339
340
341 end
342 and Node :
343 sig
344 type t = { id : int; comp_unit: CompUnit.t; mutable descr : Descr.t }
345 val dump: Format.formatter -> t -> unit
346 val check: t -> unit
347 val equal: t -> t -> bool
348 val hash: t -> int
349 val compare:t -> t -> int
350 val serialize: t Serialize.Put.f
351 val deserialize: t Serialize.Get.f
352 val mk: int -> Descr.t -> t
353 end =
354
355 struct
356 type t = { id : int; comp_unit : CompUnit.t; mutable descr : Descr.t }
357 let check n = ()
358 let dump ppf n = failwith "Types.Node.dump"
359 let hash x = x.id + 17 * x.comp_unit
360 let compare x y =
361 let c = x.id - y.id in
362 if c = 0 then x.comp_unit - y.comp_unit else c
363 let equal x y = x == y
364
365 let serialize_memo = Inttbl.create ()
366 let counter_serialize = ref 0
367
368 let () =
369 CompUnit.close_serialize_ref :=
370 (fun () ->
371 Inttbl.clear serialize_memo;
372 counter_serialize := 0)
373
374 let serialize t n =
375 if n.comp_unit == !CompUnit.current then (
376 Serialize.Put.bool t true;
377 try
378 let i = Inttbl.find serialize_memo n.id in
379 Serialize.Put.int t i
380 with Not_found ->
381 let i = !counter_serialize in
382 incr counter_serialize;
383 Inttbl.add serialize_memo n.id i;
384 Serialize.Put.int t i;
385 Descr.serialize t n.descr
386 ) else (
387 Serialize.Put.bool t false;
388 CompUnit.serialize t n.comp_unit;
389 Serialize.Put.int t n.id
390 )
391
392
393 let deserialize_memo = Inttbl.create ()
394
395 let find_tbl id =
396 try Inttbl.find deserialize_memo id
397 with Not_found ->
398 let tbl = Inttbl.create () in
399 Inttbl.add deserialize_memo id tbl;
400 tbl
401
402 let mk id d =
403 let n = { id = id; comp_unit = !CompUnit.current; descr = d } in
404 if !CompUnit.current == CompUnit.pervasives then
405 Inttbl.add (find_tbl CompUnit.pervasives) n.id n;
406 n
407
408 let deserialize t =
409 if Serialize.Get.bool t then
410 let i = Serialize.Get.int t in
411 let tbl = find_tbl !CompUnit.current in
412 try Inttbl.find tbl i
413 with Not_found ->
414 let n = { id = i; comp_unit = !CompUnit.current;
415 descr = Descr.empty } in
416 Inttbl.add tbl i n;
417 n.descr <- Descr.deserialize t;
418 n
419 else
420 let cu = CompUnit.deserialize t in
421 let i = Serialize.Get.int t in
422 try Inttbl.find (Inttbl.find deserialize_memo cu) i
423 with Not_found -> assert false
424
425 end
426
427 (* See PR#2920 in OCaml BTS *)
428 and NodeT : Custom.T with type t = Node.t =
429 struct
430 type t = Node.t
431 let dump x = Node.dump x
432 let check x = Node.check x
433 let equal x = Node.equal x
434 let hash x = Node.hash x
435 let compare x = Node.compare x
436 let serialize x = Node.serialize x
437 let deserialize x = Node.deserialize x
438 end
439
440
441 (* It is also possible to use Boolean instead of Bool here;
442 need to analyze when each one is more efficient *)
443 and BoolPair : Bool.S with type elem = Node.t * Node.t =
444 Bool.Make(Custom.Pair(NodeT)(NodeT))
445
446 and BoolRec : Bool.S with type elem = bool * Node.t label_map =
447 Bool.Make(Custom.Pair(Custom.Bool)(LabelSet.MakeMap(NodeT)))
448
449 module DescrHash = Hashtbl.Make(Descr)
450 module DescrMap = Map.Make(Descr)
451 module DescrSet = Set.Make(Descr)
452 module DescrSList = SortedList.Make(Descr)
453
454 type descr = Descr.t
455 type node = Node.t
456 include Descr
457
458 let forward_print = ref (fun _ _ -> assert false)
459
460 let hash_cons = DescrHash.create 17000
461
462 let count = State.ref "Types.count" 0
463
464 let () =
465 Stats.register Stats.Summary
466 (fun ppf -> Format.fprintf ppf "Allocated type nodes:%i@\n" !count)
467
468 let make () =
469 incr count;
470 Node.mk !count empty
471
472 let define n d =
473 DescrHash.add hash_cons d n;
474 n.Node.descr <- d
475 let cons d =
476 try DescrHash.find hash_cons d
477 with Not_found ->
478 incr count;
479 let n = Node.mk !count d in
480 DescrHash.add hash_cons d n; n
481
482 let any = {
483 hash = 0;
484 times = BoolPair.full;
485 xml = BoolPair.full;
486 arrow = BoolPair.full;
487 record= BoolRec.full;
488 ints = Intervals.any;
489 atoms = Atoms.any;
490 chars = Chars.any;
491 abstract = Abstract.any;
492 absent= false;
493 }
494
495
496 let non_constructed =
497 { any with
498 hash = 0;
499 times = empty.times; xml = empty.xml; record = empty.record }
500
501 let non_constructed_or_absent =
502 { non_constructed with hash = 0; absent = true }
503
504 let interval i = { empty with hash = 0; ints = i }
505 let times x y = { empty with hash = 0; times = BoolPair.atom (x,y) }
506 let xml x y = { empty with hash = 0; xml = BoolPair.atom (x,y) }
507 let arrow x y = { empty with hash = 0; arrow = BoolPair.atom (x,y) }
508 let record label t =
509 { empty with hash = 0;
510 record = BoolRec.atom (true,LabelMap.singleton label t) }
511 let record' (x : bool * node Ident.label_map) =
512 { empty with hash = 0; record = BoolRec.atom x }
513 let atom a = { empty with hash = 0; atoms = a }
514 let char c = { empty with hash = 0; chars = c }
515 let abstract a = { empty with hash = 0; abstract = a }
516
517 let get_abstract t = t.abstract
518
519 let cup x y =
520 if x == y then x else {
521 hash = 0;
522 times = BoolPair.cup x.times y.times;
523 xml = BoolPair.cup x.xml y.xml;
524 arrow = BoolPair.cup x.arrow y.arrow;
525 record= BoolRec.cup x.record y.record;
526 ints = Intervals.cup x.ints y.ints;
527 atoms = Atoms.cup x.atoms y.atoms;
528 chars = Chars.cup x.chars y.chars;
529 abstract = Abstract.cup x.abstract y.abstract;
530 absent= x.absent || y.absent;
531 }
532
533 let cap x y =
534 if x == y then x else {
535 hash = 0;
536 times = BoolPair.cap x.times y.times;
537 xml = BoolPair.cap x.xml y.xml;
538 record= BoolRec.cap x.record y.record;
539 arrow = BoolPair.cap x.arrow y.arrow;
540 ints = Intervals.cap x.ints y.ints;
541 atoms = Atoms.cap x.atoms y.atoms;
542 chars = Chars.cap x.chars y.chars;
543 abstract = Abstract.cap x.abstract y.abstract;
544 absent= x.absent && y.absent;
545 }
546
547 let diff x y =
548 if x == y then empty else {
549 hash = 0;
550 times = BoolPair.diff x.times y.times;
551 xml = BoolPair.diff x.xml y.xml;
552 arrow = BoolPair.diff x.arrow y.arrow;
553 record= BoolRec.diff x.record y.record;
554 ints = Intervals.diff x.ints y.ints;
555 atoms = Atoms.diff x.atoms y.atoms;
556 chars = Chars.diff x.chars y.chars;
557 abstract = Abstract.diff x.abstract y.abstract;
558 absent= x.absent && not y.absent;
559 }
560
561
562
563
564 (* TODO: optimize disjoint check for boolean combinations *)
565 let trivially_disjoint a b =
566 (Chars.disjoint a.chars b.chars) &&
567 (Intervals.disjoint a.ints b.ints) &&
568 (Atoms.disjoint a.atoms b.atoms) &&
569 (BoolPair.trivially_disjoint a.times b.times) &&
570 (BoolPair.trivially_disjoint a.xml b.xml) &&
571 (BoolPair.trivially_disjoint a.arrow b.arrow) &&
572 (BoolRec.trivially_disjoint a.record b.record) &&
573 (Abstract.disjoint a.abstract b.abstract) &&
574 (not (a.absent && b.absent))
575
576
577
578 let descr n = n.Node.descr
579 let internalize n = n
580 let id n = n.Node.id
581
582
583 let rec constant = function
584 | Integer i -> interval (Intervals.atom i)
585 | Atom a -> atom (Atoms.atom a)
586 | Char c -> char (Chars.atom c)
587 | Pair (x,y) -> times (const_node x) (const_node y)
588 | Xml (x,y) -> times (const_node x) (const_node y)
589 | Record x -> record' (false ,LabelMap.map const_node x)
590 | String (i,j,s,c) ->
591 if U.equal_index i j then constant c
592 else
593 let (ch,i') = U.next s i in
594 constant (Pair (Char (Chars.V.mk_int ch), String (i',j,s,c)))
595 and const_node c = cons (constant c)
596
597 let neg x = diff any x
598
599 let any_node = cons any
600 let empty_node = cons empty
601
602 module LabelS = Set.Make(LabelPool)
603
604 let any_or_absent = { any with hash=0; absent = true }
605 let only_absent = { empty with hash=0; absent = true }
606
607 let get_record r =
608 let labs accu (_,r) =
609 List.fold_left
610 (fun accu (l,_) -> LabelS.add l accu) accu (LabelMap.get r) in
611 let extend descrs labs (o,r) =
612 let rec aux i labs r =
613 match labs with
614 | [] -> ()
615 | l1::labs ->
616 match r with
617 | (l2,x)::r when l1 == l2 ->
618 descrs.(i) <- cap descrs.(i) (descr x);
619 aux (i+1) labs r
620 | r ->
621 if not o then
622 descrs.(i) <- cap descrs.(i) only_absent; (* TODO:OPT *)
623 aux (i+1) labs r
624 in
625 aux 0 labs (LabelMap.get r);
626 o
627 in
628 let line (p,n) =
629 let labels =
630 List.fold_left labs (List.fold_left labs LabelS.empty p) n in
631 let labels = LabelS.elements labels in
632 let nlab = List.length labels in
633 let mk () = Array.create nlab any_or_absent in
634
635 let pos = mk () in
636 let opos = List.fold_left
637 (fun accu x ->
638 (extend pos labels x) && accu)
639 true p in
640 let p = (opos, pos) in
641
642 let n = List.map (fun x ->
643 let neg = mk () in
644 let o = extend neg labels x in
645 (o,neg)
646 ) n in
647 (labels,p,n)
648 in
649 List.map line (BoolRec.get r)
650
651
652
653
654
655 (* Subtyping algorithm *)
656
657 let diff_t d t = diff d (descr t)
658 let cap_t d t = cap d (descr t)
659 let cup_t d t = cup d (descr t)
660 let cap_product any_left any_right l =
661 List.fold_left
662 (fun (d1,d2) (t1,t2) -> (cap_t d1 t1, cap_t d2 t2))
663 (any_left,any_right)
664 l
665 let any_pair = { empty with hash = 0; times = any.times }
666
667
668 let rec exists max f =
669 (max > 0) && (f (max - 1) || exists (max - 1) f)
670
671 exception NotEmpty
672
673 type slot = { mutable status : status;
674 mutable notify : notify;
675 mutable active : bool }
676 and status = Empty | NEmpty | Maybe
677 and notify = Nothing | Do of slot * (slot -> unit) * notify
678
679 let slot_empty = { status = Empty; active = false; notify = Nothing }
680 let slot_not_empty = { status = NEmpty; active = false; notify = Nothing }
681
682 let rec notify = function
683 | Nothing -> ()
684 | Do (n,f,rem) ->
685 if n.status == Maybe then (try f n with NotEmpty -> ());
686 notify rem
687
688 let rec iter_s s f = function
689 | [] -> ()
690 | arg::rem -> f arg s; iter_s s f rem
691
692
693 let set s =
694 s.status <- NEmpty;
695 notify s.notify;
696 s.notify <- Nothing;
697 raise NotEmpty
698
699 let rec big_conj f l n =
700 match l with
701 | [] -> set n
702 | [arg] -> f arg n
703 | arg::rem ->
704 let s =
705 { status = Maybe; active = false;
706 notify = Do (n,(big_conj f rem), Nothing) } in
707 try
708 f arg s;
709 if s.active then n.active <- true
710 with NotEmpty -> if n.status == NEmpty then raise NotEmpty
711
712 let guard a f n =
713 match a with
714 | { status = Empty } -> ()
715 | { status = Maybe } as s ->
716 n.active <- true;
717 s.notify <- Do (n,f,s.notify)
718 | { status = NEmpty } -> f n
719
720
721 (* Fast approximation *)
722
723 module ClearlyEmpty =
724 struct
725
726 let memo = DescrHash.create 33000
727 let marks = ref []
728
729 let rec slot d =
730 if not ((Intervals.is_empty d.ints) &&
731 (Atoms.is_empty d.atoms) &&
732 (Chars.is_empty d.chars) &&
733 (Abstract.is_empty d.abstract) &&
734 (not d.absent)) then slot_not_empty
735 else try DescrHash.find memo d
736 with Not_found ->
737 let s = { status = Maybe; active = false; notify = Nothing } in
738 DescrHash.add memo d s;
739 (try
740 iter_s s check_times (BoolPair.get d.times);
741 iter_s s check_xml (BoolPair.get d.xml);
742 iter_s s check_arrow (BoolPair.get d.arrow);
743 iter_s s check_record (get_record d.record);
744 if s.active then marks := s :: !marks else s.status <- Empty;
745 with
746 NotEmpty -> ());
747 s
748
749 and check_times (left,right) s =
750 let (accu1,accu2) = cap_product any any left in
751 let single_right (t1,t2) s =
752 let t1 = descr t1 and t2 = descr t2 in
753 if trivially_disjoint accu1 t1 || trivially_disjoint accu2 t2 then set s
754 else
755 let accu1 = diff accu1 t1 in guard (slot accu1) set s;
756 let accu2 = diff accu2 t2 in guard (slot accu2) set s in
757 guard (slot accu1) (guard (slot accu2) (big_conj single_right right)) s
758
759 and check_xml (left,right) s =
760 let (accu1,accu2) = cap_product any any_pair left in
761 let single_right (t1,t2) s =
762 let t1 = descr t1 and t2 = descr t2 in
763 if trivially_disjoint accu1 t1 || trivially_disjoint accu2 t2 then set s
764 else
765 let accu1 = diff accu1 t1 in guard (slot accu1) set s;
766 let accu2 = diff accu2 t2 in guard (slot accu2) set s in
767 guard (slot accu1) (guard (slot accu2) (big_conj single_right right)) s
768
769 and check_arrow (left,right) s =
770 let single_right (s1,s2) s =
771 let accu1 = descr s1 and accu2 = neg (descr s2) in
772 let single_left (t1,t2) s =
773 let accu1 = diff_t accu1 t1 in guard (slot accu1) set s;
774 let accu2 = cap_t accu2 t2 in guard (slot accu2) set s
775 in
776 guard (slot accu1) (big_conj single_left left) s
777 in
778 big_conj single_right right s
779
780 and check_record (labels,(oleft,left),rights) s =
781 let rec single_right (oright,right) s =
782 let next =
783 (oleft && (not oright)) ||
784 exists (Array.length left)
785 (fun i -> trivially_disjoint left.(i) right.(i))
786 in
787 if next then set s
788 else
789 for i = 0 to Array.length left - 1 do
790 let di = diff left.(i) right.(i) in guard (slot di) set s
791 done
792 in
793 let rec start i s =
794 if (i < 0) then big_conj single_right rights s
795 else guard (slot left.(i)) (start (i - 1)) s
796 in
797 start (Array.length left - 1) s
798
799
800 let is_empty d =
801 let s = slot d in
802 List.iter
803 (fun s' ->
804 if s'.status == Maybe then s'.status <- Empty; s'.notify <- Nothing)
805 !marks;
806 marks := [];
807 s.status == Empty
808 end
809
810 let clearly_disjoint t1 t2 =
811 (*
812 if trivially_disjoint t1 t2 then true
813 else
814 if ClearlyEmpty.is_empty (cap t1 t2) then
815 (Printf.eprintf "!\n"; true) else false
816 *)
817 trivially_disjoint t1 t2 || ClearlyEmpty.is_empty (cap t1 t2)
818
819 (* TODO: need to invesigate when ClearEmpty is a good thing... *)
820
821 let memo = DescrHash.create 33000
822 let marks = ref []
823
824 let count_subtype = Stats.Counter.create "Subtyping internal loop"
825
826 let rec slot d =
827 Stats.Counter.incr count_subtype;
828 if not ((Intervals.is_empty d.ints) &&
829 (Atoms.is_empty d.atoms) &&
830 (Chars.is_empty d.chars) &&
831 (Abstract.is_empty d.abstract) &&
832 (not d.absent)) then slot_not_empty
833 else try DescrHash.find memo d
834 with Not_found ->
835 let s = { status = Maybe; active = false; notify = Nothing } in
836 DescrHash.add memo d s;
837 (try
838 iter_s s check_times (BoolPair.get d.times);
839 iter_s s check_xml (BoolPair.get d.xml);
840 iter_s s check_arrow (BoolPair.get d.arrow);
841 iter_s s check_record (get_record d.record);
842 if s.active then marks := s :: !marks else s.status <- Empty;
843 with
844 NotEmpty -> ());
845 s
846
847 and check_times (left,right) s =
848 let rec aux accu1 accu2 right s = match right with
849 | (t1,t2)::right ->
850 let t1 = descr t1 and t2 = descr t2 in
851 if trivially_disjoint accu1 t1 ||
852 trivially_disjoint accu2 t2 then (
853 aux accu1 accu2 right s )
854 else (
855 let accu1' = diff accu1 t1 in
856 guard (slot accu1') (aux accu1' accu2 right) s;
857
858 let accu2' = diff accu2 t2 in
859 guard (slot accu2') (aux accu1 accu2' right) s
860 )
861 | [] -> set s
862 in
863 let (accu1,accu2) = cap_product any any left in
864 guard (slot accu1) (guard (slot accu2) (aux accu1 accu2 right)) s
865
866 and check_xml (left,right) s =
867 let rec aux accu1 accu2 right s = match right with
868 | (t1,t2)::right ->
869 let t1 = descr t1 and t2 = descr t2 in
870 if clearly_disjoint accu1 t1 ||
871 trivially_disjoint accu2 t2 then (
872 aux accu1 accu2 right s )
873 else (
874 let accu1' = diff accu1 t1 in
875 guard (slot accu1') (aux accu1' accu2 right) s;
876
877 let accu2' = diff accu2 t2 in
878 guard (slot accu2') (aux accu1 accu2' right) s
879 )
880 | [] -> set s
881 in
882 let (accu1,accu2) = cap_product any any_pair left in
883 guard (slot accu1) (guard (slot accu2) (aux accu1 accu2 right)) s
884
885 and check_arrow (left,right) s =
886 let single_right (s1,s2) s =
887 let rec aux accu1 accu2 left s = match left with
888 | (t1,t2)::left ->
889 let accu1' = diff_t accu1 t1 in
890 guard (slot accu1') (aux accu1' accu2 left) s;
891
892 let accu2' = cap_t accu2 t2 in
893 guard (slot accu2') (aux accu1 accu2' left) s
894 | [] -> set s
895 in
896 let accu1 = descr s1 in
897 guard (slot accu1) (aux accu1 (neg (descr s2)) left) s
898 in
899 big_conj single_right right s
900
901 and check_record (labels,(oleft,left),rights) s =
902 let rec aux left rights s = match rights with
903 | [] -> set s
904 | (oright,right)::rights ->
905 let next =
906 (oleft && (not oright)) ||
907 exists (Array.length left)
908 (fun i -> trivially_disjoint left.(i) right.(i))
909 in
910 if next then aux left rights s
911 else
912 for i = 0 to Array.length left - 1 do
913 let left' = Array.copy left in
914 let di = diff left.(i) right.(i) in
915 left'.(i) <- di;
916 guard (slot di) (aux left' rights) s;
917 done
918 in
919 let rec start i s =
920 if (i < 0) then aux left rights s
921 else
922 guard (slot left.(i)) (start (i - 1)) s
923 in
924 start (Array.length left - 1) s
925
926
927
928 let timer_subtype = Stats.Timer.create "Types.is_empty"
929
930
931 let is_empty d =
932 Stats.Timer.start timer_subtype;
933 let s = slot d in
934 List.iter
935 (fun s' ->
936 if s'.status == Maybe then s'.status <- Empty; s'.notify <- Nothing)
937 !marks;
938 marks := [];
939 Stats.Timer.stop timer_subtype
940 (s.status == Empty)
941
942 (*
943 let is_empty d =
944 (* let b1 = ClearlyEmpty.is_empty d in
945 let b2 = is_empty d in
946 assert (b2 || not b1);
947 Printf.eprintf "b1 = %b; b2 = %b\n" b1 b2;
948 b2 *)
949 if ClearlyEmpty.is_empty d then (Printf.eprintf "!\n"; true) else is_empty d
950 *)
951
952 let non_empty d =
953 not (is_empty d)
954
955 let subtype d1 d2 =
956 is_empty (diff d1 d2)
957
958 let disjoint d1 d2 =
959 is_empty (cap d1 d2)
960
961 let equiv d1 d2 = (subtype d1 d2) && (subtype d2 d1)
962
963 module Product =
964 struct
965 type t = (descr * descr) list
966
967 let other ?(kind=`Normal) d =
968 match kind with
969 | `Normal -> { d with hash = 0; times = empty.times }
970 | `XML -> { d with hash = 0; xml = empty.xml }
971
972 let is_product ?kind d = is_empty (other ?kind d)
973
974 let need_second = function _::_::_ -> true | _ -> false
975
976 let normal_aux = function
977 | ([] | [ _ ]) as d -> d
978 | d ->
979
980 let res = ref [] in
981
982 let add (t1,t2) =
983 let rec loop t1 t2 = function
984 | [] -> res := (ref (t1,t2)) :: !res
985 | ({contents = (d1,d2)} as r)::l ->
986 (*OPT*)
987 (* if equal_descr d1 t1 then r := (d1,cup d2 t2) else*)
988
989 let i = cap t1 d1 in
990 if is_empty i then loop t1 t2 l
991 else (
992 r := (i, cup t2 d2);
993 let k = diff d1 t1 in
994 if non_empty k then res := (ref (k,d2)) :: !res;
995
996 let j = diff t1 d1 in
997 if non_empty j then loop j t2 l
998 )
999 in
1000 loop t1 t2 !res
1001 in
1002 List.iter add d;
1003 List.map (!) !res
1004
1005
1006 (* Partitioning:
1007
1008 (t,s) - ((t1,s1) | (t2,s2) | ... | (tn,sn))
1009 =
1010 (t & t1, s - s1) | ... | (t & tn, s - sn) | (t - (t1|...|tn), s)
1011
1012 *)
1013 let get_aux any_right d =
1014 let accu = ref [] in
1015 let line (left,right) =
1016 let (d1,d2) = cap_product any any_right left in
1017 if (non_empty d1) && (non_empty d2) then
1018 let right = List.map (fun (t1,t2) -> descr t1, descr t2) right in
1019 let right = normal_aux right in
1020 let resid1 = ref d1 in
1021 let () =
1022 List.iter
1023 (fun (t1,t2) ->
1024 let t1 = cap d1 t1 in
1025 if (non_empty t1) then
1026 let () = resid1 := diff !resid1 t1 in
1027 let t2 = diff d2 t2 in
1028 if (non_empty t2) then accu := (t1,t2) :: !accu
1029 ) right in
1030 if non_empty !resid1 then accu := (!resid1, d2) :: !accu
1031 in
1032 List.iter line (BoolPair.get d);
1033 !accu
1034 (* Maybe, can improve this function with:
1035 (t,s) \ (t1,s1) = (t&t',s\s') | (t\t',s),
1036 don't call normal_aux *)
1037
1038
1039 let get ?(kind=`Normal) d =
1040 match kind with
1041 | `Normal -> get_aux any d.times
1042 | `XML -> get_aux any_pair d.xml
1043
1044 let pi1 = List.fold_left (fun acc (t1,_) -> cup acc t1) empty
1045 let pi2 = List.fold_left (fun acc (_,t2) -> cup acc t2) empty
1046 let pi2_restricted restr =
1047 List.fold_left (fun acc (t1,t2) ->
1048 if is_empty (cap t1 restr) then acc
1049 else cup acc t2) empty
1050
1051 let restrict_1 rects pi1 =
1052 let aux acc (t1,t2) =
1053 let t1 = cap t1 pi1 in if is_empty t1 then acc else (t1,t2)::acc in
1054 List.fold_left aux [] rects
1055
1056 type normal = t
1057
1058 module Memo = Map.Make(BoolPair)
1059
1060 (* TODO: try with an hashtable *)
1061 (* Also, avoid lookup for simple products (t1,t2) *)
1062 let memo = ref Memo.empty
1063 let normal_times d =
1064 try Memo.find d !memo
1065 with
1066 Not_found ->
1067 let gd = get_aux any d in
1068 let n = normal_aux gd in
1069 (* Could optimize this call to normal_aux because one already
1070 know that each line is normalized ... *)
1071 memo := Memo.add d n !memo;
1072 n
1073
1074 let memo_xml = ref Memo.empty
1075 let normal_xml d =
1076 try Memo.find d !memo_xml
1077 with
1078 Not_found ->
1079 let gd = get_aux any_pair d in
1080 let n = normal_aux gd in
1081 memo_xml := Memo.add d n !memo_xml;
1082 n
1083
1084 let normal ?(kind=`Normal) d =
1085 match kind with
1086 | `Normal -> normal_times d.times
1087 | `XML -> normal_xml d.xml
1088
1089
1090 let merge_same_2 r =
1091 let r =
1092 List.fold_left
1093 (fun accu (t1,t2) ->
1094 let t = try DescrMap.find t2 accu with Not_found -> empty in
1095 DescrMap.add t2 (cup t t1) accu
1096 ) DescrMap.empty r in
1097 DescrMap.fold (fun t2 t1 accu -> (t1,t2)::accu) r []
1098
1099
1100 let constraint_on_2 n t1 =
1101 List.fold_left
1102 (fun accu (d1,d2) ->
1103 if is_empty (cap d1 t1) then accu else cap accu d2)
1104 any
1105 n
1106
1107
1108 let clean_normal l =
1109 let rec aux accu (t1,t2) =
1110 match accu with
1111 | [] -> [ (t1,t2) ]
1112 | (s1,s2) :: rem when equiv t2 s2 -> (cup s1 t1, s2) :: rem
1113 | (s1,s2) :: rem -> (s1,s2) :: (aux rem (t1,t2)) in
1114 List.fold_left aux [] l
1115
1116 let any = { empty with hash = 0; times = any.times }
1117 and any_xml = { empty with hash = 0; xml = any.xml }
1118 let is_empty d = d == []
1119 let any_of = function `XML -> any_xml | `Normal -> any
1120 end
1121
1122 module Record =
1123 struct
1124 let has_record d = not (is_empty { empty with hash= 0; record = d.record })
1125 let or_absent d = { d with hash = 0; absent = true }
1126 let absent = or_absent empty
1127 let any_or_absent = or_absent any
1128 let any_or_absent_node = cons any_or_absent
1129 let has_absent d = d.absent
1130
1131 let absent_node = cons absent
1132
1133 module T = struct
1134 type t = descr
1135 let any = any_or_absent
1136 let cap = cap
1137 let cup = cup
1138 let diff = diff
1139 let is_empty = is_empty
1140 let empty = empty
1141 end
1142 module R = struct
1143 type t = descr
1144 let any = { empty with hash = 0; record = any.record }
1145 let cap = cap
1146 let cup = cup
1147 let diff = diff
1148 let is_empty = is_empty
1149 let empty = empty
1150 end
1151 module TR = Normal.Make(T)(R)
1152
1153 let any_record = { empty with hash = 0; record = BoolRec.full }
1154
1155 let atom o l =
1156 if o && LabelMap.is_empty l then any_record else
1157 { empty with hash = 0; record = BoolRec.atom (o,l) }
1158
1159 type zor = Pair of descr * descr | Any
1160
1161 let aux_split d l=
1162 let f (o,r) =
1163 try
1164 let (lt,rem) = LabelMap.assoc_remove l r in
1165 Pair (descr lt, atom o rem)
1166 with Not_found ->
1167 if o then
1168 if LabelMap.is_empty r then Any else
1169 Pair (any_or_absent, { empty with hash=0; record = BoolRec.atom (o,r) })
1170 else
1171 Pair (absent,
1172 { empty with hash = 0; record = BoolRec.atom (o,r) })
1173 in
1174 List.fold_left
1175 (fun b (p,n) ->
1176 let rec aux_p accu = function
1177 | x::p ->
1178 (match f x with
1179 | Pair (t1,t2) -> aux_p ((t1,t2)::accu) p
1180 | Any -> aux_p accu p)
1181 | [] -> aux_n accu [] n
1182 and aux_n p accu = function
1183 | x::n ->
1184 (match f x with
1185 | Pair (t1,t2) -> aux_n p ((t1,t2)::accu) n
1186 | Any -> b)
1187 | [] -> (p,accu) :: b in
1188 aux_p [] p)
1189 []
1190 (BoolRec.get d.record)
1191
1192 let split (d : descr) l =
1193 TR.boolean (aux_split d l)
1194
1195 let split_normal d l =
1196 TR.boolean_normal (aux_split d l)
1197
1198
1199 let pi l d = TR.pi1 (split d l)
1200
1201 let project d l =
1202 let t = pi l d in
1203 if t.absent then raise Not_found;
1204 t
1205
1206 let project_opt d l =
1207 let t = pi l d in
1208 { t with hash = 0; absent = false }
1209
1210 let condition d l t =
1211 TR.pi2_restricted t (split d l)
1212
1213 (* TODO: eliminate this cap ... (record l absent_node) when
1214 not necessary. eg. {| ..... |} \ l *)
1215
1216 let remove_field d l =
1217 cap (TR.pi2 (split d l)) (record l absent_node)
1218
1219 let all_labels d =
1220 let res = ref LabelSet.empty in
1221 let aux (_,r) =
1222 let ls = LabelMap.domain r in
1223 res := LabelSet.cup ls !res in
1224 BoolRec.iter aux d.record;
1225 !res
1226
1227 let first_label d =
1228 let min = ref LabelPool.dummy_max in
1229 let aux (_,r) =
1230 match LabelMap.get r with
1231 (l,_)::_ -> if (l:int) < !min then min := l | _ -> () in
1232 BoolRec.iter aux d.record;
1233 !min
1234
1235 let empty_cases d =
1236 let x = BoolRec.compute
1237 ~empty:0 ~full:3 ~cup:(lor) ~cap:(land)
1238 ~diff:(fun a b -> a land lnot b)
1239 ~atom:(function (o,r) ->
1240 assert (LabelMap.get r == []);
1241 if o then 3 else 1
1242 )
1243 d.record in
1244 (x land 2 <> 0, x land 1 <> 0)
1245
1246 let has_empty_record d =
1247 BoolRec.compute
1248 ~empty:false ~full:true ~cup:(||) ~cap:(&&)
1249 ~diff:(fun a b -> a && not b)
1250 ~atom:(function (o,r) ->
1251 List.for_all
1252 (fun (l,t) -> (descr t).absent)
1253 (LabelMap.get r)
1254 )
1255 d.record
1256
1257
1258 (*TODO: optimize merge
1259 - pre-compute the sequence of labels
1260 - remove empty or full { l = t }
1261 *)
1262
1263 let merge d1 d2 =
1264 let res = ref empty in
1265 let rec aux accu d1 d2 =
1266 let l = min (first_label d1) (first_label d2) in
1267 if l = LabelPool.dummy_max then
1268 let (some1,none1) = empty_cases d1
1269 and (some2,none2) = empty_cases d2 in
1270 let none = none1 && none2 and some = some1 || some2 in
1271 let accu = LabelMap.from_list (fun _ _ -> assert false) accu in
1272 (* approx for the case (some && not none) ... *)
1273 res := cup !res (record' (some, accu))
1274 else
1275 let l1 = split d1 l and l2 = split d2 l in
1276 let loop (t1,d1) (t2,d2) =
1277 let t =
1278 if t2.absent
1279 then cup t1 { t2 with hash = 0; absent = false }
1280 else t2
1281 in
1282 aux ((l,cons t)::accu) d1 d2
1283 in
1284 List.iter (fun x -> List.iter (loop x) l2) l1
1285
1286 in
1287 aux [] d1 d2;
1288 !res
1289
1290 let any = { empty with hash = 0; record = any.record }
1291
1292 let get d =
1293 let rec aux r accu d =
1294 let l = first_label d in
1295 if l == LabelPool.dummy_max then
1296 let (o1,o2) = empty_cases d in
1297 if o1 || o2 then (LabelMap.from_list_disj r,o1,o2)::accu else accu
1298 else
1299 List.fold_left
1300 (fun accu (t1,t2) ->
1301 let x = (t1.absent, { t1 with hash = 0; absent = false }) in
1302 aux ((l,x)::r) accu t2)
1303 accu
1304 (split d l)
1305 in
1306 aux [] [] d
1307 end
1308
1309
1310 module Print =
1311 struct
1312 let rec print_const ppf = function
1313 | Integer i -> Intervals.V.print ppf i
1314 | Atom a -> Atoms.V.print_quote ppf a
1315 | Char c -> Chars.V.print ppf c
1316 | Pair (x,y) -> Format.fprintf ppf "(%a,%a)" print_const x print_const y
1317 | Xml (x,y) -> Format.fprintf ppf "XML(%a,%a)" print_const x print_const y
1318 | Record r ->
1319 Format.fprintf ppf "Record{";
1320 List.iter
1321 (fun (l,c) ->
1322 Format.fprintf ppf "%a : %a; "
1323 Label.print (LabelPool.value l)
1324 print_const c)
1325 (LabelMap.get r);
1326 Format.fprintf ppf "}"
1327 | String (i,j,s,c) ->
1328 Format.fprintf ppf "\"%a\" %a"
1329 U.print (U.mk (U.get_substr s i j))
1330 print_const c
1331
1332 let nil_atom = Atoms.V.mk_ascii "nil"
1333 let nil_type = atom (Atoms.atom nil_atom)
1334 let (seqs_node,seqs_descr) =
1335 let n = make () in
1336 let d = cup nil_type (times any_node n) in
1337 define n d;
1338 (n, d)
1339
1340 let is_regexp t = subtype t seqs_descr
1341
1342 type nd = { id : int;
1343 mutable def : d list;
1344 mutable state : [ `Expand | `None | `Marked | `Named of U.t ] }
1345 and d =
1346 | Name of U.t
1347 | Regexp of nd Pretty.regexp
1348 | Atomic of (Format.formatter -> unit)
1349 | Pair of nd * nd
1350 | Char of Chars.V.t
1351 | Xml of [ `Tag of (Format.formatter -> unit) | `Type of nd ] * nd * nd
1352 | Record of (bool * nd) label_map * bool * bool
1353 | Arrows of (nd * nd) list * (nd * nd) list
1354 | Neg of nd
1355 | Abs of nd
1356 let compare x y = x.id - y.id
1357
1358 module S = struct
1359 type t = nd
1360 let compare x y = x.id - y.id
1361 let hash x = x.id
1362 let equal x y = x.id = y.id
1363 end
1364 module Decompile = Pretty.Decompile(DescrHash)(S)
1365
1366 module DescrPairMap = Map.Make(Custom.Pair(Descr)(Descr))
1367
1368 let named = State.ref "Types.Print.named" DescrMap.empty
1369 let named_xml = State.ref "Types.Print.named_xml" DescrPairMap.empty
1370 let register_global (name : U.t) d =
1371 if equal { d with hash = 0; xml = BoolPair.empty } empty then
1372 (let l = (*Product.merge_same_2*) (Product.get ~kind:`XML d) in
1373 match l with
1374 | [(t1,t2)] ->
1375 if DescrPairMap.mem (t1,t2) !named_xml then ()
1376 else
1377 named_xml := DescrPairMap.add (t1,t2) name !named_xml
1378 | _ -> ());
1379 if DescrMap.mem d !named then ()
1380 else named := DescrMap.add d name !named
1381
1382 let unregister_global d =
1383 if equal { d with hash = 0; xml = BoolPair.empty } empty then
1384 (let l = Product.get ~kind:`XML d in
1385 match l with
1386 | [(t1,t2)] ->
1387 named_xml := DescrPairMap.remove (t1,t2) !named_xml
1388 | _ -> ());
1389 named := DescrMap.remove d !named
1390
1391 let memo = DescrHash.create 63
1392 let counter = ref 0
1393 let alloc def = { id = (incr counter; !counter); def = def; state = `None }
1394
1395 let count_name = ref 0
1396 let name () =
1397 incr count_name;
1398 U.mk ("X" ^ (string_of_int !count_name))
1399
1400 let to_print = ref []
1401
1402 let trivial_rec b =
1403 b == BoolRec.empty ||
1404 (is_empty { empty with hash = 0; record = BoolRec.diff BoolRec.full b})
1405
1406 let trivial_pair b = b == BoolPair.empty || b == BoolPair.full
1407
1408 let worth_abbrev d =
1409 not (trivial_pair d.times && trivial_pair d.xml &&
1410 trivial_pair d.arrow && trivial_rec d.record)
1411
1412 let worth_complement d =
1413 let aux f x y = if f x y = 0 then 1 else 0 in
1414 let n =
1415 aux Atoms.compare d.atoms any.atoms +
1416 aux Chars.compare d.chars any.chars +
1417 aux Intervals.compare d.ints any.ints +
1418 aux BoolPair.compare d.times any.times +
1419 aux BoolPair.compare d.xml any.xml +
1420 aux BoolPair.compare d.arrow any.arrow +
1421 aux BoolRec.compare d.record any.record +
1422 aux Abstract.compare d.abstract any.abstract
1423 in
1424 n >= 5
1425
1426 let rec prepare d =
1427 try DescrHash.find memo d
1428 with Not_found ->
1429 try
1430 let n = DescrMap.find d !named in
1431 let s = alloc [] in
1432 s.state <- `Named n;
1433 DescrHash.add memo d s;
1434 s
1435 with Not_found ->
1436 if d.absent then alloc [Abs (prepare ({d with hash=0; absent=false}))]
1437 else if worth_complement d
1438 then alloc [Neg (prepare (neg d))]
1439 else let slot = alloc [] in
1440 if not (worth_abbrev d) then slot.state <- `Expand;
1441 DescrHash.add memo d slot;
1442 let (seq,not_seq) =
1443 if (subtype { empty with hash = 0; times = d.times } seqs_descr) then
1444 (cap d seqs_descr, diff d seqs_descr)
1445 else
1446 (empty, d) in
1447
1448 let add u = slot.def <- u :: slot.def in
1449 if (non_empty seq) then
1450 add (Regexp (decompile seq));
1451 List.iter
1452 (fun (t1,t2) -> add (Pair (prepare t1, prepare t2)))
1453 (Product.get not_seq);
1454 List.iter
1455 (fun (t1,t2) ->
1456 try
1457 let n = DescrPairMap.find (t1,t2) !named_xml in
1458 add (Name n)
1459 with Not_found ->
1460 let tag =
1461 match Atoms.print_tag t1.atoms with
1462 | Some a when is_empty { t1 with hash=0; atoms = Atoms.empty } -> `Tag a
1463 | _ -> `Type (prepare t1) in
1464 assert (equal { t2 with hash=0; times = empty.times } empty);
1465 List.iter
1466 (fun (ta,tb) ->
1467 add (Xml (tag, prepare ta, prepare tb)))
1468 (Product.get t2);
1469 )
1470 ((*Product.merge_same_2*) (Product.get ~kind:`XML not_seq));
1471 List.iter
1472 (fun (r,some,none) ->
1473 let r = LabelMap.map (fun (o,t) -> (o, prepare t)) r in
1474 add (Record (r,some,none)))
1475 (Record.get not_seq);
1476 (match Chars.is_char not_seq.chars with
1477 | Some c -> add (Char c)
1478 | None ->
1479 List.iter (fun x -> add (Atomic x)) (Chars.print not_seq.chars));
1480 List.iter (fun x -> add (Atomic x)) (Intervals.print not_seq.ints);
1481 List.iter (fun x -> add (Atomic x)) (Atoms.print not_seq.atoms);
1482 List.iter (fun x -> add (Atomic x)) (Abstract.print not_seq.abstract);
1483 List.iter
1484 (fun (p,n) ->
1485 let aux (t,s) = prepare (descr t), prepare (descr s) in
1486 let p = List.map aux p and n = List.map aux n in
1487 add (Arrows (p,n)))
1488 (BoolPair.get not_seq.arrow);
1489 if not_seq.absent then add (Atomic (fun ppf -> Format.fprintf ppf "#ABSENT"));
1490 slot.def <- List.rev slot.def;
1491 slot
1492
1493 and decompile d =
1494 Decompile.decompile
1495 (fun t ->
1496 let tr = Product.get t in
1497 let tr = Product.clean_normal tr in
1498
1499 let tr = List.map (fun (l,t) -> prepare l, t) tr in
1500 tr, Atoms.contains nil_atom t.atoms)
1501 d
1502
1503 let gen = ref 0
1504
1505 let rec assign_name s =
1506 incr gen;
1507 match s.state with
1508 | `None ->
1509 let g = !gen in
1510 s.state <- `Marked;
1511 List.iter assign_name_rec s.def;
1512 if (s.state == `Marked) && (!gen == g) then s.state <- `None
1513 | `Marked -> s.state <- `Named (name ()); to_print := s :: !to_print
1514 | _ -> ()
1515 and assign_name_rec = function
1516 | Neg t -> assign_name t
1517 | Abs t -> assign_name t
1518 | Name _ | Char _ | Atomic _ -> ()
1519 | Regexp r -> assign_name_regexp r
1520 | Pair (t1,t2) -> assign_name t1; assign_name t2
1521 | Xml (tag,t2,t3) ->
1522 (match tag with `Type t -> assign_name t | _ -> ());
1523 assign_name t2;
1524 assign_name t3
1525 | Record (r,_,_) ->
1526 List.iter (fun (_,(_,t)) -> assign_name t) (LabelMap.get r)
1527 | Arrows (p,n) ->
1528 List.iter (fun (t1,t2) -> assign_name t1; assign_name t2) p;
1529 List.iter (fun (t1,t2) -> assign_name t1; assign_name t2) n
1530 and assign_name_regexp = function
1531 | Pretty.Epsilon | Pretty.Empty -> ()
1532 | Pretty.Alt (r1,r2)
1533 | Pretty.Seq (r1,r2) -> assign_name_regexp r1; assign_name_regexp r2
1534 | Pretty.Star r | Pretty.Plus r -> assign_name_regexp r
1535 | Pretty.Trans t -> assign_name t
1536
1537 let rec do_print_slot pri ppf s =
1538 match s.state with
1539 | `Named n -> Format.fprintf ppf "%a" U.print n
1540 | _ -> do_print_slot_real pri ppf s.def
1541 and do_print_slot_real pri ppf def =
1542 let rec aux ppf = function
1543 | [] -> Format.fprintf ppf "Empty"
1544 | [ h ] -> (do_print pri) ppf h
1545 | h :: t -> Format.fprintf ppf "%a |@ %a" (do_print pri) h aux t
1546 in
1547 if (pri >= 2) && (List.length def >= 2)
1548 then Format.fprintf ppf "@[(%a)@]" aux def
1549 else aux ppf def
1550 and do_print pri ppf = function
1551 | Neg { def = [] } -> Format.fprintf ppf "Any"
1552 | Neg t -> Format.fprintf ppf "Any \\ (@[%a@])" (do_print_slot 0) t
1553 | Abs t -> Format.fprintf ppf "?(@[%a@])" (do_print_slot 0) t
1554 | Name n -> Format.fprintf ppf "%a" U.print n
1555 | Char c -> Chars.V.print ppf c
1556 | Regexp r -> Format.fprintf ppf "@[[ %a ]@]" (do_print_regexp 0) r
1557 | Atomic a -> a ppf
1558 | Pair (t1,t2) ->
1559 Format.fprintf ppf "@[(%a,%a)@]"
1560 (do_print_slot 0) t1
1561 (do_print_slot 0) t2
1562 | Xml (tag,attr,t) ->
1563 Format.fprintf ppf "<%a%a>%a"
1564 do_print_tag tag
1565 do_print_attr attr
1566 (do_print_slot 2) t
1567 | Record (r,some,none) ->
1568 if some then Format.fprintf ppf "@[{"
1569 else Format.fprintf ppf "@[{|";
1570 do_print_record ppf r;
1571 if not none then Format.fprintf ppf ";@ ...";
1572 if some then Format.fprintf ppf " }@]"
1573 else Format.fprintf ppf " |}@]"
1574 | Arrows (p,n) ->
1575 (match p with
1576 | [] -> Format.fprintf ppf "Arrow"
1577 | (t,s)::l ->
1578 Format.fprintf ppf "%a" (do_print_arrow pri) (t,s);
1579 List.iter
1580 (fun (t,s) ->
1581 Format.fprintf ppf " &@ %a" (do_print_arrow pri) (t,s)
1582 ) l);
1583 List.iter
1584 (fun (t,s) ->
1585 Format.fprintf ppf " \\@ %a" (do_print_arrow pri) (t,s)
1586 ) n
1587 and do_print_arrow pri ppf (t,s) =
1588 if (pri = 3) then Format.fprintf ppf "(";
1589 Format.fprintf ppf "%a -> %a"
1590 (do_print_slot 3) t
1591 (do_print_slot 2) s;
1592 if (pri = 3) then Format.fprintf ppf ")"
1593 and do_print_tag ppf = function
1594 | `Tag s -> s ppf
1595 | `Type t -> Format.fprintf ppf "(%a)" (do_print_slot 0) t
1596 and do_print_attr ppf = function
1597 | { state = `Marked|`Expand;
1598 def = [ Record (r,true,true) ] } -> do_print_record ppf r
1599 | t -> Format.fprintf ppf " %a" (do_print_slot 2) t
1600 and do_print_record ppf r =
1601 let first = ref true in
1602 List.iter
1603 (fun (l,(o,t)) ->
1604 let sep = if !first then (first := false; "") else ";" in
1605 let opt = if o then "?" else "" in
1606 Format.fprintf ppf "%s@ @[%a =%s@] %a" sep
1607 Label.print (LabelPool.value l) opt (do_print_slot 0) t
1608 ) (LabelMap.get r)
1609 and do_print_regexp pri ppf = function
1610 | Pretty.Empty -> Format.fprintf ppf "Empty" (*assert false *)
1611 | Pretty.Epsilon -> ()
1612 | Pretty.Seq (Pretty.Trans { def = [ Char _ ] }, _) as r->
1613 (match extract_string [] r with
1614 | s, None ->
1615 Format.fprintf ppf "'";
1616 List.iter (Chars.V.print_in_string ppf) s;
1617 Format.fprintf ppf "'"
1618 | s, Some r ->
1619 if pri >= 3 then Format.fprintf ppf "@[(";
1620 Format.fprintf ppf "'";
1621 List.iter (Chars.V.print_in_string ppf) s;
1622 Format.fprintf ppf "' %a" (do_print_regexp 2) r;
1623 if pri >= 3 then Format.fprintf ppf ")@]")
1624 | Pretty.Seq (r1,r2) ->
1625 if pri >= 3 then Format.fprintf ppf "@[(";
1626 Format.fprintf ppf "%a@ %a"
1627 (do_print_regexp 2) r1
1628 (do_print_regexp 2) r2;
1629 if pri >= 3 then Format.fprintf ppf ")@]"
1630 | Pretty.Alt (r,Pretty.Epsilon) | Pretty.Alt (Pretty.Epsilon,r) ->
1631 Format.fprintf ppf "@[%a@]?" (do_print_regexp 3) r
1632 | Pretty.Alt (r1,r2) ->
1633 if pri >= 2 then Format.fprintf ppf "@[(";
1634 Format.fprintf ppf "%a |@ %a"
1635 (do_print_regexp 1) r1
1636 (do_print_regexp 1) r2;
1637 if pri >= 2 then Format.fprintf ppf ")@]"
1638 | Pretty.Star r ->
1639 Format.fprintf ppf "@[%a@]*" (do_print_regexp 3) r
1640 | Pretty.Plus r ->
1641 Format.fprintf ppf "@[%a@]+" (do_print_regexp 3) r
1642 | Pretty.Trans t ->
1643 do_print_slot pri ppf t
1644 and extract_string accu = function
1645 | Pretty.Seq (Pretty.Trans { def = [ Char c ] }, r) ->
1646 extract_string (c :: accu) r
1647 | Pretty.Trans { def = [ Char c ] } ->
1648 (List.rev (c :: accu), None)
1649 | r -> (List.rev accu,Some r)
1650
1651
1652 let get_name = function
1653 | { state = `Named n } -> n
1654 | _ -> assert false
1655
1656 let print ppf t =
1657 let t = prepare t in
1658 assign_name t;
1659 Format.fprintf ppf "@[@[%a@]" (do_print_slot 0) t;
1660 (match List.rev !to_print with
1661 | [] -> ()
1662 | s::t ->
1663 Format.fprintf ppf
1664 " where@ @[<v>%a = @[%a@]" U.print (get_name s)
1665 (do_print_slot_real 0) s.def;
1666 List.iter
1667 (fun s ->
1668 Format.fprintf ppf " and@ %a = @[%a@]" U.print
1669 (get_name s) (do_print_slot_real 0) s.def)
1670 t;
1671 Format.fprintf ppf "@]"
1672 );
1673 Format.fprintf ppf "@]";
1674 count_name := 0;
1675 to_print := [];
1676 DescrHash.clear memo
1677
1678 let print_noname ppf t =
1679 let old_named = !named in
1680 let old_named_xml = !named_xml in
1681 unregister_global t;
1682 print ppf t;
1683 named := old_named;
1684 named_xml := old_named_xml
1685
1686 let print_node ppf n = print ppf (descr n)
1687
1688 let () = forward_print := print
1689 end
1690
1691 module Positive =
1692 struct
1693 type rhs = [ `Type of descr | `Cup of v list | `Times of v * v | `Xml of v * v ]
1694 and v = { mutable def : rhs; mutable node : node option }
1695
1696
1697 let rec make_descr seen v =
1698 if List.memq v seen then empty
1699 else
1700 let seen = v :: seen in
1701 match v.def with
1702 | `Type d -> d
1703 | `Cup vl ->
1704 List.fold_left (fun acc v -> cup acc (make_descr seen v)) empty vl
1705 | `Times (v1,v2) -> times (make_node v1) (make_node v2)
1706 | `Xml (v1,v2) -> xml (make_node v1) (make_node v2)
1707
1708 and make_node v =
1709 match v.node with
1710 | Some n -> n
1711 | None ->
1712 let n = make () in
1713 v.node <- Some n;
1714 let d = make_descr [] v in
1715 define n d;
1716 n
1717
1718 let forward () = { def = `Cup []; node = None }
1719 let def v d = v.def <- d
1720 let cons d = let v = forward () in def v d; v
1721 let ty d = cons (`Type d)
1722 let cup vl = cons (`Cup vl)
1723 let times d1 d2 = cons (`Times (d1,d2))
1724 let xml d1 d2 = cons (`Xml (d1,d2))
1725 let define v1 v2 = def v1 (`Cup [v2])
1726
1727 let solve v = internalize (make_node v)
1728 end
1729
1730
1731 let memo_normalize = ref DescrMap.empty
1732
1733
1734 let rec rec_normalize d =
1735 try DescrMap.find d !memo_normalize
1736 with Not_found ->
1737 let n = make () in
1738 memo_normalize := DescrMap.add d n !memo_normalize;
1739 let times =
1740 List.fold_left
1741 (fun accu (d1,d2) -> BoolPair.cup accu (BoolPair.atom (rec_normalize d1, rec_normalize d2)))
1742 BoolPair.empty (Product.normal d)
1743 in
1744 let xml =
1745 List.fold_left
1746 (fun accu (d1,d2) -> BoolPair.cup accu (BoolPair.atom (rec_normalize d1, rec_normalize d2)))
1747 BoolPair.empty (Product.normal ~kind:`XML d)
1748 in
1749 let record = d.record
1750 in
1751 define n { d with hash=0; times = times; xml = xml; record = record };
1752 n
1753
1754 let normalize n =
1755 descr (internalize (rec_normalize n))
1756
1757 module Arrow =
1758 struct
1759 let check_simple left (s1,s2) =
1760 let rec aux accu1 accu2 = function
1761 | (t1,t2)::left ->
1762 let accu1' = diff_t accu1 t1 in
1763 if non_empty accu1' then aux accu1 accu2 left;
1764 let accu2' = cap_t accu2 t2 in
1765 if non_empty accu2' then aux accu1 accu2 left
1766 | [] -> raise NotEmpty
1767 in
1768 let accu1 = descr s1 in
1769 (is_empty accu1) ||
1770 (try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false)
1771
1772 let check_line_non_empty (left,right) =
1773 not (List.exists (check_simple left) right)
1774
1775 let sample t =
1776 let (left,right) = List.find check_line_non_empty (BoolPair.get t.arrow) in
1777 List.fold_left (fun accu (t,s) -> cap accu (arrow t s))
1778 { empty with hash=0; arrow = any.arrow } left
1779
1780
1781 let check_strenghten t s =
1782 (*
1783 let left = match (BoolPair.get t.arrow) with [ (p,[]) ] -> p | _ -> assert false in
1784 let rec aux = function
1785 | [] -> raise Not_found
1786 | (p,n) :: rem ->
1787 if (List.for_all (fun (a,b) -> check_simple left a b) p) &&
1788 (List.for_all (fun (a,b) -> not (check_simple left a b)) n) then
1789 { empty with hash=0; arrow = Obj.magic [ (SortedList.cup left p, n) ] } (* rework this ! *)
1790 else aux rem
1791 in
1792 aux (BoolPair.get s.arrow)
1793 *)
1794 if subtype t s then t else raise Not_found
1795
1796 let check_simple_iface left s1 s2 =
1797 let rec aux accu1 accu2 = function
1798 | (t1,t2)::left ->
1799 let accu1' = diff accu1 t1 in
1800 if non_empty accu1' then aux accu1 accu2 left;
1801 let accu2' = cap accu2 t2 in
1802 if non_empty accu2' then aux accu1 accu2 left
1803 | [] -> raise NotEmpty
1804 in
1805 let accu1 = descr s1 in
1806 (is_empty accu1) ||
1807 (try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false)
1808
1809 let check_iface iface s =
1810 let rec aux = function
1811 | [] -> false
1812 | (p,n) :: rem ->
1813 ((List.for_all (fun (a,b) -> check_simple_iface iface a b) p) &&
1814 (List.for_all (fun (a,b) -> not (check_simple_iface iface a b)) n))
1815 || (aux rem)
1816 in
1817 aux (BoolPair.get s.arrow)
1818
1819 type t = descr * (descr * descr) list list
1820
1821 let get t =
1822 List.fold_left
1823 (fun ((dom,arr) as accu) (left,right) ->
1824 if check_line_non_empty (left,right)
1825 then
1826 let left = List.map (fun (t,s) -> (descr t, descr s)) left in
1827 let d = List.fold_left (fun d (t,_) -> cup d t) empty left in
1828 (cap dom d, left :: arr)
1829 else accu
1830 )
1831 (any, [])
1832 (BoolPair.get t.arrow)
1833
1834 let domain (dom,_) = dom
1835
1836 let apply_simple t result left =
1837 let rec aux result accu1 accu2 = function
1838 | (t1,s1)::left ->
1839 let result =
1840 let accu1 = diff accu1 t1 in
1841 if non_empty accu1 then aux result accu1 accu2 left
1842 else result in
1843 let result =
1844 let accu2 = cap accu2 s1 in
1845 aux result accu1 accu2 left in
1846 result
1847 | [] ->
1848 if subtype accu2 result
1849 then result
1850 else cup result accu2
1851 in
1852 aux result t any left
1853
1854 let apply (_,arr) t =
1855 List.fold_left (apply_simple t) empty arr
1856
1857 let need_arg (dom, arr) =
1858 List.exists (function [_] -> false | _ -> true) arr
1859
1860 let apply_noarg (_,arr) =
1861 List.fold_left
1862 (fun accu ->
1863 function
1864 | [(t,s)] -> cup accu s
1865 | _ -> assert false
1866 )
1867 empty arr
1868
1869 let any = { empty with hash=0; arrow = any.arrow }
1870 let is_empty (_,arr) = arr == []
1871 end
1872
1873
1874 module Int = struct
1875 let has_int d i = Intervals.contains i d.ints
1876 let get d = d.ints
1877 let any = { empty with hash=0; ints = any.ints }
1878 end
1879
1880 module Atom = struct
1881 let has_atom d a = Atoms.contains a d.atoms
1882 let get d = d.atoms
1883 let any = { empty with hash=0; atoms = any.atoms }
1884 end
1885
1886 module Char = struct
1887 let has_char d c = Chars.contains c d.chars
1888 let is_empty d = Chars.is_empty d.chars
1889 let get d = d.chars
1890 let any = { empty with hash=0; chars = any.chars }
1891 end
1892
1893 (* <helpers> *)
1894
1895 let rec tuple = function
1896 | [t1;t2] -> times t1 t2
1897 | t::tl -> times t (cons (tuple tl))
1898 | _ -> assert false
1899
1900 let choice_of_list = List.fold_left cup empty
1901
1902 let xml' tag attrs cont = xml (cons tag) (cons (times (cons attrs) (cons cont)))
1903
1904 let rec_of_list ?(opened=true) l =
1905 let map =
1906 List.fold_left
1907 (fun acc (qname, typ) ->
1908 LabelMap.union_disj acc
1909 (LabelMap.singleton (LabelPool.mk qname) (cons typ)))
1910 LabelMap.empty
1911 l
1912 in
1913 record' (opened, map)
1914
1915 let rec_of_list' ?(opened=true) l =
1916 let map =
1917 List.fold_left
1918 (fun acc (opt, qname, typ) ->
1919 LabelMap.union_disj acc
1920 (LabelMap.singleton (LabelPool.mk qname)
1921 (if opt then cons (Record.or_absent typ) else (cons typ))))
1922 LabelMap.empty
1923 l
1924 in
1925 record' (opened, map)
1926
1927 let empty_closed_record = rec_of_list ~opened:false []
1928 let empty_opened_record = rec_of_list ~opened:true []
1929
1930 (* </helpers> *)
1931
1932 let cond_partition univ qs =
1933 let rec add accu (t,s) =
1934 let t = if subtype t s then t else cap t s in
1935 if (subtype s t) || (is_empty t) then accu else
1936 let rec aux accu u =
1937 let c = cap u t in
1938 if (is_empty c) || (subtype (cap u s) t) then u::accu
1939 else c::(diff u t)::accu
1940 in
1941 List.fold_left aux [] accu
1942 in
1943 List.fold_left add [ univ ] qs
1944
1945

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