Parent Directory
|
Revision Log
[r2004-12-27 16:03:23 by afrisch] Cleanup Original author: afrisch Date: 2004-12-27 16:03:23+00:00
| 1 | exception Error of string |
| 2 | open Ident |
| 3 | |
| 4 | let print_lab ppf l = |
| 5 | if (l == LabelPool.dummy_max) |
| 6 | then Format.fprintf ppf "<dummy_max>" |
| 7 | else Label.print ppf (LabelPool.value l) |
| 8 | |
| 9 | (* |
| 10 | To be sure not to use generic comparison ... |
| 11 | *) |
| 12 | let (=) : int -> int -> bool = (==) |
| 13 | let (<) : int -> int -> bool = (<) |
| 14 | let (<=) : int -> int -> bool = (<=) |
| 15 | let (<>) : int -> int -> bool = (<>) |
| 16 | let compare = 1 |
| 17 | |
| 18 | |
| 19 | (* Syntactic algebra *) |
| 20 | (* Constraint: any node except Constr has fv<>[] ... *) |
| 21 | type d = |
| 22 | | Constr of Types.t |
| 23 | | Cup of descr * descr |
| 24 | | Cap of descr * descr |
| 25 | | Times of node * node |
| 26 | | Xml of node * node |
| 27 | | Record of label * node |
| 28 | | Capture of id |
| 29 | | Constant of id * Types.const |
| 30 | | Dummy |
| 31 | and node = { |
| 32 | id : int; |
| 33 | mutable descr : descr; |
| 34 | accept : Types.Node.t; |
| 35 | fv : fv |
| 36 | } and descr = Types.t * fv * d |
| 37 | |
| 38 | |
| 39 | |
| 40 | let id x = x.id |
| 41 | let descr x = x.descr |
| 42 | let fv x = x.fv |
| 43 | let accept x = Types.internalize x.accept |
| 44 | |
| 45 | let printed = ref [] |
| 46 | let to_print = ref [] |
| 47 | let rec print ppf (a,_,d) = |
| 48 | match d with |
| 49 | | Constr t -> Types.Print.print ppf t |
| 50 | | Cup (p1,p2) -> Format.fprintf ppf "(%a | %a)" print p1 print p2 |
| 51 | | Cap (p1,p2) -> Format.fprintf ppf "(%a & %a)" print p1 print p2 |
| 52 | | Times (n1,n2) -> |
| 53 | Format.fprintf ppf "(P%i,P%i)" n1.id n2.id; |
| 54 | to_print := n1 :: n2 :: !to_print |
| 55 | | Xml (n1,n2) -> |
| 56 | Format.fprintf ppf "XML(P%i,P%i)" n1.id n2.id; |
| 57 | to_print := n1 :: n2 :: !to_print |
| 58 | | Record (l,n) -> |
| 59 | Format.fprintf ppf "{ %a = P%i }" Label.print (LabelPool.value l) n.id; |
| 60 | to_print := n :: !to_print |
| 61 | | Capture x -> |
| 62 | Format.fprintf ppf "%a" U.print (Id.value x) |
| 63 | | Constant (x,c) -> |
| 64 | Format.fprintf ppf "(%a := %a)" U.print (Id.value x) |
| 65 | Types.Print.print_const c |
| 66 | | Dummy -> |
| 67 | Format.fprintf ppf "*DUMMY*" |
| 68 | |
| 69 | let dump_print ppf = |
| 70 | while !to_print != [] do |
| 71 | let p = List.hd !to_print in |
| 72 | to_print := List.tl !to_print; |
| 73 | if not (List.mem p.id !printed) then |
| 74 | ( printed := p.id :: !printed; |
| 75 | Format.fprintf ppf "P%i:=%a\n" p.id print (descr p) |
| 76 | ) |
| 77 | done |
| 78 | |
| 79 | let print ppf d = |
| 80 | Format.fprintf ppf "%a@\n" print d; |
| 81 | dump_print ppf |
| 82 | |
| 83 | let print_node ppf n = |
| 84 | Format.fprintf ppf "P%i" n.id; |
| 85 | to_print := n :: !to_print; |
| 86 | dump_print ppf |
| 87 | |
| 88 | |
| 89 | let counter = State.ref "Patterns.counter" 0 |
| 90 | |
| 91 | let dummy = (Types.empty,IdSet.empty,Dummy) |
| 92 | let make fv = |
| 93 | incr counter; |
| 94 | { id = !counter; descr = dummy; accept = Types.make (); fv = fv } |
| 95 | |
| 96 | let define x ((accept,fv,_) as d) = |
| 97 | (* assert (x.fv = fv); *) |
| 98 | Types.define x.accept accept; |
| 99 | x.descr <- d |
| 100 | |
| 101 | let cons fv d = |
| 102 | let q = make fv in |
| 103 | define q d; |
| 104 | q |
| 105 | |
| 106 | let constr x = (x,IdSet.empty,Constr x) |
| 107 | let cup ((acc1,fv1,_) as x1) ((acc2,fv2,_) as x2) = |
| 108 | if not (IdSet.equal fv1 fv2) then ( |
| 109 | let x = match IdSet.pick (IdSet.diff fv1 fv2) with |
| 110 | | Some x -> x |
| 111 | | None -> match IdSet.pick (IdSet.diff fv2 fv1) with Some x -> x |
| 112 | | None -> assert false |
| 113 | in |
| 114 | raise |
| 115 | (Error |
| 116 | ("The capture variable " ^ (U.to_string (Id.value x)) ^ |
| 117 | " should appear on both side of this | pattern")) |
| 118 | ); |
| 119 | (Types.cup acc1 acc2, IdSet.cup fv1 fv2, Cup (x1,x2)) |
| 120 | let cap ((acc1,fv1,_) as x1) ((acc2,fv2,_) as x2) = |
| 121 | if not (IdSet.disjoint fv1 fv2) then ( |
| 122 | match IdSet.pick (IdSet.cap fv1 fv2) with |
| 123 | | Some x -> |
| 124 | raise |
| 125 | (Error |
| 126 | ("The capture variable " ^ (U.to_string (Id.value x)) ^ |
| 127 | " cannot appear on both side of this & pattern")) |
| 128 | | None -> assert false |
| 129 | ); |
| 130 | (Types.cap acc1 acc2, IdSet.cup fv1 fv2, Cap (x1,x2)) |
| 131 | let times x y = |
| 132 | (Types.times x.accept y.accept, IdSet.cup x.fv y.fv, Times (x,y)) |
| 133 | let xml x y = |
| 134 | (Types.xml x.accept y.accept, IdSet.cup x.fv y.fv, Xml (x,y)) |
| 135 | let record l x = |
| 136 | (Types.record l x.accept, x.fv, Record (l,x)) |
| 137 | let capture x = (Types.any, IdSet.singleton x, Capture x) |
| 138 | let constant x c = (Types.any, IdSet.singleton x, Constant (x,c)) |
| 139 | |
| 140 | |
| 141 | module Node = struct |
| 142 | type t = node |
| 143 | let compare n1 n2 = n1.id - n2.id |
| 144 | let equal n1 n2 = n1.id == n2.id |
| 145 | let hash n = n.id |
| 146 | |
| 147 | let check n = () |
| 148 | let dump = print_node |
| 149 | |
| 150 | |
| 151 | module SMemo = Set.Make(Custom.Int) |
| 152 | let memo = Serialize.Put.mk_property (fun t -> ref SMemo.empty) |
| 153 | let rec serialize t n = |
| 154 | let l = Serialize.Put.get_property memo t in |
| 155 | Serialize.Put.int t n.id; |
| 156 | if not (SMemo.mem n.id !l) then ( |
| 157 | l := SMemo.add n.id !l; |
| 158 | Types.Node.serialize t n.accept; |
| 159 | IdSet.serialize t n.fv; |
| 160 | serialize_descr t n.descr |
| 161 | ) |
| 162 | and serialize_descr s (_,_,d) = |
| 163 | serialize_d s d |
| 164 | and serialize_d s = function |
| 165 | | Constr t -> |
| 166 | Serialize.Put.bits 3 s 0; |
| 167 | Types.serialize s t |
| 168 | | Cup (p1,p2) -> |
| 169 | Serialize.Put.bits 3 s 1; |
| 170 | serialize_descr s p1; |
| 171 | serialize_descr s p2 |
| 172 | | Cap (p1,p2) -> |
| 173 | Serialize.Put.bits 3 s 2; |
| 174 | serialize_descr s p1; |
| 175 | serialize_descr s p2 |
| 176 | | Times (p1,p2) -> |
| 177 | Serialize.Put.bits 3 s 3; |
| 178 | serialize s p1; |
| 179 | serialize s p2 |
| 180 | | Xml (p1,p2) -> |
| 181 | Serialize.Put.bits 3 s 4; |
| 182 | serialize s p1; |
| 183 | serialize s p2 |
| 184 | | Record (l,p) -> |
| 185 | Serialize.Put.bits 3 s 5; |
| 186 | LabelPool.serialize s l; |
| 187 | serialize s p |
| 188 | | Capture x -> |
| 189 | Serialize.Put.bits 3 s 6; |
| 190 | Id.serialize s x |
| 191 | | Constant (x,c) -> |
| 192 | Serialize.Put.bits 3 s 7; |
| 193 | Id.serialize s x; |
| 194 | Types.Const.serialize s c |
| 195 | | Dummy -> assert false |
| 196 | |
| 197 | module DMemo = Map.Make(Custom.Int) |
| 198 | let memo = Serialize.Get.mk_property (fun t -> ref DMemo.empty) |
| 199 | let rec deserialize t = |
| 200 | let l = Serialize.Get.get_property memo t in |
| 201 | let id = Serialize.Get.int t in |
| 202 | try DMemo.find id !l |
| 203 | with Not_found -> |
| 204 | let accept = Types.Node.deserialize t in |
| 205 | let fv = IdSet.deserialize t in |
| 206 | incr counter; |
| 207 | let n = { id = !counter; descr = dummy; accept = accept; fv = fv } in |
| 208 | l := DMemo.add id n !l; |
| 209 | n.descr <- deserialize_descr t; |
| 210 | n |
| 211 | and deserialize_descr s = |
| 212 | match Serialize.Get.bits 3 s with |
| 213 | | 0 -> constr (Types.deserialize s) |
| 214 | | 1 -> |
| 215 | (* Avoid unnecessary tests *) |
| 216 | let (acc1,fv1,_) as x1 = deserialize_descr s in |
| 217 | let (acc2,fv2,_) as x2 = deserialize_descr s in |
| 218 | (Types.cup acc1 acc2, IdSet.cup fv1 fv2, Cup (x1,x2)) |
| 219 | | 2 -> |
| 220 | let (acc1,fv1,_) as x1 = deserialize_descr s in |
| 221 | let (acc2,fv2,_) as x2 = deserialize_descr s in |
| 222 | (Types.cap acc1 acc2, IdSet.cup fv1 fv2, Cap (x1,x2)) |
| 223 | | 3 -> |
| 224 | let x = deserialize s in |
| 225 | let y = deserialize s in |
| 226 | times x y |
| 227 | | 4 -> |
| 228 | let x = deserialize s in |
| 229 | let y = deserialize s in |
| 230 | xml x y |
| 231 | | 5 -> |
| 232 | let l = LabelPool.deserialize s in |
| 233 | let x = deserialize s in |
| 234 | record l x |
| 235 | | 6 -> capture (Id.deserialize s) |
| 236 | | 7 -> |
| 237 | let x = Id.deserialize s in |
| 238 | let c = Types.Const.deserialize s in |
| 239 | constant x c |
| 240 | | _ -> assert false |
| 241 | |
| 242 | |
| 243 | end |
| 244 | |
| 245 | (* Pretty-print *) |
| 246 | |
| 247 | module Pat = struct |
| 248 | type t = descr |
| 249 | let rec compare (_,_,d1) (_,_,d2) = if d1 == d2 then 0 else |
| 250 | match (d1,d2) with |
| 251 | | Constr t1, Constr t2 -> Types.compare t1 t2 |
| 252 | | Constr _, _ -> -1 | _, Constr _ -> 1 |
| 253 | |
| 254 | | Cup (x1,y1), Cup (x2,y2) | Cap (x1,y1), Cap (x2,y2) -> |
| 255 | let c = compare x1 x2 in if c <> 0 then c |
| 256 | else compare y1 y2 |
| 257 | | Cup _, _ -> -1 | _, Cup _ -> 1 |
| 258 | | Cap _, _ -> -1 | _, Cap _ -> 1 |
| 259 | |
| 260 | | Times (x1,y1), Times (x2,y2) | Xml (x1,y1), Xml (x2,y2) -> |
| 261 | let c = Node.compare x1 x2 in if c <> 0 then c |
| 262 | else Node.compare y1 y2 |
| 263 | | Times _, _ -> -1 | _, Times _ -> 1 |
| 264 | | Xml _, _ -> -1 | _, Xml _ -> 1 |
| 265 | |
| 266 | | Record (x1,y1), Record (x2,y2) -> |
| 267 | let c = LabelPool.compare x1 x2 in if c <> 0 then c |
| 268 | else Node.compare y1 y2 |
| 269 | | Record _, _ -> -1 | _, Record _ -> 1 |
| 270 | |
| 271 | | Capture x1, Capture x2 -> |
| 272 | Id.compare x1 x2 |
| 273 | | Capture _, _ -> -1 | _, Capture _ -> 1 |
| 274 | |
| 275 | | Constant (x1,y1), Constant (x2,y2) -> |
| 276 | let c = Id.compare x1 x2 in if c <> 0 then c |
| 277 | else Types.Const.compare y1 y2 |
| 278 | | Constant _, _ -> -1 | _, Constant _ -> 1 |
| 279 | |
| 280 | | Dummy, Dummy -> assert false |
| 281 | |
| 282 | let equal p1 p2 = compare p1 p2 == 0 |
| 283 | |
| 284 | let rec hash (_,_,d) = match d with |
| 285 | | Constr t -> 1 + 17 * (Types.hash t) |
| 286 | | Cup (p1,p2) -> 2 + 17 * (hash p1) + 257 * (hash p2) |
| 287 | | Cap (p1,p2) -> 3 + 17 * (hash p1) + 257 * (hash p2) |
| 288 | | Times (q1,q2) -> 4 + 17 * q1.id + 257 * q2.id |
| 289 | | Xml (q1,q2) -> 5 + 17 * q1.id + 257 * q2.id |
| 290 | | Record (l,q) -> 6 + 17 * (LabelPool.hash l) + 257 * q.id |
| 291 | | Capture x -> 7 + (Id.hash x) |
| 292 | | Constant (x,c) -> 8 + 17 * (Id.hash x) + 257 * (Types.Const.hash c) |
| 293 | | Dummy -> assert false |
| 294 | end |
| 295 | |
| 296 | module Print = struct |
| 297 | module M = Map.Make(Pat) |
| 298 | module S = Set.Make(Pat) |
| 299 | |
| 300 | let names = ref M.empty |
| 301 | let printed = ref S.empty |
| 302 | let toprint = Queue.create () |
| 303 | let id = ref 0 |
| 304 | |
| 305 | let rec mark seen ((_,_,d) as p) = |
| 306 | if (M.mem p !names) then () |
| 307 | else if (S.mem p seen) then |
| 308 | (incr id; |
| 309 | names := M.add p !id !names; |
| 310 | Queue.add p toprint) |
| 311 | else |
| 312 | let seen = S.add p seen in |
| 313 | match d with |
| 314 | | Cup (p1,p2) | Cap (p1,p2) -> mark seen p1; mark seen p2 |
| 315 | | Times (q1,q2) | Xml (q1,q2) -> mark seen q1.descr; mark seen q2.descr |
| 316 | | Record (_,q) -> mark seen q.descr |
| 317 | | _ -> () |
| 318 | |
| 319 | let rec print ppf p = |
| 320 | try |
| 321 | let i = M.find p !names in |
| 322 | Format.fprintf ppf "P%i" i |
| 323 | with Not_found -> |
| 324 | real_print ppf p |
| 325 | and real_print ppf (_,_,d) = match d with |
| 326 | | Constr t -> |
| 327 | Types.Print.print ppf t |
| 328 | | Cup (p1,p2) -> |
| 329 | Format.fprintf ppf "(%a | %a)" print p1 print p2 |
| 330 | | Cap (p1,p2) -> |
| 331 | Format.fprintf ppf "(%a & %a)" print p1 print p2 |
| 332 | | Times (q1,q2) -> |
| 333 | Format.fprintf ppf "(%a,%a)" print q1.descr print q2.descr |
| 334 | | Xml (q1,{ descr = (_,_,Times(q2,q3)) }) -> |
| 335 | Format.fprintf ppf "<(%a) (%a)>(%a)" print q1.descr print q2.descr print q3.descr |
| 336 | | Xml _ -> assert false |
| 337 | | Record (l,q) -> |
| 338 | Format.fprintf ppf "{%a=%a}" Label.print (LabelPool.value l) print q.descr |
| 339 | | Capture x -> |
| 340 | Format.fprintf ppf "%a" Ident.print x |
| 341 | | Constant (x,c) -> |
| 342 | Format.fprintf ppf "(%a:=%a)" Ident.print x Types.Print.print_const c |
| 343 | | Dummy -> assert false |
| 344 | |
| 345 | let print ppf p = |
| 346 | mark S.empty p; |
| 347 | print ppf p; |
| 348 | let first = ref true in |
| 349 | (try while true do |
| 350 | let p = Queue.pop toprint in |
| 351 | if not (S.mem p !printed) then |
| 352 | ( printed := S.add p !printed; |
| 353 | Format.fprintf ppf " %s@ @[%a=%a@]" |
| 354 | (if !first then (first := false; "where") else "and") |
| 355 | print p |
| 356 | real_print p |
| 357 | ); |
| 358 | done with Queue.Empty -> ()); |
| 359 | id := 0; |
| 360 | names := M.empty; |
| 361 | printed := S.empty |
| 362 | |
| 363 | |
| 364 | let print_xs ppf xs = |
| 365 | Format.fprintf ppf "{"; |
| 366 | let rec aux = function |
| 367 | | [] -> () |
| 368 | | [x] -> Ident.print ppf x |
| 369 | | x::q -> Ident.print ppf x; Format.fprintf ppf ","; aux q |
| 370 | in |
| 371 | aux xs; |
| 372 | Format.fprintf ppf "}" |
| 373 | end |
| 374 | |
| 375 | |
| 376 | |
| 377 | (* Static semantics *) |
| 378 | |
| 379 | let cup_res v1 v2 = Types.Positive.cup [v1;v2] |
| 380 | let empty_res fv = IdMap.constant (Types.Positive.ty Types.empty) fv |
| 381 | let times_res v1 v2 = Types.Positive.times v1 v2 |
| 382 | |
| 383 | (* Try with a hash-table *) |
| 384 | module MemoFilter = Map.Make |
| 385 | (struct |
| 386 | type t = Types.t * node |
| 387 | let compare (t1,n1) (t2,n2) = |
| 388 | if n1.id < n2.id then -1 else if n1.id > n2.id then 1 else |
| 389 | Types.compare t1 t2 |
| 390 | end) |
| 391 | |
| 392 | let memo_filter = ref MemoFilter.empty |
| 393 | |
| 394 | let rec filter_descr t (_,fv,d) : Types.Positive.v id_map = |
| 395 | (* TODO: avoid is_empty t when t is not changing (Cap) *) |
| 396 | if Types.is_empty t |
| 397 | then empty_res fv |
| 398 | else |
| 399 | match d with |
| 400 | | Constr _ -> IdMap.empty |
| 401 | | Cup ((a,_,_) as d1,d2) -> |
| 402 | IdMap.merge cup_res |
| 403 | (filter_descr (Types.cap t a) d1) |
| 404 | (filter_descr (Types.diff t a) d2) |
| 405 | | Cap (d1,d2) -> |
| 406 | IdMap.merge cup_res (filter_descr t d1) (filter_descr t d2) |
| 407 | | Times (p1,p2) -> filter_prod fv p1 p2 t |
| 408 | | Xml (p1,p2) -> filter_prod ~kind:`XML fv p1 p2 t |
| 409 | | Record (l,p) -> |
| 410 | filter_node (Types.Record.project t l) p |
| 411 | | Capture c -> |
| 412 | IdMap.singleton c (Types.Positive.ty t) |
| 413 | | Constant (c, cst) -> |
| 414 | IdMap.singleton c (Types.Positive.ty (Types.constant cst)) |
| 415 | | Dummy -> assert false |
| 416 | |
| 417 | and filter_prod ?kind fv p1 p2 t = |
| 418 | List.fold_left |
| 419 | (fun accu (d1,d2) -> |
| 420 | let term = |
| 421 | IdMap.merge times_res (filter_node d1 p1) (filter_node d2 p2) |
| 422 | in |
| 423 | IdMap.merge cup_res accu term |
| 424 | ) |
| 425 | (empty_res fv) |
| 426 | (Types.Product.normal ?kind t) |
| 427 | |
| 428 | |
| 429 | and filter_node t p : Types.Positive.v id_map = |
| 430 | try MemoFilter.find (t,p) !memo_filter |
| 431 | with Not_found -> |
| 432 | let (_,fv,_) as d = descr p in |
| 433 | let res = IdMap.map_from_slist (fun _ -> Types.Positive.forward ()) fv in |
| 434 | memo_filter := MemoFilter.add (t,p) res !memo_filter; |
| 435 | let r = filter_descr t (descr p) in |
| 436 | IdMap.collide Types.Positive.define res r; |
| 437 | r |
| 438 | |
| 439 | let filter t p = |
| 440 | let r = filter_node t p in |
| 441 | memo_filter := MemoFilter.empty; |
| 442 | IdMap.get (IdMap.map Types.Positive.solve r) |
| 443 | |
| 444 | let filter_descr t p = |
| 445 | let r = filter_descr t p in |
| 446 | memo_filter := MemoFilter.empty; |
| 447 | IdMap.get (IdMap.map Types.Positive.solve r) |
| 448 | |
| 449 | |
| 450 | (* Normal forms for patterns and compilation *) |
| 451 | |
| 452 | let min (a:int) (b:int) = if a < b then a else b |
| 453 | |
| 454 | let any_basic = Types.Record.or_absent Types.non_constructed |
| 455 | |
| 456 | let rec first_label (acc,fv,d) = |
| 457 | if Types.is_empty acc |
| 458 | then LabelPool.dummy_max |
| 459 | else match d with |
| 460 | | Constr t -> Types.Record.first_label t |
| 461 | | Cap (p,q) -> min (first_label p) (first_label q) |
| 462 | | Cup ((acc1,_,_) as p,q) -> min (first_label p) (first_label q) |
| 463 | | Record (l,p) -> l |
| 464 | | _ -> LabelPool.dummy_max |
| 465 | |
| 466 | module Normal = struct |
| 467 | |
| 468 | type source = |
| 469 | | SCatch | SConst of Types.const |
| 470 | | SLeft | SRight | SRecompose |
| 471 | type result = source id_map |
| 472 | |
| 473 | let compare_source s1 s2 = |
| 474 | if s1 == s2 then 0 |
| 475 | else match (s1,s2) with |
| 476 | | SCatch, _ -> -1 | _, SCatch -> 1 |
| 477 | | SLeft, _ -> -1 | _, SLeft -> 1 |
| 478 | | SRight, _ -> -1 | _, SRight -> 1 |
| 479 | | SRecompose, _ -> -1 | _, SRecompose -> 1 |
| 480 | | SConst c1, SConst c2 -> Types.Const.compare c1 c2 |
| 481 | |
| 482 | let hash_source = function |
| 483 | | SCatch -> 1 |
| 484 | | SLeft -> 2 |
| 485 | | SRight -> 3 |
| 486 | | SRecompose -> 4 |
| 487 | | SConst c -> Types.Const.hash c |
| 488 | |
| 489 | let compare_result r1 r2 = |
| 490 | IdMap.compare compare_source r1 r2 |
| 491 | |
| 492 | let hash_result r = |
| 493 | IdMap.hash hash_source r |
| 494 | |
| 495 | |
| 496 | let print_result ppf r = Format.fprintf ppf "<result>" |
| 497 | let print_result_option ppf = function |
| 498 | | Some x -> Format.fprintf ppf "Some(%a)" print_result x |
| 499 | | None -> Format.fprintf ppf "None" |
| 500 | |
| 501 | module NodeSet = SortedList.Make(Node) |
| 502 | |
| 503 | module Nnf = struct |
| 504 | type t = NodeSet.t * Types.t * IdSet.t (* pl,t; t <= \accept{pl} *) |
| 505 | |
| 506 | let check (pl,t,xs) = |
| 507 | List.iter (fun p -> assert(Types.subtype t (Types.descr p.accept))) |
| 508 | (NodeSet.get pl) |
| 509 | let print ppf (pl,t,xs) = |
| 510 | Format.fprintf ppf "@[(pl=%a;t=%a)@]" NodeSet.dump pl Types.Print.print t |
| 511 | let compare (l1,t1,xs1) (l2,t2,xs2) = |
| 512 | let c = NodeSet.compare l1 l2 in if c <> 0 then c |
| 513 | else let c = Types.compare t1 t2 in if c <> 0 then c |
| 514 | else IdSet.compare xs1 xs2 |
| 515 | let hash (l,t,xs) = |
| 516 | (NodeSet.hash l) + 17 * (Types.hash t) + 257 * (IdSet.hash xs) |
| 517 | let equal x y = compare x y == 0 |
| 518 | |
| 519 | |
| 520 | let first_label (pl,t,xs) = |
| 521 | List.fold_left |
| 522 | (fun l p -> min l (first_label (descr p))) |
| 523 | (Types.Record.first_label t) |
| 524 | pl |
| 525 | end |
| 526 | |
| 527 | module NBasic = struct |
| 528 | include Custom.Dummy |
| 529 | let serialize s _ = failwith "Patterns.NLineBasic.serialize" |
| 530 | type t = result * Types.t |
| 531 | let compare (r1,t1) (r2,t2) = |
| 532 | let c = compare_result r1 r2 in if c <> 0 then c |
| 533 | else Types.compare t1 t2 |
| 534 | let equal x y = compare x y == 0 |
| 535 | let hash (r,t) = hash_result r + 17 * Types.hash t |
| 536 | end |
| 537 | |
| 538 | |
| 539 | module NProd = struct |
| 540 | type t = result * Nnf.t * Nnf.t |
| 541 | |
| 542 | let serialize s _ = failwith "Patterns.NLineProd.serialize" |
| 543 | let deserialize s = failwith "Patterns.NLineProd.deserialize" |
| 544 | let check x = () |
| 545 | let dump ppf (r,x,y) = |
| 546 | Format.fprintf ppf "@[(result=%a;x=%a;y=%a)@]" |
| 547 | print_result r Nnf.print x Nnf.print y |
| 548 | |
| 549 | let compare (r1,x1,y1) (r2,x2,y2) = |
| 550 | let c = compare_result r1 r2 in if c <> 0 then c |
| 551 | else let c = Nnf.compare x1 x2 in if c <> 0 then c |
| 552 | else Nnf.compare y1 y2 |
| 553 | let equal x y = compare x y == 0 |
| 554 | let hash (r,x,y) = hash_result r + 17 * (Nnf.hash x) + 267 * (Nnf.hash y) |
| 555 | end |
| 556 | |
| 557 | module NLineBasic = SortedList.Make(NBasic) |
| 558 | module NLineProd = SortedList.Make(NProd) |
| 559 | |
| 560 | type record = |
| 561 | | RecNolabel of result option * result option |
| 562 | | RecLabel of label * NLineProd.t |
| 563 | type t = { |
| 564 | nfv : fv; |
| 565 | na : Types.t; |
| 566 | nbasic : NLineBasic.t; |
| 567 | nprod : NLineProd.t; |
| 568 | nxml : NLineProd.t; |
| 569 | nrecord: record |
| 570 | } |
| 571 | |
| 572 | let print_record ppf = function |
| 573 | | RecLabel (lab,l) -> |
| 574 | Format.fprintf ppf "RecLabel(@[%a@],@ @[%a@])" |
| 575 | Label.print (LabelPool.value lab) |
| 576 | NLineProd.dump l |
| 577 | | RecNolabel (a,b) -> |
| 578 | Format.fprintf ppf "RecNolabel(@[%a@],@[%a@])" |
| 579 | print_result_option a |
| 580 | print_result_option b |
| 581 | let print ppf nf = |
| 582 | Format.fprintf ppf "@[NF{na=%a;@[nrecord=@ @[%a@]@]}@]" |
| 583 | Types.Print.print nf.na |
| 584 | print_record nf.nrecord |
| 585 | |
| 586 | |
| 587 | include Custom.Dummy |
| 588 | let compare_record t1 t2 = match t1,t2 with |
| 589 | | RecNolabel (s1,n1), RecNolabel (s2,n2) -> |
| 590 | (match (s1,s2,n1,n2) with |
| 591 | | Some r1, Some r2, _, _ -> compare_result r1 r2 |
| 592 | | None, Some _, _, _ -> -1 |
| 593 | | Some _, None, _, _ -> 1 |
| 594 | | None,None,Some r1, Some r2 -> compare_result r1 r2 |
| 595 | | None,None,None, Some _ -> -1 |
| 596 | | None,None, Some _, None -> 1 |
| 597 | | None,None, None, None -> 0) |
| 598 | | RecNolabel (_,_), _ -> -1 |
| 599 | | _, RecNolabel (_,_) -> 1 |
| 600 | | RecLabel (l1,p1), RecLabel (l2,p2) -> |
| 601 | let c = LabelPool.compare l1 l2 in if c <> 0 then c |
| 602 | else NLineProd.compare p1 p2 |
| 603 | let compare t1 t2 = |
| 604 | if t1 == t2 then 0 |
| 605 | else |
| 606 | (* TODO: reorder; remove comparison of nfv ? *) |
| 607 | let c = IdSet.compare t1.nfv t2.nfv in if c <> 0 then c |
| 608 | else let c = Types.compare t1.na t2.na in if c <> 0 then c |
| 609 | else let c = NLineBasic.compare t1.nbasic t2.nbasic in if c <> 0 then c |
| 610 | else let c = NLineProd.compare t1.nprod t2.nprod in if c <> 0 then c |
| 611 | else let c = NLineProd.compare t1.nxml t2.nxml in if c <> 0 then c |
| 612 | else compare_record t1.nrecord t2.nrecord |
| 613 | |
| 614 | let fus = IdMap.union_disj |
| 615 | |
| 616 | let nempty lab = |
| 617 | { nfv = IdSet.empty; |
| 618 | na = Types.empty; |
| 619 | nbasic = NLineBasic.empty; |
| 620 | nprod = NLineProd.empty; |
| 621 | nxml = NLineProd.empty; |
| 622 | nrecord = (match lab with |
| 623 | | Some l -> RecLabel (l,NLineProd.empty) |
| 624 | | None -> RecNolabel (None,None)) |
| 625 | } |
| 626 | let dummy = nempty None |
| 627 | |
| 628 | |
| 629 | let ncup nf1 nf2 = |
| 630 | (* assert (Types.is_empty (Types.cap nf1.na nf2.na)); *) |
| 631 | (* assert (nf1.nfv = nf2.nfv); *) |
| 632 | { nfv = nf1.nfv; |
| 633 | na = Types.cup nf1.na nf2.na; |
| 634 | nbasic = NLineBasic.cup nf1.nbasic nf2.nbasic; |
| 635 | nprod = NLineProd.cup nf1.nprod nf2.nprod; |
| 636 | nxml = NLineProd.cup nf1.nxml nf2.nxml; |
| 637 | nrecord = (match (nf1.nrecord,nf2.nrecord) with |
| 638 | | RecLabel (l1,r1), RecLabel (l2,r2) -> |
| 639 | (* assert (l1 = l2); *) RecLabel (l1, NLineProd.cup r1 r2) |
| 640 | | RecNolabel (x1,y1), RecNolabel (x2,y2) -> |
| 641 | RecNolabel((if x1 == None then x2 else x1), |
| 642 | (if y1 == None then y2 else y1)) |
| 643 | | _ -> assert false) |
| 644 | } |
| 645 | |
| 646 | let double_fold f l1 l2 = |
| 647 | List.fold_left |
| 648 | (fun accu x1 -> List.fold_left (fun accu x2 -> f accu x1 x2) accu l2) |
| 649 | [] l1 |
| 650 | |
| 651 | let double_fold_prod f l1 l2 = |
| 652 | double_fold f (NLineProd.get l1) (NLineProd.get l2) |
| 653 | |
| 654 | let ncap nf1 nf2 = |
| 655 | let prod accu (res1,(pl1,t1,xs1),(ql1,s1,ys1)) (res2,(pl2,t2,xs2),(ql2,s2,ys2)) = |
| 656 | let t = Types.cap t1 t2 in |
| 657 | if Types.is_empty t then accu else |
| 658 | let s = Types.cap s1 s2 in |
| 659 | if Types.is_empty s then accu else |
| 660 | (fus res1 res2, |
| 661 | (NodeSet.cup pl1 pl2, t, IdSet.cup xs1 xs2), |
| 662 | (NodeSet.cup ql1 ql2, s, IdSet.cup ys1 ys2)) |
| 663 | :: accu |
| 664 | in |
| 665 | let basic accu (res1,t1) (res2,t2) = |
| 666 | let t = Types.cap t1 t2 in |
| 667 | if Types.is_empty t then accu else |
| 668 | (fus res1 res2, t) :: accu |
| 669 | in |
| 670 | let record r1 r2 = match r1,r2 with |
| 671 | | RecLabel (l1,r1), RecLabel (l2,r2) -> |
| 672 | (* assert (l1 = l2); *) |
| 673 | RecLabel(l1, NLineProd.from_list (double_fold_prod prod r1 r2)) |
| 674 | | RecNolabel (x1,y1), RecNolabel (x2,y2) -> |
| 675 | let x = match x1,x2 with |
| 676 | | Some res1, Some res2 -> Some (fus res1 res2) |
| 677 | | _ -> None |
| 678 | and y = match y1,y2 with |
| 679 | | Some res1, Some res2 -> Some (fus res1 res2) |
| 680 | | _ -> None in |
| 681 | RecNolabel (x,y) |
| 682 | | _ -> assert false |
| 683 | in |
| 684 | { nfv = IdSet.cup nf1.nfv nf2.nfv; |
| 685 | na = Types.cap nf1.na nf2.na; |
| 686 | nbasic = NLineBasic.from_list (double_fold basic |
| 687 | (NLineBasic.get nf1.nbasic) |
| 688 | (NLineBasic.get nf2.nbasic)); |
| 689 | nprod = NLineProd.from_list (double_fold_prod prod nf1.nprod nf2.nprod); |
| 690 | nxml = NLineProd.from_list (double_fold_prod prod nf1.nxml nf2.nxml); |
| 691 | nrecord = record nf1.nrecord nf2.nrecord; |
| 692 | } |
| 693 | |
| 694 | let nnode p xs = NodeSet.singleton p, Types.descr p.accept, xs |
| 695 | let nc t = NodeSet.empty, t, IdSet.empty |
| 696 | let ncany = nc Types.any |
| 697 | let ncany_abs = nc Types.Record.any_or_absent |
| 698 | |
| 699 | let empty_res = IdMap.empty |
| 700 | |
| 701 | let single_basic src t = NLineBasic.singleton (src, t) |
| 702 | let single_prod src p q = NLineProd.singleton (src, p,q) |
| 703 | |
| 704 | let ntimes lab acc p q xs = |
| 705 | let xsp = IdSet.cap xs p.fv and xsq = IdSet.cap xs q.fv in |
| 706 | let src_p = IdMap.constant SLeft xsp |
| 707 | and src_q = IdMap.constant SRight xsq in |
| 708 | let src = IdMap.merge_elem SRecompose src_p src_q in |
| 709 | { nempty lab with |
| 710 | nfv = xs; |
| 711 | na = acc; |
| 712 | nprod = single_prod src (nnode p xsp) (nnode q xsq) |
| 713 | } |
| 714 | |
| 715 | let nxml lab acc p q xs = |
| 716 | let xsp = IdSet.cap xs p.fv and xsq = IdSet.cap xs q.fv in |
| 717 | let src_p = IdMap.constant SLeft xsp |
| 718 | and src_q = IdMap.constant SRight xsq in |
| 719 | let src = IdMap.merge_elem SRecompose src_p src_q in |
| 720 | { nempty lab with |
| 721 | nfv = xs; |
| 722 | na = acc; |
| 723 | nxml = single_prod src (nnode p xsp) (nnode q xsq) |
| 724 | } |
| 725 | |
| 726 | let nrecord lab acc l p xs = |
| 727 | assert (IdSet.equal xs (fv p)); |
| 728 | match lab with |
| 729 | | None -> assert false |
| 730 | | Some label -> |
| 731 | assert (label <= l); |
| 732 | let src,lft,rgt = |
| 733 | if l == label |
| 734 | then SLeft, nnode p xs, ncany |
| 735 | else SRight, ncany_abs, nnode (cons p.fv (record l p)) xs |
| 736 | in |
| 737 | let src = IdMap.constant src xs in |
| 738 | { nempty lab with |
| 739 | nfv = xs; |
| 740 | na = acc; |
| 741 | nrecord = RecLabel(label, single_prod src lft rgt) } |
| 742 | |
| 743 | let nconstr lab t = |
| 744 | let aux l = NLineProd.from_list |
| 745 | (List.map (fun (t1,t2) -> empty_res, nc t1,nc t2) l) in |
| 746 | let record = match lab with |
| 747 | | None -> |
| 748 | let (x,y) = Types.Record.empty_cases t in |
| 749 | RecNolabel ((if x then Some empty_res else None), |
| 750 | (if y then Some empty_res else None)) |
| 751 | | Some l -> |
| 752 | RecLabel (l,aux (Types.Record.split_normal t l)) in |
| 753 | { nempty lab with |
| 754 | na = t; |
| 755 | nbasic = single_basic empty_res (Types.cap t any_basic); |
| 756 | nprod = aux (Types.Product.normal t); |
| 757 | nxml = aux (Types.Product.normal ~kind:`XML t); |
| 758 | nrecord = record |
| 759 | } |
| 760 | |
| 761 | let nany lab res = |
| 762 | { nfv = IdMap.domain res; |
| 763 | na = Types.any; |
| 764 | nbasic = single_basic res any_basic; |
| 765 | nprod = single_prod res ncany ncany; |
| 766 | nxml = single_prod res ncany ncany; |
| 767 | nrecord = match lab with |
| 768 | | None -> RecNolabel (Some res, Some res) |
| 769 | | Some lab -> RecLabel (lab, single_prod res ncany_abs ncany) |
| 770 | } |
| 771 | |
| 772 | let nconstant lab x c = nany lab (IdMap.singleton x (SConst c)) |
| 773 | let ncapture lab x = nany lab (IdMap.singleton x SCatch) |
| 774 | |
| 775 | let rec nnormal lab ((acc,fv,d) as p) xs = |
| 776 | let xs = IdSet.cap xs fv in |
| 777 | if not (IdSet.equal xs fv) then |
| 778 | (Format.fprintf Format.std_formatter |
| 779 | "ERR: p=%a xs=%a fv=%a@." Print.print p Print.print_xs xs Print.print_xs fv; |
| 780 | exit 1); |
| 781 | if Types.is_empty acc then nempty lab |
| 782 | else if IdSet.is_empty xs then nconstr lab acc |
| 783 | else match d with |
| 784 | | Constr t -> assert false |
| 785 | | Cap (p,q) -> ncap (nnormal lab p xs) (nnormal lab q xs) |
| 786 | | Cup ((acc1,_,_) as p,q) -> |
| 787 | ncup |
| 788 | (nnormal lab p xs) |
| 789 | (ncap (nnormal lab q xs) (nconstr lab (Types.neg acc1))) |
| 790 | | Times (p,q) -> ntimes lab acc p q xs |
| 791 | | Xml (p,q) -> nxml lab acc p q xs |
| 792 | | Capture x -> ncapture lab x |
| 793 | | Constant (x,c) -> nconstant lab x c |
| 794 | | Record (l,p) -> nrecord lab acc l p xs |
| 795 | | Dummy -> assert false |
| 796 | |
| 797 | (*TODO: when an operand of Cap has its first_label > lab, |
| 798 | directly shift it*) |
| 799 | |
| 800 | |
| 801 | |
| 802 | let print_node_list ppf pl = |
| 803 | List.iter (fun p -> Format.fprintf ppf "%a;" Node.dump p) pl |
| 804 | |
| 805 | let normal l t pl xs = |
| 806 | List.fold_left |
| 807 | (fun a p -> ncap a (nnormal l (descr p) xs)) |
| 808 | (nconstr l t) |
| 809 | pl |
| 810 | |
| 811 | let nnf lab (pl,t,xs) = |
| 812 | let pl = NodeSet.get pl in |
| 813 | normal lab t pl xs |
| 814 | |
| 815 | |
| 816 | (* |
| 817 | let normal l t pl = |
| 818 | let nf = normal l t pl in |
| 819 | (match l with Some l -> |
| 820 | Format.fprintf Format.std_formatter |
| 821 | "normal(l=%a;t=%a;pl=%a)=%a@." |
| 822 | Label.print (LabelPool.value l) |
| 823 | Types.Print.print t |
| 824 | print_node_list pl |
| 825 | print nf |
| 826 | | None -> Format.fprintf Format.std_formatter |
| 827 | "normal(t=%a;pl=%a)=%a@." |
| 828 | Types.Print.print t |
| 829 | print_node_list pl |
| 830 | print nf); |
| 831 | nf |
| 832 | *) |
| 833 | end |
| 834 | |
| 835 | |
| 836 | module Compile = |
| 837 | struct |
| 838 | type actions = |
| 839 | | AIgnore of result |
| 840 | | AKind of actions_kind |
| 841 | and actions_kind = { |
| 842 | basic: (Types.t * result) list; |
| 843 | atoms: result Atoms.map; |
| 844 | chars: result Chars.map; |
| 845 | prod: result dispatch dispatch; |
| 846 | xml: result dispatch dispatch; |
| 847 | record: record option; |
| 848 | } |
| 849 | and record = |
| 850 | | RecLabel of label * result dispatch dispatch |
| 851 | | RecNolabel of result option * result option |
| 852 | |
| 853 | and 'a dispatch = |
| 854 | | Dispatch of dispatcher * 'a array |
| 855 | | TailCall of dispatcher |
| 856 | | Ignore of 'a |
| 857 | | Impossible |
| 858 | |
| 859 | and result = int * source array |
| 860 | and source = |
| 861 | | Catch | Const of Types.const |
| 862 | | Left of int | Right of int | Recompose of int * int |
| 863 | |
| 864 | and return_code = |
| 865 | Types.t * int * (* accepted type, arity *) |
| 866 | int id_map option array |
| 867 | |
| 868 | and interface = |
| 869 | [ `Result of int |
| 870 | | `Switch of interface * interface |
| 871 | | `None ] |
| 872 | |
| 873 | and dispatcher = { |
| 874 | id : int; |
| 875 | t : Types.t; |
| 876 | pl : Normal.t array; |
| 877 | label : label option; |
| 878 | interface : interface; |
| 879 | codes : return_code array; |
| 880 | mutable actions : actions option; |
| 881 | mutable printed : bool |
| 882 | } |
| 883 | |
| 884 | let equal_array f a1 a2 = |
| 885 | let rec aux i = (i < 0) || ((f a1.(i) a2.(i)) && (aux (i - 1))) in |
| 886 | let l1 = Array.length a1 and l2 = Array.length a2 in |
| 887 | (l1 == l2) && (aux (l1 - 1)) |
| 888 | |
| 889 | let array_for_all f a = |
| 890 | let rec aux f a i = (i < 0) || (f a.(i) && (aux f a (pred i))) in |
| 891 | aux f a (Array.length a - 1) |
| 892 | |
| 893 | let array_for_all_i f a = |
| 894 | let rec aux f a i = (i < 0) || (f i a.(i) && (aux f a (pred i))) in |
| 895 | aux f a (Array.length a - 1) |
| 896 | |
| 897 | let equal_source s1 s2 = |
| 898 | (s1 == s2) || match (s1,s2) with |
| 899 | | Const x, Const y -> Types.Const.equal x y |
| 900 | | Left x, Left y -> x == y |
| 901 | | Right x, Right y -> x == y |
| 902 | | Recompose (x1,x2), Recompose (y1,y2) -> (x1 == y1) && (x2 == y2) |
| 903 | | _ -> false |
| 904 | |
| 905 | let equal_result (r1,s1) (r2,s2) = |
| 906 | (r1 == r2) && (equal_array equal_source s1 s2) |
| 907 | |
| 908 | let equal_result_dispatch d1 d2 = (d1 == d2) || match (d1,d2) with |
| 909 | | Dispatch (d1,a1), Dispatch (d2,a2) -> |
| 910 | (d1 == d2) && (equal_array equal_result a1 a2) |
| 911 | | TailCall d1, TailCall d2 -> d1 == d2 |
| 912 | | Ignore a1, Ignore a2 -> equal_result a1 a2 |
| 913 | | _ -> false |
| 914 | |
| 915 | let immediate_res basic prod xml record = |
| 916 | let res = ref None in |
| 917 | let chk = function Catch | Const _ -> true | _ -> false in |
| 918 | let f ((_,ret) as r) = |
| 919 | match !res with |
| 920 | | Some r0 when equal_result r r0 -> () |
| 921 | | None when array_for_all chk ret -> res := Some r |
| 922 | | _ -> raise Exit in |
| 923 | (match basic with [_,r] -> f r | [] -> () | _ -> raise Exit); |
| 924 | (match prod with Ignore (Ignore r) -> f r |Impossible ->()| _->raise Exit); |
| 925 | (match xml with Ignore (Ignore r) -> f r |Impossible ->()| _->raise Exit); |
| 926 | (match record with |
| 927 | | None -> () |
| 928 | | Some (RecLabel (_,Ignore (Ignore r))) -> f r |
| 929 | | Some (RecNolabel (Some r1, Some r2)) -> f r1; f r2 |
| 930 | | _ -> raise Exit); |
| 931 | match !res with Some r -> r | None -> raise Exit |
| 932 | |
| 933 | let split_kind basic prod xml record = { |
| 934 | basic = basic; |
| 935 | atoms = Atoms.mk_map (List.map (fun (t,r) -> Types.Atom.get t, r) basic); |
| 936 | chars = Chars.mk_map (List.map (fun (t,r) -> Types.Char.get t, r) basic); |
| 937 | prod = prod; |
| 938 | xml = xml; |
| 939 | record = record |
| 940 | } |
| 941 | |
| 942 | let combine_kind basic prod xml record = |
| 943 | try AIgnore (immediate_res basic prod xml record) |
| 944 | with Exit -> AKind (split_kind basic prod xml record) |
| 945 | |
| 946 | let combine f (disp,act) = |
| 947 | if Array.length act == 0 then Impossible |
| 948 | else |
| 949 | if (array_for_all (fun (_,ar,_) -> ar == 0) disp.codes) |
| 950 | && (array_for_all ( f act.(0) ) act) then |
| 951 | Ignore act.(0) |
| 952 | else |
| 953 | Dispatch (disp, act) |
| 954 | |
| 955 | let detect_tail_call f = function |
| 956 | | Dispatch (disp,branches) when array_for_all_i f branches -> TailCall disp |
| 957 | | x -> x |
| 958 | |
| 959 | let detect_right_tail_call = |
| 960 | detect_tail_call |
| 961 | (fun i (code,ret) -> |
| 962 | (i == code) && |
| 963 | (array_for_all_i |
| 964 | (fun pos -> |
| 965 | function Right j when pos == j -> true | _ -> false) |
| 966 | ret |
| 967 | ) |
| 968 | ) |
| 969 | |
| 970 | let detect_left_tail_call = |
| 971 | detect_tail_call |
| 972 | (fun i -> |
| 973 | function |
| 974 | | Ignore (code,ret) when (i == code) -> |
| 975 | array_for_all_i |
| 976 | (fun pos -> |
| 977 | function Left j when pos == j -> true | _ -> false) |
| 978 | ret |
| 979 | | _ -> false |
| 980 | ) |
| 981 | |
| 982 | let cur_id = State.ref "Patterns.cur_id" 0 |
| 983 | (* TODO: save dispatchers ? *) |
| 984 | |
| 985 | module NfMap = Map.Make(Normal) |
| 986 | module NfSet = Set.Make(Normal) |
| 987 | |
| 988 | module DispMap = Map.Make(Custom.Pair(Types)(Custom.Array(Normal))) |
| 989 | |
| 990 | (* Try with a hash-table ! *) |
| 991 | |
| 992 | let dispatchers = ref DispMap.empty |
| 993 | |
| 994 | let timer_disp = Stats.Timer.create "Patterns.dispatcher loop" |
| 995 | |
| 996 | let rec print_iface ppf = function |
| 997 | | `Result i -> Format.fprintf ppf "Result(%i)" i |
| 998 | | `Switch (yes,no) -> Format.fprintf ppf "Switch(%a,%a)" |
| 999 | print_iface yes print_iface no |
| 1000 | | `None -> Format.fprintf ppf "None" |
| 1001 | |
| 1002 | let dispatcher t pl lab : dispatcher = |
| 1003 | try DispMap.find (t,pl) !dispatchers |
| 1004 | with Not_found -> |
| 1005 | let nb = ref 0 in |
| 1006 | let codes = ref [] in |
| 1007 | let rec aux t arity i accu = |
| 1008 | if i == Array.length pl |
| 1009 | then (incr nb; let r = Array.of_list (List.rev accu) in |
| 1010 | codes := (t,arity,r)::!codes; `Result (!nb - 1)) |
| 1011 | else |
| 1012 | let p = pl.(i) in |
| 1013 | let tp = p.Normal.na in |
| 1014 | |
| 1015 | let a1 = Types.cap t tp in |
| 1016 | if Types.is_empty a1 then |
| 1017 | `Switch (`None,aux t arity (i+1) (None::accu)) |
| 1018 | else |
| 1019 | let v = p.Normal.nfv in |
| 1020 | let a2 = Types.diff t tp in |
| 1021 | let accu' = Some (IdMap.num arity v) :: accu in |
| 1022 | if Types.is_empty a2 then |
| 1023 | `Switch (aux t (arity + (IdSet.length v)) (i+1) accu',`None) |
| 1024 | else |
| 1025 | `Switch (aux a1 (arity + (IdSet.length v)) (i+1) accu', |
| 1026 | aux a2 arity (i+1) (None::accu)) |
| 1027 | |
| 1028 | (* Unopt version: |
| 1029 | `Switch |
| 1030 | ( |
| 1031 | aux (Types.cap t tp) (arity + (IdSet.length v)) (i+1) accu', |
| 1032 | aux (Types.diff t tp) arity (i+1) accu |
| 1033 | ) |
| 1034 | *) |
| 1035 | |
| 1036 | in |
| 1037 | Stats.Timer.start timer_disp; |
| 1038 | let iface = if Types.is_empty t then `None else aux t 0 0 [] in |
| 1039 | Stats.Timer.stop timer_disp (); |
| 1040 | let res = { |
| 1041 | id = !cur_id; |
| 1042 | t = t; |
| 1043 | label = lab; |
| 1044 | pl = pl; |
| 1045 | interface = iface; |
| 1046 | codes = Array.of_list (List.rev !codes); |
| 1047 | actions = None; printed = false |
| 1048 | } in |
| 1049 | incr cur_id; |
| 1050 | dispatchers := DispMap.add (t,pl) res !dispatchers; |
| 1051 | res |
| 1052 | |
| 1053 | let find_code d a = |
| 1054 | let rec aux i = function |
| 1055 | | `Result code -> code |
| 1056 | | `None -> assert false |
| 1057 | | `Switch (yes,_) when a.(i) != None -> aux (i + 1) yes |
| 1058 | | `Switch (_,no) -> aux (i + 1) no in |
| 1059 | aux 0 d.interface |
| 1060 | |
| 1061 | let create_result pl = |
| 1062 | let aux x accu = match x with Some b -> b @ accu | None -> accu in |
| 1063 | Array.of_list (Array.fold_right aux pl []) |
| 1064 | |
| 1065 | let return disp pl f = |
| 1066 | let aux = function [x] -> Some (f x) | [] -> None | _ -> assert false in |
| 1067 | let final = Array.map aux pl in |
| 1068 | (find_code disp final, create_result final) |
| 1069 | |
| 1070 | let conv_source_basic s = match s with |
| 1071 | | Normal.SCatch -> Catch |
| 1072 | | Normal.SConst c -> Const c |
| 1073 | | _ -> assert false |
| 1074 | |
| 1075 | let return_basic disp selected = |
| 1076 | let aux_final res = IdMap.map_to_list conv_source_basic res in |
| 1077 | return disp selected aux_final |
| 1078 | |
| 1079 | let assoc v l = |
| 1080 | try IdMap.assoc v l with Not_found -> -1 |
| 1081 | |
| 1082 | let conv_source_prod left right v s = match s with |
| 1083 | | Normal.SCatch -> Catch |
| 1084 | | Normal.SConst c -> Const c |
| 1085 | | Normal.SLeft -> Left (assoc v left) |
| 1086 | | Normal.SRight -> Right (assoc v right) |
| 1087 | | Normal.SRecompose -> Recompose (assoc v left, assoc v right) |
| 1088 | |
| 1089 | module TypeList = SortedList.Make(Types) |
| 1090 | let dispatch_basic disp : (Types.t * result) list = |
| 1091 | (* TODO: try other algo, using disp.codes .... *) |
| 1092 | let pl = Array.map (fun p -> p.Normal.nbasic) disp.pl in |
| 1093 | let tests = |
| 1094 | let accu = ref [] in |
| 1095 | let aux i (res,x) = accu := (x, [i,res]) :: !accu in |
| 1096 | Array.iteri (fun i -> Normal.NLineBasic.iter (aux i)) pl; |
| 1097 | TypeList.Map.get (TypeList.Map.from_list (@) !accu) in |
| 1098 | |
| 1099 | let t = Types.cap any_basic disp.t in |
| 1100 | let accu = ref [] in |
| 1101 | let rec aux (success : (int * Normal.result) list) t l = |
| 1102 | if Types.non_empty t |
| 1103 | then match l with |
| 1104 | | [] -> |
| 1105 | let selected = Array.create (Array.length pl) [] in |
| 1106 | let add (i,res) = selected.(i) <- res :: selected.(i) in |
| 1107 | List.iter add success; |
| 1108 | accu := (t, return_basic disp selected) :: !accu |
| 1109 | | (ty,i) :: rem -> |
| 1110 | aux (i @ success) (Types.cap t ty) rem; |
| 1111 | aux success (Types.diff t ty) rem |
| 1112 | in |
| 1113 | aux [] t tests; |
| 1114 | !accu |
| 1115 | |
| 1116 | |
| 1117 | let first_lab pl = |
| 1118 | let aux l (req,_) = min l (Normal.Nnf.first_label req) in |
| 1119 | let lab = Array.fold_left (List.fold_left aux) LabelPool.dummy_max pl in |
| 1120 | if lab == LabelPool.dummy_max then None else Some lab |
| 1121 | |
| 1122 | |
| 1123 | let get_tests pl f t d post = |
| 1124 | let pl = Array.map (List.map f) pl in |
| 1125 | let lab = first_lab pl in |
| 1126 | let pl = Array.map (List.map (fun (x,info) -> (Normal.nnf lab x,info))) pl |
| 1127 | in |
| 1128 | (* Collect all subrequests *) |
| 1129 | let aux reqs (req,_) = NfSet.add req reqs in |
| 1130 | let reqs = Array.fold_left (List.fold_left aux) NfSet.empty pl in |
| 1131 | let reqs = Array.of_list (NfSet.elements reqs) in |
| 1132 | (* Map subrequest -> idx in reqs *) |
| 1133 | let idx = ref NfMap.empty in |
| 1134 | Array.iteri (fun i req -> idx := NfMap.add req i !idx) reqs; |
| 1135 | let idx = !idx in |
| 1136 | |
| 1137 | (* Build dispatcher *) |
| 1138 | let disp = dispatcher t reqs lab in |
| 1139 | |
| 1140 | (* Build continuation *) |
| 1141 | let result (t,_,m) = |
| 1142 | let get a (req,info) = |
| 1143 | match m.(NfMap.find req idx) with Some res -> (res,info)::a | _ -> a in |
| 1144 | let pl = Array.map (List.fold_left get []) pl in |
| 1145 | d t pl |
| 1146 | in |
| 1147 | let res = Array.map result disp.codes in |
| 1148 | post (disp,res) |
| 1149 | |
| 1150 | |
| 1151 | type 'a rhs = Match of (id * int) list * 'a | Fail |
| 1152 | let make_branches t brs = |
| 1153 | let t0 = ref t in |
| 1154 | let aux (p,e) = |
| 1155 | let xs = fv p in |
| 1156 | let nnf = (Normal.NodeSet.singleton p, !t0, xs) in |
| 1157 | t0 := Types.diff !t0 (Types.descr (accept p)); |
| 1158 | [(nnf, (xs, e))] in |
| 1159 | let res _ pl = |
| 1160 | let aux r = function |
| 1161 | | [(res, (xs,e))] -> assert (r == Fail); |
| 1162 | let m = List.map (fun x -> (x,IdMap.assoc x res)) xs in |
| 1163 | Match (m,e) |
| 1164 | | [] -> r | _ -> assert false in |
| 1165 | Array.fold_left aux Fail pl in |
| 1166 | let pl = Array.map aux (Array.of_list brs) in |
| 1167 | get_tests pl (fun x -> x) t res (fun x -> x) |
| 1168 | |
| 1169 | |
| 1170 | let rec dispatch_prod ?(kind=`Normal) disp = |
| 1171 | let extr = match kind with |
| 1172 | | `Normal -> fun p -> Normal.NLineProd.get p.Normal.nprod |
| 1173 | | `XML -> fun p -> Normal.NLineProd.get p.Normal.nxml in |
| 1174 | let t = Types.Product.get ~kind disp.t in |
| 1175 | dispatch_prod0 disp t (Array.map extr disp.pl) |
| 1176 | and dispatch_prod0 disp t pl = |
| 1177 | get_tests pl |
| 1178 | (fun (res,p,q) -> p, (res,q)) |
| 1179 | (Types.Product.pi1 t) |
| 1180 | (dispatch_prod1 disp t) |
| 1181 | (fun x -> detect_left_tail_call (combine equal_result_dispatch x)) |
| 1182 | and dispatch_prod1 disp t t1 pl = |
| 1183 | get_tests pl |
| 1184 | (fun (ret1, (res,q)) -> q, (ret1,res) ) |
| 1185 | (Types.Product.pi2_restricted t1 t) |
| 1186 | (dispatch_prod2 disp) |
| 1187 | (fun x -> detect_right_tail_call (combine equal_result x)) |
| 1188 | and dispatch_prod2 disp t2 pl = |
| 1189 | let aux_final (ret2, (ret1, res)) = |
| 1190 | IdMap.mapi_to_list (conv_source_prod ret1 ret2) res in |
| 1191 | return disp pl aux_final |
| 1192 | |
| 1193 | |
| 1194 | let dispatch_record disp : record option = |
| 1195 | let t = disp.t in |
| 1196 | if not (Types.Record.has_record t) then None |
| 1197 | else |
| 1198 | match disp.label with |
| 1199 | | None -> |
| 1200 | let (some,none) = Types.Record.empty_cases t in |
| 1201 | let some = aux some |
| 1202 | if some then |
| 1203 | let pl = Array.map (fun p -> match p.Normal.nrecord with |
| 1204 | | Normal.RecNolabel (Some x,_) -> [x] |
| 1205 | | Normal.RecNolabel (None,_) -> [] |
| 1206 | | _ -> assert false) disp.pl in |
| 1207 | Some (return disp pl (IdMap.map_to_list conv_source_basic)) |
| 1208 | else None |
| 1209 | in |
| 1210 | let none = |
| 1211 | if none then |
| 1212 | let pl = Array.map (fun p -> match p.Normal.nrecord with |
| 1213 | | Normal.RecNolabel (_,Some x) -> [x] |
| 1214 | | Normal.RecNolabel (_,None) -> [] |
| 1215 | | _ -> assert false) disp.pl in |
| 1216 | Some (return disp pl (IdMap.map_to_list conv_source_basic)) |
| 1217 | else None |
| 1218 | in |
| 1219 | Some (RecNolabel (some,none)) |
| 1220 | | Some lab -> |
| 1221 | let t = Types.Record.split t lab in |
| 1222 | let pl = Array.map (fun p -> match p.Normal.nrecord with |
| 1223 | | Normal.RecLabel (_,l) -> |
| 1224 | Normal.NLineProd.get l |
| 1225 | | _ -> assert false) disp.pl in |
| 1226 | Some (RecLabel (lab,dispatch_prod0 disp t pl)) |
| 1227 | |
| 1228 | let actions disp = |
| 1229 | match disp.actions with |
| 1230 | | Some a -> a |
| 1231 | | None -> |
| 1232 | let a = combine_kind |
| 1233 | (dispatch_basic disp) |
| 1234 | (dispatch_prod disp) |
| 1235 | (dispatch_prod ~kind:`XML disp) |
| 1236 | (dispatch_record disp) |
| 1237 | in |
| 1238 | disp.actions <- Some a; |
| 1239 | a |
| 1240 | |
| 1241 | let to_print = ref [] |
| 1242 | |
| 1243 | module DSET = Set.Make (struct type t = int let compare (x:t) (y:t) = x - y end) |
| 1244 | let printed = ref DSET.empty |
| 1245 | |
| 1246 | let queue d = |
| 1247 | if not d.printed then ( |
| 1248 | d.printed <- true; |
| 1249 | to_print := d :: !to_print |
| 1250 | ) |
| 1251 | |
| 1252 | let rec print_source ppf = function |
| 1253 | | Catch -> Format.fprintf ppf "v" |
| 1254 | | Const c -> Types.Print.print_const ppf c |
| 1255 | | Left (-1) -> Format.fprintf ppf "v1" |
| 1256 | | Right (-1) -> Format.fprintf ppf "v2" |
| 1257 | | Left i -> Format.fprintf ppf "l%i" i |
| 1258 | | Right j -> Format.fprintf ppf "r%i" j |
| 1259 | | Recompose (i,j) -> |
| 1260 | Format.fprintf ppf "(%a,%a)" |
| 1261 | print_source (Left i) |
| 1262 | print_source (Right j) |
| 1263 | |
| 1264 | let print_result ppf = |
| 1265 | Array.iteri |
| 1266 | (fun i s -> |
| 1267 | if i > 0 then Format.fprintf ppf ","; |
| 1268 | print_source ppf s; |
| 1269 | ) |
| 1270 | |
| 1271 | let print_ret ppf (code,ret) = |
| 1272 | Format.fprintf ppf "$%i" code; |
| 1273 | if Array.length ret <> 0 then |
| 1274 | Format.fprintf ppf "(%a)" print_result ret |
| 1275 | |
| 1276 | let print_ret_opt ppf = function |
| 1277 | | None -> Format.fprintf ppf "*" |
| 1278 | | Some r -> print_ret ppf r |
| 1279 | |
| 1280 | let print_kind ppf actions = |
| 1281 | let print_lhs ppf (code,prefix,d) = |
| 1282 | let arity = match d.codes.(code) with (_,a,_) -> a in |
| 1283 | Format.fprintf ppf "$%i(" code; |
| 1284 | for i = 0 to arity - 1 do |
| 1285 | if i > 0 then Format.fprintf ppf ","; |
| 1286 | Format.fprintf ppf "%s%i" prefix i; |
| 1287 | done; |
| 1288 | Format.fprintf ppf ")" in |
| 1289 | let print_basic (t,ret) = |
| 1290 | Format.fprintf ppf " | %a -> %a@\n" |
| 1291 | Types.Print.print t |
| 1292 | print_ret ret |
| 1293 | in |
| 1294 | let print_prod2 = function |
| 1295 | | Impossible -> assert false |
| 1296 | | Ignore r -> |
| 1297 | Format.fprintf ppf " %a\n" |
| 1298 | print_ret r |
| 1299 | | TailCall d -> |
| 1300 | queue d; |
| 1301 | Format.fprintf ppf " disp_%i v2@\n" d.id |
| 1302 | | Dispatch (d, branches) -> |
| 1303 | queue d; |
| 1304 | Format.fprintf ppf " match v2 with disp_%i@\n" d.id; |
| 1305 | Array.iteri |
| 1306 | (fun code r -> |
| 1307 | Format.fprintf ppf " | %a -> %a\n" |
| 1308 | print_lhs (code, "r", d) |
| 1309 | print_ret r; |
| 1310 | ) |
| 1311 | branches |
| 1312 | in |
| 1313 | let print_prod prefix ppf = function |
| 1314 | | Impossible -> () |
| 1315 | | Ignore d2 -> |
| 1316 | Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix; |
| 1317 | print_prod2 d2 |
| 1318 | | TailCall d -> |
| 1319 | queue d; |
| 1320 | Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix; |
| 1321 | Format.fprintf ppf " disp_%i v1@\n" d.id |
| 1322 | | Dispatch (d,branches) -> |
| 1323 | queue d; |
| 1324 | Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix; |
| 1325 | Format.fprintf ppf " match v1 with disp_%i@\n" d.id; |
| 1326 | Array.iteri |
| 1327 | (fun code d2 -> |
| 1328 | Format.fprintf ppf " | %a -> @\n" |
| 1329 | print_lhs (code, "l", d); |
| 1330 | print_prod2 d2; |
| 1331 | ) |
| 1332 | branches |
| 1333 | in |
| 1334 | let rec print_record_opt ppf = function |
| 1335 | | None -> () |
| 1336 | | Some (RecLabel (l,d)) -> |
| 1337 | let l = LabelPool.value l in |
| 1338 | print_prod ("record:"^(Label.to_string l)) ppf d |
| 1339 | | Some (RecNolabel (r1,r2)) -> |
| 1340 | Format.fprintf ppf " | Record -> @\n"; |
| 1341 | Format.fprintf ppf " SomeField:%a;NoField:%a@\n" |
| 1342 | print_ret_opt r1 print_ret_opt r2 |
| 1343 | in |
| 1344 | |
| 1345 | List.iter print_basic actions.basic; |
| 1346 | print_prod "" ppf actions.prod; |
| 1347 | print_prod "XML" ppf actions.xml; |
| 1348 | print_record_opt ppf actions.record |
| 1349 | |
| 1350 | let print_actions ppf = function |
| 1351 | | AKind k -> print_kind ppf k |
| 1352 | | AIgnore r -> Format.fprintf ppf "v -> %a@\n" print_ret r |
| 1353 | |
| 1354 | let print_dispatcher ppf d = |
| 1355 | Format.fprintf ppf "Dispatcher %i accepts [%a]@\n" |
| 1356 | d.id Types.Print.print (Types.normalize d.t); |
| 1357 | let print_code code (t, arity, m) = |
| 1358 | Format.fprintf ppf " Returns $%i(arity=%i) for [%a]" |
| 1359 | code arity |
| 1360 | Types.Print.print (Types.normalize t); |
| 1361 | (* |
| 1362 | List.iter |
| 1363 | (fun (i,b) -> |
| 1364 | Format.fprintf ppf "[%i:" i; |
| 1365 | List.iter |
| 1366 | (fun (v,i) -> Format.fprintf ppf "%s=>%i;" v i) |
| 1367 | b; |
| 1368 | Format.fprintf ppf "]" |
| 1369 | ) m; *) |
| 1370 | |
| 1371 | Format.fprintf ppf "@\n"; |
| 1372 | in |
| 1373 | Array.iteri print_code d.codes; |
| 1374 | Format.fprintf ppf "let disp_%i = function@\n" d.id; |
| 1375 | print_actions ppf (actions d); |
| 1376 | Format.fprintf ppf "====================================@\n" |
| 1377 | |
| 1378 | |
| 1379 | let rec print_dispatchers ppf = |
| 1380 | match !to_print with |
| 1381 | | [] -> () |
| 1382 | | d :: rem -> |
| 1383 | to_print := rem; |
| 1384 | print_dispatcher ppf d; |
| 1385 | print_dispatchers ppf |
| 1386 | |
| 1387 | |
| 1388 | let show ppf t pl lab = |
| 1389 | let disp = dispatcher t pl lab in |
| 1390 | queue disp; |
| 1391 | print_dispatchers ppf |
| 1392 | |
| 1393 | let debug_compile ppf t pl = |
| 1394 | let t = Types.descr t in |
| 1395 | let lab = |
| 1396 | List.fold_left |
| 1397 | (fun l p -> min l (first_label (descr p))) |
| 1398 | (Types.Record.first_label t) pl in |
| 1399 | let lab = if lab == LabelPool.dummy_max then None else Some lab in |
| 1400 | |
| 1401 | let pl = Array.of_list |
| 1402 | (List.map (fun p -> Normal.normal lab (*t*) Types.Record.any_or_absent [p] (fv p)) pl) in |
| 1403 | |
| 1404 | show ppf t pl lab; |
| 1405 | Format.fprintf ppf "# compiled dispatchers: %i@\n" !cur_id |
| 1406 | end |
| 1407 | |
| 1408 | |
| 1409 | |
| 1410 | |
| 1411 | (* New compilation procedure *) |
| 1412 | |
| 1413 | module Compile2 = struct |
| 1414 | |
| 1415 | let any_or_abs = Types.Record.any_or_absent |
| 1416 | |
| 1417 | module PatList = SortedList.Make(struct include Custom.Dummy include Pat end) |
| 1418 | module TypesFv = Custom.Pair(Types)(IdSet) |
| 1419 | module Req = PatList.MakeMap(TypesFv) |
| 1420 | (* Invariant for (p |-> (t,X)): |
| 1421 | i) t != Empty |
| 1422 | ii) X \subset fv(p) *) |
| 1423 | |
| 1424 | let empty_reqs = PatList.Map.empty |
| 1425 | |
| 1426 | let merge_reqs = |
| 1427 | PatList.Map.merge |
| 1428 | (fun (t1,xs1) (t2,xs2) -> Types.cup t1 t2, IdSet.cup xs1 xs2) |
| 1429 | |
| 1430 | let add_req reqs p t xs = |
| 1431 | merge_reqs reqs (PatList.Map.singleton p (t,xs)) |
| 1432 | |
| 1433 | module NodeSet = Set.Make(Node) |
| 1434 | |
| 1435 | let pi1 ~kind t = Types.Product.pi1 (Types.Product.get ~kind t) |
| 1436 | let pi2 ~kind t = Types.Product.pi2 (Types.Product.get ~kind t) |
| 1437 | |
| 1438 | module Approx = struct |
| 1439 | |
| 1440 | (* Note: this is incomplete because of non-atomic constant patterns: |
| 1441 | # debug approx (_,(x:=(1,2))) (1,2);; |
| 1442 | [DEBUG:approx] |
| 1443 | x=(1,2) |
| 1444 | *) |
| 1445 | let rec approx_var seen ((a,fv,d) as p) t xs = |
| 1446 | assert (Types.subtype t a); |
| 1447 | assert (IdSet.subset xs fv); |
| 1448 | if (IdSet.is_empty xs) || (Types.is_empty t) then xs |
| 1449 | else match d with |
| 1450 | | Cup ((a1,_,_) as p1,p2) -> |
| 1451 | IdSet.cap |
| 1452 | (approx_var seen p1 (Types.cap t a1) xs) |
| 1453 | (approx_var seen p2 (Types.diff t a1) xs) |
| 1454 | | Cap ((_,fv1,_) as p1,((_,fv2,_) as p2)) -> |
| 1455 | IdSet.cup |
| 1456 | (approx_var seen p1 t (IdSet.cap fv1 xs)) |
| 1457 | (approx_var seen p2 t (IdSet.cap fv2 xs)) |
| 1458 | | Capture _ -> |
| 1459 | xs |
| 1460 | | Constant (_,c) -> |
| 1461 | if (Types.subtype t (Types.constant c)) then xs else IdSet.empty |
| 1462 | | Times (q1,q2) -> |
| 1463 | let xs = IdSet.cap xs (IdSet.cap q1.fv q2.fv) in |
| 1464 | IdSet.cap |
| 1465 | (approx_var_node seen q1 (pi1 ~kind:`Normal t) xs) |
| 1466 | (approx_var_node seen q2 (pi2 ~kind:`Normal t) xs) |
| 1467 | | Xml (q1,q2) -> |
| 1468 | let xs = IdSet.cap xs (IdSet.cap q1.fv q2.fv) in |
| 1469 | IdSet.cap |
| 1470 | (approx_var_node seen q1 (pi1 ~kind:`XML t) xs) |
| 1471 | (approx_var_node seen q2 (pi2 ~kind:`XML t) xs) |
| 1472 | | Record _ -> IdSet.empty |
| 1473 | | _ -> assert false |
| 1474 | |
| 1475 | and approx_var_node seen q t xs = |
| 1476 | if (NodeSet.mem q seen) |
| 1477 | then xs |
| 1478 | else approx_var (NodeSet.add q seen) q.descr t xs |
| 1479 | |
| 1480 | |
| 1481 | let approx_cst ((a,_,_) as p) t xs = |
| 1482 | if IdSet.is_empty xs then IdMap.empty |
| 1483 | else |
| 1484 | let rec aux accu (x,t) = |
| 1485 | if (IdSet.mem xs x) then |
| 1486 | match Sample.single_opt (Types.descr t) with |
| 1487 | | Some c -> (x,c)::accu |
| 1488 | | None -> accu |
| 1489 | else accu in |
| 1490 | let t = Types.cap t a in |
| 1491 | IdMap.from_list_disj (List.fold_left aux [] (filter_descr t p)) |
| 1492 | |
| 1493 | let approx_var ((a,_,_) as p) t = |
| 1494 | approx_var NodeSet.empty p (Types.cap t a) |
| 1495 | end |
| 1496 | |
| 1497 | module TargExpr = struct |
| 1498 | |
| 1499 | type t = source IdMap.map |
| 1500 | and source = |
| 1501 | | SrcCapture |
| 1502 | | SrcLeft | SrcRight |
| 1503 | | SrcCst of Types.const |
| 1504 | | SrcPair of source * source |
| 1505 | | SrcFetchLeft of int |
| 1506 | | SrcFetchRight of int |
| 1507 | | SrcLocal of int |
| 1508 | |
| 1509 | (* |
| 1510 | let rec equal_src s1 s2 = (s1 == s2) || match (s1,s2) with |
| 1511 | | SrcCst c1, SrcCst c2 -> Types.Const.equal c1 c2 |
| 1512 | | SrcPair (s1,ss1), SrcPair (s2,ss2) -> |
| 1513 | equal_src s1 s2 && equal_src ss1 ss2 |
| 1514 | | SrcFetchLeft i, SrcFetchLeft j |
| 1515 | | SrcFetchRight i, SrcFetchRight j |
| 1516 | | SrcLocal i, SrcLocal j when i == j -> true |
| 1517 | | _ -> false |
| 1518 | |
| 1519 | let equal = IdMap.equal equal_src |
| 1520 | *) |
| 1521 | |
| 1522 | |
| 1523 | type push = PushConst of Types.const | PushField | PushCapture |
| 1524 | |
| 1525 | let capture x = IdMap.singleton x SrcCapture |
| 1526 | let captures xs = IdMap.constant SrcCapture xs |
| 1527 | let cst x c = IdMap.singleton x (SrcCst c) |
| 1528 | let constants cs = IdMap.map (fun c -> SrcCst c) cs |
| 1529 | let fetch_left f = SrcFetchLeft f |
| 1530 | let fetch_right f = SrcFetchRight f |
| 1531 | let fetch_local ofs i = SrcLocal (ofs + i) |
| 1532 | let empty = IdMap.empty |
| 1533 | let merge e1 e2 = IdMap.merge (fun s1 s2 -> SrcPair (s1,s2)) e1 e2 |
| 1534 | let captures_left xs = IdMap.constant SrcLeft xs |
| 1535 | let captures_right xs = IdMap.constant SrcRight xs |
| 1536 | |
| 1537 | let rec print_src ppf = function |
| 1538 | | SrcCapture -> Format.fprintf ppf "v" |
| 1539 | | SrcLeft -> Format.fprintf ppf "v1" |
| 1540 | | SrcRight -> Format.fprintf ppf "v2" |
| 1541 | | SrcCst c -> Types.Print.print_const ppf c |
| 1542 | | SrcPair (s1,s2) -> |
| 1543 | Format.fprintf ppf "(%a,%a)" print_src s1 print_src s2 |
| 1544 | | SrcFetchLeft x -> Format.fprintf ppf "x%i" x |
| 1545 | | SrcFetchRight x -> Format.fprintf ppf "y%i" x |
| 1546 | | SrcLocal x -> Format.fprintf ppf "local(%i)" x |
| 1547 | |
| 1548 | let print ppf r = |
| 1549 | Format.fprintf ppf "{ "; |
| 1550 | List.iter (fun (x,s) -> |
| 1551 | Format.fprintf ppf "%a:=%a " |
| 1552 | U.print (Id.value x) |
| 1553 | print_src s) (IdMap.get r); |
| 1554 | Format.fprintf ppf "}"; |
| 1555 | end |
| 1556 | |
| 1557 | module Derivation = struct |
| 1558 | |
| 1559 | type t = |
| 1560 | | TSucceed |
| 1561 | | TFail |
| 1562 | | TConstr of Types.t * Types.t |
| 1563 | | TCapt of TargExpr.t * t |
| 1564 | | TAlt of descr * Types.t * t * t |
| 1565 | | TConj of Types.t * fv * t * t |
| 1566 | | TTimes of Types.pair_kind * int * descr * Types.t * fv * node * node |
| 1567 | | TRecord of int * descr * Types.t * fv * label * node |
| 1568 | |
| 1569 | (* |
| 1570 | let rec same p1 p2 = (p1 == p2) || match (p1,p2) with |
| 1571 | | TConstr (t1,s1), TConstr (t2,s2) -> |
| 1572 | Types.equiv s1 s2 && |
| 1573 | Types.equiv (Types.cap t1 s1) (Types.cap t2 s2) |
| 1574 | | TCapt (pr1,p1), TCapt (pr2,p2) -> |
| 1575 | TargExpr.equal pr1 pr2 && same p1 p2 |
| 1576 | | TAlt (p1,_,a1,b1), TAlt (p2,_,a2,b2) -> |
| 1577 | (p1 == p2) && (same a1 a2) && (same b1 b2) |
| 1578 | | TConj (_,_,a1,b1), TConj (_,_,a2,b2) -> |
| 1579 | same a1 a2 && same b1 b2 |
| 1580 | | TTimes (k1,uid1,p1,t1,xs1,a1,b1), |
| 1581 | TTimes (k2,uid2,p2,t2,xs2,a2,b2) -> |
| 1582 | assert false |
| 1583 | | TRecord (uid1,_,t1,_,_,_), |
| 1584 | TRecord (uid2,_,t2,_,_,_) -> |
| 1585 | (uid1 == uid2) && (Types.equiv t1 t2) |
| 1586 | | _ -> false |
| 1587 | *) |
| 1588 | |
| 1589 | (* TODO: allocate the stack locations by sorting the ids |
| 1590 | (to allow ({ l = (x,y) } | (x:=1)&(y:=2))) *) |
| 1591 | let push_csts pushes locals = |
| 1592 | let push x = |
| 1593 | pushes := x :: !pushes; |
| 1594 | let loc = TargExpr.SrcLocal !locals in |
| 1595 | incr locals; loc in |
| 1596 | let reloc = function |
| 1597 | | TargExpr.SrcCst c -> push (TargExpr.PushConst c) |
| 1598 | | TargExpr.SrcLeft -> push TargExpr.PushField |
| 1599 | | TargExpr.SrcCapture -> push TargExpr.PushCapture |
| 1600 | | TargExpr.SrcLocal _ as s -> s |
| 1601 | | _ -> assert false |
| 1602 | in |
| 1603 | let rec aux = function |
| 1604 | | TCapt (pr,p) -> TCapt (IdMap.map reloc pr, p) |
| 1605 | | TAlt (p,a1,p1,p2) -> TAlt (p,a1,aux p1,aux p2) |
| 1606 | | TConj (a1,fv1,p1,p2) -> TConj (a1,fv1,aux p1, aux p2) |
| 1607 | | p -> p |
| 1608 | in |
| 1609 | aux |
| 1610 | |
| 1611 | let capt pr p = |
| 1612 | if IdMap.is_empty pr then p else match p with |
| 1613 | | TCapt (pr2,p) -> TCapt (TargExpr.merge pr pr2,p) |
| 1614 | | TFail -> TFail |
| 1615 | | p -> TCapt (pr,p) |
| 1616 | |
| 1617 | let success pr = |
| 1618 | capt pr TSucceed |
| 1619 | |
| 1620 | let success_if_present pr = |
| 1621 | capt pr (TConstr (Types.any,any_or_abs)) |
| 1622 | |
| 1623 | let rec conj a1 fv1 r1 r2 = match (r1,r2) with |
| 1624 | | TSucceed,r | r,TSucceed -> r |
| 1625 | | TFail,r | r,TFail -> TFail |
| 1626 | | TCapt (f,r1), r2 | r2, TCapt (f,r1) -> capt f (conj a1 fv1 r1 r2) |
| 1627 | | r1,r2 -> TConj (a1,fv1,r1,r2) |
| 1628 | |
| 1629 | let constrain a t = |
| 1630 | if Types.disjoint a t then TFail |
| 1631 | else if Types.subtype t a then ( |
| 1632 | (* Format.fprintf Format.std_formatter |
| 1633 | "Optimize constraint -> Succeed a=%a t=%a@." |
| 1634 | Types.Print.print a |
| 1635 | Types.Print.print t; *) |
| 1636 | TSucceed |
| 1637 | ) |
| 1638 | else TConstr (a,t) |
| 1639 | |
| 1640 | let alt p a1 r1 r2 = match (r1,r2) with |
| 1641 | | TFail,r | r,TFail -> r |
| 1642 | | TSucceed, _ -> assert false |
| 1643 | (* Note: this cannot happen because if the lhs succeeds, |
| 1644 | then the rhs must fail (it is evaluated under |
| 1645 | the assumption that the lhs fails, so the static |
| 1646 | assumption is empty in this case). *) |
| 1647 | | r1,r2 -> TAlt (p,a1,r1,r2) |
| 1648 | |
| 1649 | let rec print ppf = function |
| 1650 | | TSucceed -> Format.fprintf ppf "Succeed" |
| 1651 | | TFail -> Format.fprintf ppf "Fail" |
| 1652 | | TConstr (t,s) -> |
| 1653 | Format.fprintf ppf "%a/%a" |
| 1654 | Types.Print.print t |
| 1655 | Types.Print.print s |
| 1656 | | TCapt (pr,r) -> |
| 1657 | Format.fprintf ppf "{%a}(%a)" TargExpr.print pr print r |
| 1658 | | TAlt (_,_,l,r) -> |
| 1659 | Format.fprintf ppf "(%a | %a)" print l print r |
| 1660 | | TConj (_,_,l,r) -> |
| 1661 | Format.fprintf ppf "(%a & %a)" print l print r |
| 1662 | | TRecord (_,_,t,xs,l,q) -> |
| 1663 | Format.fprintf ppf "<t=%a;xs=%a;{%a=%a}>" |
| 1664 | Types.Print.print t |
| 1665 | Print.print_xs xs |
| 1666 | Label.print (LabelPool.value l) |
| 1667 | Print.print q.descr |
| 1668 | | TTimes (kind,_,_,t,xs,q1,q2) -> |
| 1669 | Format.fprintf ppf "<t=%a;xs=%a;(%a,%a)>" |
| 1670 | Types.Print.print t |
| 1671 | Print.print_xs xs |
| 1672 | Print.print q1.descr |
| 1673 | Print.print q2.descr |
| 1674 | |
| 1675 | exception NotAResult |
| 1676 | |
| 1677 | let get_result = function |
| 1678 | | TSucceed -> Some TargExpr.empty |
| 1679 | | TCapt (r,TSucceed) -> Some r |
| 1680 | | TFail -> None |
| 1681 | | r -> raise NotAResult |
| 1682 | (* |
| 1683 | Format.fprintf Format.std_formatter "ERR: %a@." print r; |
| 1684 | *) |
| 1685 | |
| 1686 | |
| 1687 | let print_result ppf = function |
| 1688 | | None -> Format.fprintf ppf "Fail" |
| 1689 | | Some r -> TargExpr.print ppf r |
| 1690 | |
| 1691 | |
| 1692 | let uid = ref 0 |
| 1693 | let rec mk ((a,fv,d) as p) = match d with |
| 1694 | | Constr t -> TConstr (t, any_or_abs) |
| 1695 | | Cup ((a1,_,_) as p1,p2) -> TAlt (p, a1,mk p1, mk p2) |
| 1696 | | Cap ((a1,fv1,_) as p1,p2) -> TConj (a1,fv1,mk p1,mk p2) |
| 1697 | | Capture x -> success_if_present (TargExpr.capture x) |
| 1698 | | Constant (x,c) -> success_if_present (TargExpr.cst x c) |
| 1699 | | Times (q1,q2) -> |
| 1700 | TTimes (`Normal,(incr uid; !uid), p, any_or_abs,fv,q1,q2) |
| 1701 | | Xml (q1,q2) -> |
| 1702 | TTimes (`XML,(incr uid; !uid), p,any_or_abs,fv,q1,q2) |
| 1703 | | Record (l,q) -> |
| 1704 | TRecord ((incr uid; !uid),p, any_or_abs,fv,l,q) |
| 1705 | | Dummy -> assert false |
| 1706 | |
| 1707 | |
| 1708 | let approx_var p t xs f = |
| 1709 | let vs = Approx.approx_var p t xs in |
| 1710 | let xs = IdSet.diff xs vs in |
| 1711 | let pr = f vs in |
| 1712 | (pr,xs) |
| 1713 | |
| 1714 | let approx_cst p t xs f = |
| 1715 | let vs = Approx.approx_cst p t xs in |
| 1716 | let xs = IdSet.diff xs (IdMap.domain vs) in |
| 1717 | let pr = f vs in |
| 1718 | (pr,xs) |
| 1719 | |
| 1720 | let factorize ((a,_,_) as p) t xs f = |
| 1721 | if Types.disjoint a t then TFail |
| 1722 | else |
| 1723 | (* let () = Format.fprintf Format.std_formatter |
| 1724 | "Factorize p=%a t=%a a=%a@." |
| 1725 | Print.print p |
| 1726 | Types.Print.print t |
| 1727 | Types.Print.print a in *) |
| 1728 | let pr,xs = approx_var p t xs TargExpr.captures in |
| 1729 | let pr',xs = approx_cst p t xs TargExpr.constants in |
| 1730 | let pr = TargExpr.merge pr pr' in |
| 1731 | capt pr (if (IdSet.is_empty xs) then constrain a t else f xs) |
| 1732 | |
| 1733 | |
| 1734 | let rec optimize t xs = function |
| 1735 | | TCapt (pr,p) -> |
| 1736 | let pr = IdMap.restrict pr xs in |
| 1737 | capt pr (optimize t (IdSet.diff xs (IdMap.domain pr)) p) |
| 1738 | | TAlt (p,a1,p1,p2) -> |
| 1739 | factorize p t xs |
| 1740 | (fun xs -> |
| 1741 | alt p a1 (optimize t xs p1) (optimize (Types.diff t a1) xs p2)) |
| 1742 | | TConj (a1,fv1,p1,p2) -> |
| 1743 | (* We don't factorize above a & pattern eagerly, because |
| 1744 | if factorization would occur, it would also |
| 1745 | occur below and be lifted by the conj function, which |
| 1746 | produces the same effect. *) |
| 1747 | conj a1 fv1 |
| 1748 | (optimize t (IdSet.cap xs fv1) p1) |
| 1749 | (optimize (Types.cap t a1) (IdSet.diff xs fv1) p2) |
| 1750 | | TConstr (a,_) -> constrain a t |
| 1751 | | TTimes (kind,uid, p,_,_,q1,q2) -> |
| 1752 | factorize p t xs (fun xs -> TTimes (kind,uid, p,t,xs,q1,q2)) |
| 1753 | | TRecord (uid,p,_,_,l,q) -> |
| 1754 | factorize p t xs (fun xs -> TRecord (uid,p,t,xs,l,q)) |
| 1755 | | TSucceed -> if Types.is_empty t then TFail else TSucceed |
| 1756 | | TFail -> TFail |
| 1757 | |
| 1758 | (* |
| 1759 | let optimize t xs p = |
| 1760 | let p' = optimize t xs p in |
| 1761 | Format.fprintf Format.std_formatter |
| 1762 | "Optimize %a // (t=%a) ===> %a@." |
| 1763 | print p |
| 1764 | Types.Print.print t |
| 1765 | print p'; |
| 1766 | p' |
| 1767 | *) |
| 1768 | |
| 1769 | let fold f accu = function |
| 1770 | | TCapt (_,p) -> f accu p |
| 1771 | | TAlt (_,_,p1,p2) | TConj (_,_,p1,p2) -> f (f accu p1) p2 |
| 1772 | | _ -> accu |
| 1773 | |
| 1774 | let iter f = function |
| 1775 | | TCapt (_,p) -> f p |
| 1776 | | TAlt (_,_,p1,p2) | TConj (_,_,p1,p2) -> f p1; f p2 |
| 1777 | | _ -> () |
| 1778 | |
| 1779 | let map f = function |
| 1780 | | TCapt (pr,p) -> capt pr (f p) |
| 1781 | | TAlt (p,a1,p1,p2) -> alt p a1 (f p1) (f p2) |
| 1782 | | TConj (a1,fv1,p1,p2) -> conj a1 fv1 (f p1) (f p2) |
| 1783 | | x -> x |
| 1784 | |
| 1785 | let iter_constr f = |
| 1786 | let rec aux = function |
| 1787 | | TConstr (t,s) -> f (t,s) |
| 1788 | | p -> iter aux p |
| 1789 | in aux |
| 1790 | |
| 1791 | let iter_times k f = |
| 1792 | let rec aux = function |
| 1793 | | TTimes (kind,uid,_,t,xs,q1,q2) when k == kind -> f (uid,t,xs,q1,q2) |
| 1794 | | p -> iter aux p |
| 1795 | in aux |
| 1796 | |
| 1797 | let iter_records f = |
| 1798 | let rec aux = function |
| 1799 | | TRecord (uid,_,t,xs,l,q) -> f (uid,t,xs,l,q) |
| 1800 | | p -> iter aux p |
| 1801 | in aux |
| 1802 | |
| 1803 | let iter_field l f = |
| 1804 | let rec aux = function |
| 1805 | | TRecord (uid,_,t,xs,l',q) when l == l' -> f (uid,t,xs,q) |
| 1806 | | p -> iter aux p |
| 1807 | in aux |
| 1808 | |
| 1809 | let opt_all t0 = |
| 1810 | List.map |
| 1811 | (fun (p,t,xs) -> |
| 1812 | if Types.subtype t t0 then (p,t,xs) |
| 1813 | else let t = Types.cap t t0 in (optimize t xs p, t, xs)) |
| 1814 | |
| 1815 | let get_results reqs = |
| 1816 | List.map (fun (p,_,_) -> get_result p) reqs |
| 1817 | |
| 1818 | let iter_all f g reqs = |
| 1819 | List.iter (fun (p,_,_) -> f g p) reqs |
| 1820 | |
| 1821 | let get_all pi get sel extract iter side reqs = |
| 1822 | let extra = ref [] in |
| 1823 | let res = ref empty_reqs in |
| 1824 | let aux3 s1 t12 = |
| 1825 | let t1 = sel t12 in |
| 1826 | if not ((Types.subtype s1 t1) || (Types.disjoint s1 t1)) |
| 1827 | then res := add_req !res (constr t1) s1 IdSet.empty in |
| 1828 | let aux2 (t,s) = List.iter (aux3 (pi s)) (get (Types.cap t s)) in |
| 1829 | let aux z = |
| 1830 | let uid,t,xs,q = extract z in |
| 1831 | let xs = IdSet.cap xs q.fv and p = q.descr and t = pi t in |
| 1832 | |
| 1833 | (* let p = cap p (constr Types.any) in *) |
| 1834 | let pr,xs = approx_var p t xs side in |
| 1835 | let pr',xs = approx_cst p t xs TargExpr.constants in |
| 1836 | let pr = TargExpr.merge pr pr' in |
| 1837 | |
| 1838 | extra := (uid,pr)::!extra; |
| 1839 | if not ((IdSet.is_empty xs) |
| 1840 | && (Types.subtype t (Types.descr q.accept))) then |
| 1841 | res := add_req !res p t xs in |
| 1842 | iter_all iter aux reqs; |
| 1843 | iter_all iter_constr aux2 reqs; |
| 1844 | !extra,!res |
| 1845 | |
| 1846 | let prod_all k side pi sel selq reqs = |
| 1847 | get_all pi (fun t -> Types.Product.clean_normal (Types.Product.normal ~kind:k t)) sel |
| 1848 | (fun (uid,t,xs,q1,q2) -> uid,t,xs,selq (q1,q2)) |
| 1849 | (iter_times k) |
| 1850 | side |
| 1851 | reqs |
| 1852 | |
| 1853 | let all_labels reqs = |
| 1854 | let res = ref LabelSet.empty in |
| 1855 | let aux2 (t,_) = res := LabelSet.cup !res (Types.Record.all_labels t) in |
| 1856 | let aux (_,_,_,l,_) = res := LabelSet.add l !res in |
| 1857 | iter_all iter_records aux reqs; |
| 1858 | iter_all iter_constr aux2 reqs; |
| 1859 | LabelSet.get !res |
| 1860 | |
| 1861 | let record_all l reqs = |
| 1862 | let extra,res = |
| 1863 | get_all (Types.Record.pi l) (fun t -> Types.Record.split_normal t l) fst |
| 1864 | (fun z -> z) |
| 1865 | (iter_field l) |
| 1866 | TargExpr.captures_left |
| 1867 | reqs in |
| 1868 | extra,res |
| 1869 | |
| 1870 | let rec find_binds q reqs binds fetch = |
| 1871 | match (reqs,binds) with |
| 1872 | | (p2,_)::_, Some b::_ when Pat.equal q.descr p2 -> |
| 1873 | IdMap.map fetch b |
| 1874 | | _::reqs, _::binds -> find_binds q reqs binds fetch |
| 1875 | | _ -> raise Not_found |
| 1876 | let find_binds q reqs binds fetch uid extra = |
| 1877 | let r = List.assq uid extra in |
| 1878 | try TargExpr.merge r (find_binds q (PatList.Map.get reqs) binds fetch) |
| 1879 | with Not_found -> r |
| 1880 | |
| 1881 | let pair swap l r = let (l,r) = swap (l,r) in TargExpr.SrcPair (l,r) |
| 1882 | let rec set_times k swap swap' extra1 extra2 reqs1 reqs2 binds1 binds2 = |
| 1883 | let rec aux = function |
| 1884 | | TTimes (kind,uid,_,t,xs,q1,q2) when k == kind-> |
| 1885 | let (q1,q2) = swap (q1,q2) in |
| 1886 | let r1 = find_binds q1 reqs1 binds1 TargExpr.fetch_left uid extra1 |
| 1887 | and r2 = find_binds q2 reqs2 binds2 TargExpr.fetch_right uid extra2 |
| 1888 | in |
| 1889 | let r = IdMap.merge (pair swap') r1 r2 in |
| 1890 | success (IdMap.restrict r xs) |
| 1891 | | x -> map aux x |
| 1892 | in |
| 1893 | aux |
| 1894 | |
| 1895 | let rec set_field l locals extra1 reqs1 binds1 = |
| 1896 | let rec aux = function |
| 1897 | | TRecord (uid,_,t,xs,l',q) when l == l' -> |
| 1898 | let r = find_binds q reqs1 binds1 |
| 1899 | (TargExpr.fetch_local locals) uid extra1 |
| 1900 | in |
| 1901 | success (IdMap.restrict r xs) |
| 1902 | | x -> map aux x |
| 1903 | in |
| 1904 | aux |
| 1905 | |
| 1906 | |
| 1907 | let mkopt p t xs = optimize t xs (mk p) |
| 1908 | |
| 1909 | let demo ppf ((_,fv,_) as p) t = |
| 1910 | let p = mk p in |
| 1911 | (* Format.fprintf ppf "%a@." print p; *) |
| 1912 | let p = optimize t fv p in |
| 1913 | Format.fprintf ppf "%a@." print p; |
| 1914 | Format.fprintf ppf "@.Fields:@."; |
| 1915 | iter_records |
| 1916 | (fun (_,t,xs,l,q) -> |
| 1917 | Format.fprintf ppf "(%a=%a) / %a@." |
| 1918 | print_lab l |
| 1919 | Print.print q.descr |
| 1920 | Types.Print.print (Types.Record.project_opt t l) |
| 1921 | ) p |
| 1922 | |
| 1923 | end |
| 1924 | |
| 1925 | type output = Types.t * int * int id_map option list |
| 1926 | (* Obtained type, arity, bindings *) |
| 1927 | |
| 1928 | type rescode = |
| 1929 | | RFail |
| 1930 | | RCode of int |
| 1931 | | RSwitch of rescode * rescode |
| 1932 | | RIgnore of rescode |
| 1933 | |
| 1934 | type result = int * TargExpr.source array |
| 1935 | type actions = |
| 1936 | | AResult of result |
| 1937 | | AKind of actions_kind |
| 1938 | and actions_kind = { |
| 1939 | basic: (Types.t * result) list; |
| 1940 | atoms: result Atoms.map; |