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