| 20 |
|
|
| 21 |
type const = Integer of Big_int.big_int | Atom of atom | Char of Chars.Unichar.t |
type const = Integer of Big_int.big_int | Atom of atom | Char of Chars.Unichar.t |
| 22 |
|
|
| 23 |
|
type pair_kind = [ `Normal | `XML ] |
| 24 |
|
|
| 25 |
module I = struct |
module I = struct |
| 26 |
type 'a t = { |
type 'a t = { |
| 27 |
ints : Intervals.t; |
ints : Intervals.t; |
| 28 |
atoms : atom Atoms.t; |
atoms : atom Atoms.t; |
| 29 |
times : ('a * 'a) Boolean.t; |
times : ('a * 'a) Boolean.t; |
| 30 |
|
xml : ('a * 'a) Boolean.t; |
| 31 |
arrow : ('a * 'a) Boolean.t; |
arrow : ('a * 'a) Boolean.t; |
| 32 |
record: (label * bool * 'a) Boolean.t; |
record: (label * bool * 'a) Boolean.t; |
| 33 |
chars : Chars.t; |
chars : Chars.t; |
| 35 |
|
|
| 36 |
let empty = { |
let empty = { |
| 37 |
times = Boolean.empty; |
times = Boolean.empty; |
| 38 |
|
xml = Boolean.empty; |
| 39 |
arrow = Boolean.empty; |
arrow = Boolean.empty; |
| 40 |
record= Boolean.empty; |
record= Boolean.empty; |
| 41 |
ints = Intervals.empty; |
ints = Intervals.empty; |
| 42 |
atoms = Atoms.empty; |
atoms = Atoms.empty; |
| 43 |
chars = Chars.empty; |
chars = Chars.empty; |
| 44 |
} |
} |
| 45 |
|
(* |
| 46 |
let any = { |
let any = { |
| 47 |
times = Boolean.full; |
times = Boolean.full; |
| 48 |
|
xml = Boolean.full; |
| 49 |
arrow = Boolean.full; |
arrow = Boolean.full; |
| 50 |
record= Boolean.full; |
record= Boolean.full; |
| 51 |
ints = Intervals.any; |
ints = Intervals.any; |
| 52 |
atoms = Atoms.any; |
atoms = Atoms.any; |
| 53 |
chars = Chars.any; |
chars = Chars.any; |
| 54 |
} |
} |
| 55 |
|
*) |
| 56 |
|
|
| 57 |
let interval i = { empty with ints = i } |
let interval i = { empty with ints = i } |
| 58 |
let times x y = { empty with times = Boolean.atom (x,y) } |
let times x y = { empty with times = Boolean.atom (x,y) } |
| 59 |
|
let xml x y = { empty with xml = Boolean.atom (x,y) } |
| 60 |
let arrow x y = { empty with arrow = Boolean.atom (x,y) } |
let arrow x y = { empty with arrow = Boolean.atom (x,y) } |
| 61 |
let record label opt t = { empty with record = Boolean.atom (label,opt,t) } |
let record label opt t = { empty with record = Boolean.atom (label,opt,t) } |
| 62 |
let atom a = { empty with atoms = a } |
let atom a = { empty with atoms = a } |
| 67 |
| Char c -> char (Chars.atom c) |
| Char c -> char (Chars.atom c) |
| 68 |
|
|
| 69 |
|
|
|
let any_record = { empty with record = any.record } |
|
|
|
|
| 70 |
let cup x y = |
let cup x y = |
| 71 |
if x = y then x else { |
if x = y then x else { |
| 72 |
times = Boolean.cup x.times y.times; |
times = Boolean.cup x.times y.times; |
| 73 |
|
xml = Boolean.cup x.xml y.xml; |
| 74 |
arrow = Boolean.cup x.arrow y.arrow; |
arrow = Boolean.cup x.arrow y.arrow; |
| 75 |
record= Boolean.cup x.record y.record; |
record= Boolean.cup x.record y.record; |
| 76 |
ints = Intervals.cup x.ints y.ints; |
ints = Intervals.cup x.ints y.ints; |
| 81 |
let cap x y = |
let cap x y = |
| 82 |
if x = y then x else { |
if x = y then x else { |
| 83 |
times = Boolean.cap x.times y.times; |
times = Boolean.cap x.times y.times; |
| 84 |
|
xml = Boolean.cap x.xml y.xml; |
| 85 |
record= Boolean.cap x.record y.record; |
record= Boolean.cap x.record y.record; |
| 86 |
arrow = Boolean.cap x.arrow y.arrow; |
arrow = Boolean.cap x.arrow y.arrow; |
| 87 |
ints = Intervals.cap x.ints y.ints; |
ints = Intervals.cap x.ints y.ints; |
| 92 |
let diff x y = |
let diff x y = |
| 93 |
if x = y then empty else { |
if x = y then empty else { |
| 94 |
times = Boolean.diff x.times y.times; |
times = Boolean.diff x.times y.times; |
| 95 |
|
xml = Boolean.diff x.xml y.xml; |
| 96 |
arrow = Boolean.diff x.arrow y.arrow; |
arrow = Boolean.diff x.arrow y.arrow; |
| 97 |
record= Boolean.diff x.record y.record; |
record= Boolean.diff x.record y.record; |
| 98 |
ints = Intervals.diff x.ints y.ints; |
ints = Intervals.diff x.ints y.ints; |
| 100 |
chars = Chars.diff x.chars y.chars; |
chars = Chars.diff x.chars y.chars; |
| 101 |
} |
} |
| 102 |
|
|
|
let neg x = diff any x |
|
| 103 |
|
|
| 104 |
let equal e a b = |
let equal e a b = |
| 105 |
if a.atoms <> b.atoms then raise NotEqual; |
if a.atoms <> b.atoms then raise NotEqual; |
| 106 |
if a.chars <> b.chars then raise NotEqual; |
if a.chars <> b.chars then raise NotEqual; |
| 107 |
if a.ints <> b.ints then raise NotEqual; |
if a.ints <> b.ints then raise NotEqual; |
| 108 |
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.times b.times; |
| 109 |
|
Boolean.equal (fun (x1,x2) (y1,y2) -> e x1 y1; e x2 y2) a.xml b.xml; |
| 110 |
Boolean.equal (fun (x1,x2) (y1,y2) -> e x1 y1; e x2 y2) a.arrow b.arrow; |
Boolean.equal (fun (x1,x2) (y1,y2) -> e x1 y1; e x2 y2) a.arrow b.arrow; |
| 111 |
Boolean.equal (fun (l1,o1,x1) (l2,o2,x2) -> |
Boolean.equal (fun (l1,o1,x1) (l2,o2,x2) -> |
| 112 |
if (l1 <> l2) || (o1 <> o2) then raise NotEqual; |
if (l1 <> l2) || (o1 <> o2) then raise NotEqual; |
| 114 |
|
|
| 115 |
let map f a = |
let map f a = |
| 116 |
{ times = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.times; |
{ times = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.times; |
| 117 |
|
xml = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.xml; |
| 118 |
arrow = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.arrow; |
arrow = Boolean.map (fun (x1,x2) -> (f x1, f x2)) a.arrow; |
| 119 |
record= Boolean.map (fun (l,o,x) -> (l,o, f x)) a.record; |
record= Boolean.map (fun (l,o,x) -> (l,o, f x)) a.record; |
| 120 |
ints = a.ints; |
ints = a.ints; |
| 148 |
end |
end |
| 149 |
) |
) |
| 150 |
|
|
| 151 |
|
(* |
| 152 |
|
let define n d = check d; define n d |
| 153 |
|
*) |
| 154 |
|
|
| 155 |
|
let cons d = |
| 156 |
|
let n = make () in |
| 157 |
|
define n d; |
| 158 |
|
internalize n |
| 159 |
|
|
| 160 |
|
let any_rec = cons { empty with record = Boolean.full } |
| 161 |
|
let any_node = make ();; |
| 162 |
|
define any_node { |
| 163 |
|
times = Boolean.full; |
| 164 |
|
xml = Boolean.atom |
| 165 |
|
(cons { empty with atoms = Atoms.any }, |
| 166 |
|
cons (times any_rec any_node)); |
| 167 |
|
arrow = Boolean.full; |
| 168 |
|
record= Boolean.full; |
| 169 |
|
ints = Intervals.any; |
| 170 |
|
atoms = Atoms.any; |
| 171 |
|
chars = Chars.any; |
| 172 |
|
};; |
| 173 |
|
internalize any_node;; |
| 174 |
|
let any = descr any_node |
| 175 |
|
|
| 176 |
|
let neg x = diff any x |
| 177 |
|
|
| 178 |
|
let get_record r = |
| 179 |
|
let add = SortedMap.add (fun (o1,t1) (o2,t2) -> (o1&&o2, cap t1 t2)) in |
| 180 |
|
let line (p,n) = |
| 181 |
|
let accu = List.fold_left |
| 182 |
|
(fun accu (l,o,t) -> add l (o,descr t) accu) [] p in |
| 183 |
|
List.fold_left |
| 184 |
|
(fun accu (l,o,t) -> add l (not o,neg (descr t)) accu) accu n in |
| 185 |
|
List.map line r |
| 186 |
|
|
| 187 |
|
|
| 188 |
module DescrMap = Map.Make(struct type t = descr let compare = compare end) |
module DescrMap = Map.Make(struct type t = descr let compare = compare end) |
| 189 |
|
|
| 190 |
let check d = |
let check d = |
| 191 |
Boolean.check d.times; |
Boolean.check d.times; |
| 192 |
|
Boolean.check d.xml; |
| 193 |
Boolean.check d.arrow; |
Boolean.check d.arrow; |
| 194 |
Boolean.check d.record; |
Boolean.check d.record; |
| 195 |
() |
() |
| 196 |
|
|
| 197 |
|
|
| 198 |
|
|
| 199 |
|
(* Subtyping algorithm *) |
| 200 |
|
|
| 201 |
|
let diff_t d t = diff d (descr t) |
| 202 |
|
let cap_t d t = cap d (descr t) |
| 203 |
|
let cup_t d t = cup d (descr t) |
| 204 |
|
let cap_product l = |
| 205 |
|
List.fold_left |
| 206 |
|
(fun (d1,d2) (t1,t2) -> (cap_t d1 t1, cap_t d2 t2)) |
| 207 |
|
(any,any) |
| 208 |
|
l |
| 209 |
|
|
| 210 |
|
|
| 211 |
|
let cup_product l = |
| 212 |
|
List.fold_left |
| 213 |
|
(fun (d1,d2) (t1,t2) -> (cup_t d1 t1, cup_t d2 t2)) |
| 214 |
|
(empty,empty) |
| 215 |
|
l |
| 216 |
|
|
| 217 |
|
|
| 218 |
|
module Assumptions = Set.Make(struct type t = descr let compare = compare end) |
| 219 |
|
|
| 220 |
|
let memo = ref Assumptions.empty |
| 221 |
|
let cache_false = ref Assumptions.empty |
| 222 |
|
|
| 223 |
|
exception NotEmpty |
| 224 |
|
|
| 225 |
|
let rec empty_rec d = |
| 226 |
|
if Assumptions.mem d !cache_false then false |
| 227 |
|
else if Assumptions.mem d !memo then true |
| 228 |
|
else if not (Intervals.is_empty d.ints) then false |
| 229 |
|
else if not (Atoms.is_empty d.atoms) then false |
| 230 |
|
else if not (Chars.is_empty d.chars) then false |
| 231 |
|
else ( |
| 232 |
|
let backup = !memo in |
| 233 |
|
memo := Assumptions.add d backup; |
| 234 |
|
if |
| 235 |
|
(empty_rec_times d.times) && |
| 236 |
|
(empty_rec_times d.xml) && |
| 237 |
|
(empty_rec_arrow d.arrow) && |
| 238 |
|
(empty_rec_record d.record) |
| 239 |
|
then true |
| 240 |
|
else ( |
| 241 |
|
memo := backup; |
| 242 |
|
cache_false := Assumptions.add d !cache_false; |
| 243 |
|
false |
| 244 |
|
) |
| 245 |
|
) |
| 246 |
|
|
| 247 |
|
and empty_rec_times c = |
| 248 |
|
List.for_all empty_rec_times_aux c |
| 249 |
|
|
| 250 |
|
and empty_rec_times_aux (left,right) = |
| 251 |
|
let rec aux accu1 accu2 = function |
| 252 |
|
| (t1,t2)::right -> |
| 253 |
|
let accu1' = diff_t accu1 t1 in |
| 254 |
|
if not (empty_rec accu1') then aux accu1' accu2 right; |
| 255 |
|
let accu2' = diff_t accu2 t2 in |
| 256 |
|
if not (empty_rec accu2') then aux accu1 accu2' right |
| 257 |
|
| [] -> raise NotEmpty |
| 258 |
|
in |
| 259 |
|
let (accu1,accu2) = cap_product left in |
| 260 |
|
(empty_rec accu1) || (empty_rec accu2) || |
| 261 |
|
(* OPT? It does'nt seem so ... The hope was to return false quickly |
| 262 |
|
for large right hand-side *) |
| 263 |
|
( |
| 264 |
|
((*if (List length right > 2) then |
| 265 |
|
let (cup1,cup2) = cup_product right in |
| 266 |
|
(empty_rec (diff accu1 cup1)) && (empty_rec (diff accu2 cup2)) |
| 267 |
|
else*) true) |
| 268 |
|
&& |
| 269 |
|
(try aux accu1 accu2 right; true with NotEmpty -> false) |
| 270 |
|
) |
| 271 |
|
|
| 272 |
|
and empty_rec_arrow c = |
| 273 |
|
List.for_all empty_rec_arrow_aux c |
| 274 |
|
|
| 275 |
|
and empty_rec_arrow_aux (left,right) = |
| 276 |
|
let single_right (s1,s2) = |
| 277 |
|
let rec aux accu1 accu2 = function |
| 278 |
|
| (t1,t2)::left -> |
| 279 |
|
let accu1' = diff_t accu1 t1 in |
| 280 |
|
if not (empty_rec accu1') then aux accu1 accu2 left; |
| 281 |
|
let accu2' = cap_t accu2 t2 in |
| 282 |
|
if not (empty_rec accu2') then aux accu1 accu2 left |
| 283 |
|
| [] -> raise NotEmpty |
| 284 |
|
in |
| 285 |
|
let accu1 = descr s1 in |
| 286 |
|
(empty_rec accu1) || |
| 287 |
|
(try aux accu1 (diff any (descr s2)) left; true with NotEmpty -> false) |
| 288 |
|
in |
| 289 |
|
List.exists single_right right |
| 290 |
|
|
| 291 |
|
and empty_rec_record c = |
| 292 |
|
let aux = List.exists (fun (_,(opt,t)) -> (not opt) && (empty_rec t)) in |
| 293 |
|
List.for_all aux (get_record c) |
| 294 |
|
|
| 295 |
|
let is_empty d = |
| 296 |
|
let old = !memo in |
| 297 |
|
let r = empty_rec d in |
| 298 |
|
if not r then memo := old; |
| 299 |
|
(* cache_false := Assumptions.empty; *) |
| 300 |
|
r |
| 301 |
|
|
| 302 |
|
let non_empty d = |
| 303 |
|
not (is_empty d) |
| 304 |
|
|
| 305 |
|
let subtype d1 d2 = |
| 306 |
|
is_empty (diff d1 d2) |
| 307 |
|
|
| 308 |
|
module Product = |
| 309 |
|
struct |
| 310 |
|
type t = (descr * descr) list |
| 311 |
|
|
| 312 |
|
let other ?(kind=`Normal) d = |
| 313 |
|
match kind with |
| 314 |
|
| `Normal -> { d with times = empty.times } |
| 315 |
|
| `XML -> { d with xml = empty.xml } |
| 316 |
|
|
| 317 |
|
let is_product ?kind d = is_empty (other ?kind d) |
| 318 |
|
|
| 319 |
|
let need_second = function _::_::_ -> true | _ -> false |
| 320 |
|
|
| 321 |
|
let normal_aux d = |
| 322 |
|
let res = ref [] in |
| 323 |
|
|
| 324 |
|
let add (t1,t2) = |
| 325 |
|
let rec loop t1 t2 = function |
| 326 |
|
| [] -> res := (ref (t1,t2)) :: !res |
| 327 |
|
| ({contents = (d1,d2)} as r)::l -> |
| 328 |
|
(*OPT*) |
| 329 |
|
if d1 = t1 then r := (d1,cup d2 t2) else |
| 330 |
|
|
| 331 |
|
let i = cap t1 d1 in |
| 332 |
|
if is_empty i then loop t1 t2 l |
| 333 |
|
else ( |
| 334 |
|
r := (i, cup t2 d2); |
| 335 |
|
let k = diff d1 t1 in |
| 336 |
|
if non_empty k then res := (ref (k,d2)) :: !res; |
| 337 |
|
|
| 338 |
|
let j = diff t1 d1 in |
| 339 |
|
if non_empty j then loop j t2 l |
| 340 |
|
) |
| 341 |
|
in |
| 342 |
|
loop t1 t2 !res |
| 343 |
|
in |
| 344 |
|
List.iter add d; |
| 345 |
|
List.map (!) !res |
| 346 |
|
|
| 347 |
(* |
(* |
| 348 |
let define n d = check d; define n d |
This version explodes when dealing with |
| 349 |
|
Any - [ t1? t2? t3? ... tn? ] |
| 350 |
|
==> need partitioning |
| 351 |
*) |
*) |
| 352 |
|
let get_aux d = |
| 353 |
|
let line accu (left,right) = |
| 354 |
|
let rec aux accu d1 d2 = function |
| 355 |
|
| (t1,t2)::right -> |
| 356 |
|
let accu = |
| 357 |
|
let d1 = diff_t d1 t1 in |
| 358 |
|
if is_empty d1 then accu else aux accu d1 d2 right in |
| 359 |
|
let accu = |
| 360 |
|
let d2 = diff_t d2 t2 in |
| 361 |
|
if is_empty d2 then accu else aux accu d1 d2 right in |
| 362 |
|
accu |
| 363 |
|
| [] -> (d1,d2) :: accu |
| 364 |
|
in |
| 365 |
|
let (d1,d2) = cap_product left in |
| 366 |
|
if (is_empty d1) || (is_empty d2) then accu else aux accu d1 d2 right |
| 367 |
|
in |
| 368 |
|
List.fold_left line [] d |
| 369 |
|
|
| 370 |
let cons d = |
(* Partitioning: |
| 371 |
let n = make () in |
|
| 372 |
define n d; |
(t,s) - ((t1,s1) | (t2,s2) | ... | (tn,sn)) |
| 373 |
internalize n |
= |
| 374 |
|
(t & t1, s - s1) | ... | (t & tn, s - sn) | (t - (t1|...|tn), s) |
| 375 |
|
|
| 376 |
|
*) |
| 377 |
|
|
| 378 |
|
let get_aux d = |
| 379 |
|
let accu = ref [] in |
| 380 |
|
let line (left,right) = |
| 381 |
|
let (d1,d2) = cap_product left in |
| 382 |
|
if (non_empty d1) && (non_empty d2) then |
| 383 |
|
let right = List.map (fun (t1,t2) -> descr t1, descr t2) right in |
| 384 |
|
let right = normal_aux right in |
| 385 |
|
let resid1 = ref d1 in |
| 386 |
|
let () = |
| 387 |
|
List.iter |
| 388 |
|
(fun (t1,t2) -> |
| 389 |
|
let t1 = cap d1 t1 in |
| 390 |
|
if (non_empty t1) then |
| 391 |
|
let () = resid1 := diff !resid1 t1 in |
| 392 |
|
let t2 = diff d2 t2 in |
| 393 |
|
if (non_empty t2) then accu := (t1,t2) :: !accu |
| 394 |
|
) right in |
| 395 |
|
if non_empty !resid1 then accu := (!resid1, d2) :: !accu |
| 396 |
|
in |
| 397 |
|
List.iter line d; |
| 398 |
|
!accu |
| 399 |
|
|
| 400 |
|
let get ?(kind=`Normal) d = |
| 401 |
|
match kind with |
| 402 |
|
| `Normal -> get_aux d.times |
| 403 |
|
| `XML -> get_aux d.xml |
| 404 |
|
|
| 405 |
|
let pi1 = List.fold_left (fun acc (t1,_) -> cup acc t1) empty |
| 406 |
|
let pi2 = List.fold_left (fun acc (_,t2) -> cup acc t2) empty |
| 407 |
|
|
| 408 |
|
let restrict_1 rects pi1 = |
| 409 |
|
let aux accu (t1,t2) = |
| 410 |
|
let t1 = cap t1 pi1 in if is_empty t1 then accu else (t1,t2)::accu in |
| 411 |
|
List.fold_left aux [] rects |
| 412 |
|
|
| 413 |
|
type normal = t |
| 414 |
|
|
| 415 |
|
module Memo = Map.Make(struct |
| 416 |
|
type t = (node * node) Boolean.t |
| 417 |
|
let compare = compare end) |
| 418 |
|
|
| 419 |
|
|
| 420 |
|
|
| 421 |
|
let memo = ref Memo.empty |
| 422 |
|
let normal ?(kind=`Normal) d = |
| 423 |
|
let d = match kind with `Normal -> d.times | `XML -> d.xml in |
| 424 |
|
try Memo.find d !memo |
| 425 |
|
with |
| 426 |
|
Not_found -> |
| 427 |
|
let gd = get_aux d in |
| 428 |
|
let n = normal_aux gd in |
| 429 |
|
memo := Memo.add d n !memo; |
| 430 |
|
n |
| 431 |
|
|
| 432 |
|
let any = { empty with times = any.times } |
| 433 |
|
and any_xml = { empty with xml = any.xml } |
| 434 |
|
let is_empty d = d = [] |
| 435 |
|
end |
| 436 |
|
|
| 437 |
module Print = |
module Print = |
| 438 |
struct |
struct |
| 439 |
|
let rec print_union ppf = function |
| 440 |
|
| [] -> Format.fprintf ppf "Empty" |
| 441 |
|
| [h] -> h ppf |
| 442 |
|
| h::t -> Format.fprintf ppf "@[%t |@ %a@]" h print_union t |
| 443 |
|
|
| 444 |
let print_atom ppf a = |
let print_atom ppf a = |
| 445 |
Format.fprintf ppf "`%s" (AtomPool.value a) |
Format.fprintf ppf "`%s" (AtomPool.value a) |
| 446 |
|
|
| 447 |
|
let print_tag ppf a = |
| 448 |
|
match Atoms.is_atom a with |
| 449 |
|
| Some a -> Format.fprintf ppf "%s" (AtomPool.value a) |
| 450 |
|
| None -> |
| 451 |
|
Format.fprintf ppf "(%a)" |
| 452 |
|
print_union |
| 453 |
|
(Atoms.print "Atom" print_atom a) |
| 454 |
|
|
| 455 |
let print_const ppf = function |
let print_const ppf = function |
| 456 |
| Integer i -> Format.fprintf ppf "%s" (Big_int.string_of_big_int i) |
| Integer i -> Format.fprintf ppf "%s" (Big_int.string_of_big_int i) |
| 457 |
| Atom a -> print_atom ppf a |
| Atom a -> print_atom ppf a |
| 490 |
with Not_found -> |
with Not_found -> |
| 491 |
DescrHash.add marks d (ref None); |
DescrHash.add marks d (ref None); |
| 492 |
bool_iter (fun (n1,n2) -> mark n1; mark n2) d.times; |
bool_iter (fun (n1,n2) -> mark n1; mark n2) d.times; |
| 493 |
|
bool_iter (fun (n1,n2) -> mark n1; mark n2) d.xml; |
| 494 |
bool_iter (fun (n1,n2) -> mark n1; mark n2) d.arrow; |
bool_iter (fun (n1,n2) -> mark n1; mark n2) d.arrow; |
| 495 |
bool_iter (fun (l,o,n) -> mark n) d.record |
bool_iter (fun (l,o,n) -> mark n) d.record |
| 496 |
|
|
| 497 |
|
|
|
let rec print_union ppf = function |
|
|
| [] -> Format.fprintf ppf "Empty" |
|
|
| [h] -> h ppf |
|
|
| h::t -> Format.fprintf ppf "@[%t |@ %a@]" h print_union t |
|
|
|
|
|
|
|
| 498 |
let rec print ppf n = print_descr ppf (descr n) |
let rec print ppf n = print_descr ppf (descr n) |
| 499 |
and print_descr ppf d = |
and print_descr ppf d = |
| 500 |
try |
try |
| 506 |
| Some n -> Format.fprintf ppf "%s" n |
| Some n -> Format.fprintf ppf "%s" n |
| 507 |
| None -> real_print_descr ppf d |
| None -> real_print_descr ppf d |
| 508 |
with |
with |
| 509 |
Not_found -> Format.fprintf ppf "XXX" |
Not_found -> assert false |
| 510 |
and real_print_descr ppf d = |
and real_print_descr ppf d = |
| 511 |
if d = any then Format.fprintf ppf "Any" else |
if d = any then Format.fprintf ppf "Any" else |
| 512 |
print_union ppf |
print_union ppf |
| 514 |
Chars.print d.chars @ |
Chars.print d.chars @ |
| 515 |
Atoms.print "Atom" print_atom d.atoms @ |
Atoms.print "Atom" print_atom d.atoms @ |
| 516 |
Boolean.print "Pair" print_times d.times @ |
Boolean.print "Pair" print_times d.times @ |
| 517 |
|
Boolean.print "XML" print_xml d.xml @ |
| 518 |
Boolean.print "Arrow" print_arrow d.arrow @ |
Boolean.print "Arrow" print_arrow d.arrow @ |
| 519 |
Boolean.print "Record" print_record d.record |
Boolean.print "Record" print_record d.record |
| 520 |
) |
) |
| 521 |
and print_times ppf (t1,t2) = |
and print_times ppf (t1,t2) = |
| 522 |
Format.fprintf ppf "@[(%a,%a)@]" print t1 print t2 |
Format.fprintf ppf "@[(%a,%a)@]" print t1 print t2 |
| 523 |
|
and print_xml ppf (t1,t2) = |
| 524 |
|
let l = Product.normal (descr t2) in |
| 525 |
|
let l = List.map |
| 526 |
|
(fun (d1,d2) ppf -> |
| 527 |
|
Format.fprintf ppf "@[<><%a%a>%a@]" |
| 528 |
|
print_tag (descr t1).atoms |
| 529 |
|
print_attribs d1.record |
| 530 |
|
print_descr d2) l |
| 531 |
|
in |
| 532 |
|
print_union ppf l |
| 533 |
and print_arrow ppf (t1,t2) = |
and print_arrow ppf (t1,t2) = |
| 534 |
Format.fprintf ppf "@[(%a -> %a)@]" print t1 print t2 |
Format.fprintf ppf "@[(%a -> %a)@]" print t1 print t2 |
| 535 |
and print_record ppf (l,o,t) = |
and print_record ppf (l,o,t) = |
| 536 |
Format.fprintf ppf "@[{ %s =%s %a }@]" |
Format.fprintf ppf "@[{ %s =%s %a }@]" |
| 537 |
(LabelPool.value l) (if o then "?" else "") print t |
(LabelPool.value l) (if o then "?" else "") print t |
| 538 |
|
and print_attribs ppf r = |
| 539 |
|
let l = get_record r in |
| 540 |
|
if l <> [ [] ] then |
| 541 |
|
let l = List.map |
| 542 |
|
(fun att ppf -> |
| 543 |
|
let first = ref true in |
| 544 |
|
Format.fprintf ppf "{" ; |
| 545 |
|
List.iter (fun (l,(o,d)) -> |
| 546 |
|
Format.fprintf ppf "%s%s=%s%a" |
| 547 |
|
(if !first then "" else " ") |
| 548 |
|
(LabelPool.value l) (if o then "?" else "") |
| 549 |
|
print_descr d; |
| 550 |
|
first := false |
| 551 |
|
) att; |
| 552 |
|
Format.fprintf ppf "}" |
| 553 |
|
) l in |
| 554 |
|
print_union ppf l |
| 555 |
|
|
| 556 |
|
|
| 557 |
let end_print ppf = |
let end_print ppf = |
| 619 |
end |
end |
| 620 |
|
|
| 621 |
|
|
|
let get_record r = |
|
|
let add = SortedMap.add (fun (o1,t1) (o2,t2) -> (o1&&o2, cap t1 t2)) in |
|
|
let line (p,n) = |
|
|
let accu = List.fold_left |
|
|
(fun accu (l,o,t) -> add l (o,descr t) accu) [] p in |
|
|
List.fold_left |
|
|
(fun accu (l,o,t) -> add l (not o,neg (descr t)) accu) accu n in |
|
|
List.map line r |
|
|
|
|
|
|
|
|
|
|
|
(* Subtyping algorithm *) |
|
|
|
|
|
let diff_t d t = diff d (descr t) |
|
|
let cap_t d t = cap d (descr t) |
|
|
let cup_t d t = cup d (descr t) |
|
|
let cap_product l = |
|
|
List.fold_left |
|
|
(fun (d1,d2) (t1,t2) -> (cap_t d1 t1, cap_t d2 t2)) |
|
|
(any,any) |
|
|
l |
|
|
let cup_product l = |
|
|
List.fold_left |
|
|
(fun (d1,d2) (t1,t2) -> (cup_t d1 t1, cup_t d2 t2)) |
|
|
(empty,empty) |
|
|
l |
|
|
|
|
|
|
|
|
module Assumptions = Set.Make(struct type t = descr let compare = compare end) |
|
|
|
|
|
let memo = ref Assumptions.empty |
|
|
let cache_false = ref Assumptions.empty |
|
|
|
|
|
exception NotEmpty |
|
|
|
|
|
let rec empty_rec d = |
|
|
if Assumptions.mem d !cache_false then false |
|
|
else if Assumptions.mem d !memo then true |
|
|
else if not (Intervals.is_empty d.ints) then false |
|
|
else if not (Atoms.is_empty d.atoms) then false |
|
|
else if not (Chars.is_empty d.chars) then false |
|
|
else ( |
|
|
let backup = !memo in |
|
|
memo := Assumptions.add d backup; |
|
|
if |
|
|
(empty_rec_times d.times) && |
|
|
(empty_rec_arrow d.arrow) && |
|
|
(empty_rec_record d.record) |
|
|
then true |
|
|
else ( |
|
|
memo := backup; |
|
|
cache_false := Assumptions.add d !cache_false; |
|
|
false |
|
|
) |
|
|
) |
|
|
|
|
|
and empty_rec_times c = |
|
|
List.for_all empty_rec_times_aux c |
|
|
|
|
|
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) || |
|
|
(* OPT? It does'nt seem so ... The hope was to return false quickly |
|
|
for large right hand-side *) |
|
|
( |
|
|
((*if (List length right > 2) then |
|
|
let (cup1,cup2) = cup_product right in |
|
|
(empty_rec (diff accu1 cup1)) && (empty_rec (diff accu2 cup2)) |
|
|
else*) true) |
|
|
&& |
|
|
(try aux accu1 accu2 right; true with NotEmpty -> false) |
|
|
) |
|
|
|
|
|
and empty_rec_arrow c = |
|
|
List.for_all empty_rec_arrow_aux c |
|
|
|
|
|
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 |
|
| 622 |
|
|
|
and empty_rec_record c = |
|
|
let aux = List.exists (fun (_,(opt,t)) -> (not opt) && (empty_rec t)) in |
|
|
List.for_all aux (get_record c) |
|
|
|
|
|
let is_empty d = |
|
|
let old = !memo in |
|
|
let r = empty_rec d in |
|
|
if not r then memo := old; |
|
|
(* cache_false := Assumptions.empty; *) |
|
|
r |
|
|
|
|
|
let non_empty d = |
|
|
not (is_empty d) |
|
|
|
|
|
let subtype d1 d2 = |
|
|
is_empty (diff d1 d2) |
|
| 623 |
|
|
| 624 |
(* Sample value *) |
(* Sample value *) |
| 625 |
module Sample = |
module Sample = |
| 633 |
| Int of Big_int.big_int |
| Int of Big_int.big_int |
| 634 |
| Atom of atom |
| Atom of atom |
| 635 |
| Char of Chars.Unichar.t |
| Char of Chars.Unichar.t |
| 636 |
| Pair of t * t |
| Pair of (t * t) |
| 637 |
|
| Xml of (t * t) |
| 638 |
| Record of (label * t) list |
| Record of (label * t) list |
| 639 |
| Fun of (node * node) list |
| Fun of (node * node) list |
| 640 |
|
|
| 649 |
try sample_rec_arrow d.arrow with Not_found -> |
try sample_rec_arrow d.arrow with Not_found -> |
| 650 |
|
|
| 651 |
let memo = Assumptions.add d memo in |
let memo = Assumptions.add d memo in |
| 652 |
try sample_rec_times memo d.times with Not_found -> |
try Pair (sample_rec_times memo d.times) with Not_found -> |
| 653 |
|
try Xml (sample_rec_times memo d.xml) with Not_found -> |
| 654 |
try sample_rec_record memo d.record with Not_found -> |
try sample_rec_record memo d.record with Not_found -> |
| 655 |
raise Not_found |
raise Not_found |
| 656 |
|
|
| 666 |
let accu2' = diff_t accu2 t2 in |
let accu2' = diff_t accu2 t2 in |
| 667 |
if non_empty accu2' then aux accu1 accu2' right else |
if non_empty accu2' then aux accu1 accu2' right else |
| 668 |
raise Not_found |
raise Not_found |
| 669 |
| [] -> Pair (sample_rec memo accu1, sample_rec memo accu2) |
| [] -> (sample_rec memo accu1, sample_rec memo accu2) |
| 670 |
in |
in |
| 671 |
let (accu1,accu2) = cap_product left in |
let (accu1,accu2) = cap_product left in |
| 672 |
if (is_empty accu1) || (is_empty accu2) then raise Not_found; |
if (is_empty accu1) || (is_empty accu2) then raise Not_found; |
| 720 |
Format.fprintf ppf "`%s" (AtomPool.value a) |
Format.fprintf ppf "`%s" (AtomPool.value a) |
| 721 |
| Char c -> Chars.Unichar.print ppf c |
| Char c -> Chars.Unichar.print ppf c |
| 722 |
| Pair (x1,x2) -> Format.fprintf ppf "(%a,%a)" print x1 print x2 |
| Pair (x1,x2) -> Format.fprintf ppf "(%a,%a)" print x1 print x2 |
| 723 |
|
| Xml (x1,x2) -> Format.fprintf ppf "XML(%a,%a)" print x1 print x2 |
| 724 |
| Record r -> |
| Record r -> |
| 725 |
Format.fprintf ppf "{ %a }" |
Format.fprintf ppf "{ %a }" |
| 726 |
(print_sep |
(print_sep |
| 743 |
end |
end |
| 744 |
|
|
| 745 |
|
|
|
module Product = |
|
|
struct |
|
|
type t = (descr * descr) list |
|
|
|
|
|
let other d = { d with times = empty.times } |
|
|
let is_product d = is_empty (other d) |
|
|
|
|
|
let need_second = function _::_::_ -> true | _ -> false |
|
|
|
|
|
let normal_aux d = |
|
|
let res = ref [] in |
|
|
|
|
|
let add (t1,t2) = |
|
|
let rec loop t1 t2 = function |
|
|
| [] -> res := (ref (t1,t2)) :: !res |
|
|
| ({contents = (d1,d2)} as r)::l -> |
|
|
(*OPT*) |
|
|
if d1 = t1 then r := (d1,cup d2 t2) else |
|
|
|
|
|
let i = cap t1 d1 in |
|
|
if is_empty i then loop t1 t2 l |
|
|
else ( |
|
|
r := (i, cup t2 d2); |
|
|
let k = diff d1 t1 in |
|
|
if non_empty k then res := (ref (k,d2)) :: !res; |
|
|
|
|
|
let j = diff t1 d1 in |
|
|
if non_empty j then loop j t2 l |
|
|
) |
|
|
in |
|
|
loop t1 t2 !res |
|
|
in |
|
|
List.iter add d; |
|
|
List.map (!) !res |
|
|
|
|
|
(* |
|
|
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 |
|
|
|
|
|
(* Partitioning: |
|
|
|
|
|
(t,s) - ((t1,s1) | (t2,s2) | ... | (tn,sn)) |
|
|
= |
|
|
(t & t1, s - s1) | ... | (t & tn, s - sn) | (t - (t1|...|tn), s) |
|
|
|
|
|
*) |
|
|
|
|
|
let get_aux d = |
|
|
let accu = ref [] in |
|
|
let line (left,right) = |
|
|
let (d1,d2) = cap_product left in |
|
|
if (non_empty d1) && (non_empty d2) then |
|
|
let right = List.map (fun (t1,t2) -> descr t1, descr t2) right in |
|
|
let right = normal_aux right in |
|
|
let resid1 = ref d1 in |
|
|
let () = |
|
|
List.iter |
|
|
(fun (t1,t2) -> |
|
|
let t1 = cap d1 t1 in |
|
|
if (non_empty t1) then |
|
|
let () = resid1 := diff !resid1 t1 in |
|
|
let t2 = diff d2 t2 in |
|
|
if (non_empty t2) then accu := (t1,t2) :: !accu |
|
|
) right in |
|
|
if non_empty !resid1 then accu := (!resid1, d2) :: !accu |
|
|
in |
|
|
List.iter line d; |
|
|
!accu |
|
|
|
|
|
let get d = get_aux d.times |
|
|
|
|
|
let pi1 = List.fold_left (fun acc (t1,_) -> cup acc t1) empty |
|
|
let pi2 = List.fold_left (fun acc (_,t2) -> cup acc t2) empty |
|
|
|
|
|
let restrict_1 rects pi1 = |
|
|
let aux accu (t1,t2) = |
|
|
let t1 = cap t1 pi1 in if is_empty t1 then accu else (t1,t2)::accu in |
|
|
List.fold_left aux [] rects |
|
|
|
|
|
type normal = t |
|
|
|
|
|
module Memo = Map.Make(struct |
|
|
type t = (node * node) Boolean.t |
|
|
let compare = compare end) |
|
|
|
|
|
|
|
|
|
|
|
let memo = ref Memo.empty |
|
|
let normal d = |
|
|
let d = d.times in |
|
|
try Memo.find d !memo |
|
|
with |
|
|
Not_found -> |
|
|
let gd = get_aux d in |
|
|
let n = normal_aux gd in |
|
|
memo := Memo.add d n !memo; |
|
|
n |
|
|
|
|
|
let any = { empty with times = any.times } |
|
|
let is_empty d = d = [] |
|
|
end |
|
|
|
|
| 746 |
|
|
| 747 |
module Record = |
module Record = |
| 748 |
struct |
struct |
| 916 |
(fun (d1,d2) -> [(rec_normalize d1, rec_normalize d2)],[]) |
(fun (d1,d2) -> [(rec_normalize d1, rec_normalize d2)],[]) |
| 917 |
(Product.normal d) |
(Product.normal d) |
| 918 |
in |
in |
| 919 |
|
let xml = |
| 920 |
|
map_sort |
| 921 |
|
(fun (d1,d2) -> [(rec_normalize d1, rec_normalize d2)],[]) |
| 922 |
|
(Product.normal ~kind:`XML d) |
| 923 |
|
in |
| 924 |
let record = |
let record = |
| 925 |
map_sort |
map_sort |
| 926 |
(fun f -> map_sort (fun (l,(o,d)) -> (l,o,rec_normalize d)) f, []) |
(fun f -> map_sort (fun (l,(o,d)) -> (l,o,rec_normalize d)) f, []) |
| 927 |
(Record.get d) |
(Record.get d) |
| 928 |
in |
in |
| 929 |
define n { d with times = times; record = record }; |
define n { d with times = times; xml = xml; record = record }; |
| 930 |
n |
n |
| 931 |
|
|
| 932 |
let normalize n = |
let normalize n = |