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

Diff of /types/types.ml

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.71  
changed lines
  Added in v.698

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