Parent Directory
|
Revision Log
[r2004-12-23 15:16:34 by afrisch] Simplify Original author: afrisch Date: 2004-12-23 15:16:34+00:00
| 1 | abate | 107 | exception Error of string |
| 2 | abate | 225 | open Ident |
| 3 | abate | 1 | |
| 4 | abate | 310 | (* |
| 5 | To be sure not to use generic comparison ... | ||
| 6 | abate | 332 | *) |
| 7 | let (=) : int -> int -> bool = (==) | ||
| 8 | abate | 310 | let (<) : int -> int -> bool = (<) |
| 9 | abate | 332 | let (<=) : int -> int -> bool = (<=) |
| 10 | let (<>) : int -> int -> bool = (<>) | ||
| 11 | let compare = 1 | ||
| 12 | abate | 310 | |
| 13 | abate | 332 | |
| 14 | abate | 1 | (* Syntactic algebra *) |
| 15 | abate | 121 | (* Constraint: any node except Constr has fv<>[] ... *) |
| 16 | abate | 1 | type d = |
| 17 | abate | 653 | | Constr of Types.t |
| 18 | abate | 1 | | Cup of descr * descr |
| 19 | abate | 121 | | Cap of descr * descr |
| 20 | abate | 1 | | Times of node * node |
| 21 | abate | 110 | | Xml of node * node |
| 22 | abate | 233 | | Record of label * node |
| 23 | abate | 225 | | Capture of id |
| 24 | | Constant of id * Types.const | ||
| 25 | abate | 691 | | Dummy |
| 26 | abate | 1 | and node = { |
| 27 | id : int; | ||
| 28 | abate | 691 | mutable descr : descr; |
| 29 | abate | 653 | accept : Types.Node.t; |
| 30 | abate | 1107 | fv : fv |
| 31 | abate | 653 | } and descr = Types.t * fv * d |
| 32 | abate | 1 | |
| 33 | abate | 653 | |
| 34 | |||
| 35 | abate | 136 | let id x = x.id |
| 36 | abate | 691 | let descr x = x.descr |
| 37 | abate | 136 | let fv x = x.fv |
| 38 | let accept x = Types.internalize x.accept | ||
| 39 | abate | 121 | |
| 40 | let printed = ref [] | ||
| 41 | let to_print = ref [] | ||
| 42 | abate | 136 | let rec print ppf (a,_,d) = |
| 43 | abate | 121 | match d with |
| 44 | abate | 367 | | Constr t -> Types.Print.print ppf t |
| 45 | abate | 121 | | Cup (p1,p2) -> Format.fprintf ppf "(%a | %a)" print p1 print p2 |
| 46 | | Cap (p1,p2) -> Format.fprintf ppf "(%a & %a)" print p1 print p2 | ||
| 47 | | Times (n1,n2) -> | ||
| 48 | Format.fprintf ppf "(P%i,P%i)" n1.id n2.id; | ||
| 49 | to_print := n1 :: n2 :: !to_print | ||
| 50 | | Xml (n1,n2) -> | ||
| 51 | Format.fprintf ppf "XML(P%i,P%i)" n1.id n2.id; | ||
| 52 | to_print := n1 :: n2 :: !to_print | ||
| 53 | | Record (l,n) -> | ||
| 54 | abate | 542 | Format.fprintf ppf "{ %a = P%i }" Label.print (LabelPool.value l) n.id; |
| 55 | abate | 121 | to_print := n :: !to_print |
| 56 | | Capture x -> | ||
| 57 | abate | 374 | Format.fprintf ppf "%a" U.print (Id.value x) |
| 58 | abate | 121 | | Constant (x,c) -> |
| 59 | abate | 374 | Format.fprintf ppf "(%a := %a)" U.print (Id.value x) |
| 60 | abate | 225 | Types.Print.print_const c |
| 61 | abate | 691 | | Dummy -> |
| 62 | Format.fprintf ppf "*DUMMY*" | ||
| 63 | abate | 121 | |
| 64 | abate | 136 | let dump_print ppf = |
| 65 | abate | 332 | while !to_print != [] do |
| 66 | abate | 136 | let p = List.hd !to_print in |
| 67 | to_print := List.tl !to_print; | ||
| 68 | if not (List.mem p.id !printed) then | ||
| 69 | ( printed := p.id :: !printed; | ||
| 70 | Format.fprintf ppf "P%i:=%a\n" p.id print (descr p) | ||
| 71 | ) | ||
| 72 | done | ||
| 73 | abate | 121 | |
| 74 | abate | 136 | let print ppf d = |
| 75 | Format.fprintf ppf "%a@\n" print d; | ||
| 76 | dump_print ppf | ||
| 77 | abate | 121 | |
| 78 | abate | 1349 | let print_node ppf n = |
| 79 | Format.fprintf ppf "P%i" n.id; | ||
| 80 | to_print := n :: !to_print; | ||
| 81 | dump_print ppf | ||
| 82 | abate | 136 | |
| 83 | abate | 1349 | |
| 84 | abate | 95 | let counter = State.ref "Patterns.counter" 0 |
| 85 | abate | 1 | |
| 86 | abate | 691 | let dummy = (Types.empty,IdSet.empty,Dummy) |
| 87 | abate | 95 | let make fv = |
| 88 | incr counter; | ||
| 89 | abate | 1107 | { id = !counter; descr = dummy; accept = Types.make (); fv = fv } |
| 90 | abate | 95 | |
| 91 | abate | 1 | let define x ((accept,fv,_) as d) = |
| 92 | abate | 310 | (* assert (x.fv = fv); *) |
| 93 | abate | 1 | Types.define x.accept accept; |
| 94 | abate | 691 | x.descr <- d |
| 95 | abate | 1 | |
| 96 | abate | 225 | let constr x = (x,IdSet.empty,Constr x) |
| 97 | abate | 1 | let cup ((acc1,fv1,_) as x1) ((acc2,fv2,_) as x2) = |
| 98 | abate | 225 | if not (IdSet.equal fv1 fv2) then ( |
| 99 | let x = match IdSet.pick (IdSet.diff fv1 fv2) with | ||
| 100 | | Some x -> x | ||
| 101 | | None -> match IdSet.pick (IdSet.diff fv2 fv1) with Some x -> x | ||
| 102 | | None -> assert false | ||
| 103 | abate | 107 | in |
| 104 | raise | ||
| 105 | (Error | ||
| 106 | abate | 374 | ("The capture variable " ^ (U.to_string (Id.value x)) ^ |
| 107 | abate | 107 | " should appear on both side of this | pattern")) |
| 108 | ); | ||
| 109 | abate | 225 | (Types.cup acc1 acc2, IdSet.cup fv1 fv2, Cup (x1,x2)) |
| 110 | abate | 121 | let cap ((acc1,fv1,_) as x1) ((acc2,fv2,_) as x2) = |
| 111 | abate | 225 | if not (IdSet.disjoint fv1 fv2) then ( |
| 112 | match IdSet.pick (IdSet.cap fv1 fv2) with | ||
| 113 | | Some x -> | ||
| 114 | abate | 107 | raise |
| 115 | (Error | ||
| 116 | abate | 374 | ("The capture variable " ^ (U.to_string (Id.value x)) ^ |
| 117 | abate | 107 | " cannot appear on both side of this & pattern")) |
| 118 | abate | 225 | | None -> assert false |
| 119 | abate | 107 | ); |
| 120 | abate | 225 | (Types.cap acc1 acc2, IdSet.cup fv1 fv2, Cap (x1,x2)) |
| 121 | abate | 1 | let times x y = |
| 122 | abate | 225 | (Types.times x.accept y.accept, IdSet.cup x.fv y.fv, Times (x,y)) |
| 123 | abate | 110 | let xml x y = |
| 124 | abate | 225 | (Types.xml x.accept y.accept, IdSet.cup x.fv y.fv, Xml (x,y)) |
| 125 | abate | 1 | let record l x = |
| 126 | abate | 229 | (Types.record l x.accept, x.fv, Record (l,x)) |
| 127 | abate | 225 | let capture x = (Types.any, IdSet.singleton x, Capture x) |
| 128 | let constant x c = (Types.any, IdSet.singleton x, Constant (x,c)) | ||
| 129 | abate | 1 | |
| 130 | |||
| 131 | abate | 691 | module Node = struct |
| 132 | type t = node | ||
| 133 | let compare n1 n2 = n1.id - n2.id | ||
| 134 | let equal n1 n2 = n1.id == n2.id | ||
| 135 | let hash n = n.id | ||
| 136 | abate | 1 | |
| 137 | abate | 698 | let check n = () |
| 138 | abate | 1349 | let dump = print_node |
| 139 | abate | 1 | |
| 140 | abate | 698 | |
| 141 | abate | 691 | module SMemo = Set.Make(Custom.Int) |
| 142 | let memo = Serialize.Put.mk_property (fun t -> ref SMemo.empty) | ||
| 143 | let rec serialize t n = | ||
| 144 | let l = Serialize.Put.get_property memo t in | ||
| 145 | Serialize.Put.int t n.id; | ||
| 146 | if not (SMemo.mem n.id !l) then ( | ||
| 147 | l := SMemo.add n.id !l; | ||
| 148 | Types.Node.serialize t n.accept; | ||
| 149 | IdSet.serialize t n.fv; | ||
| 150 | serialize_descr t n.descr | ||
| 151 | ) | ||
| 152 | and serialize_descr s (_,_,d) = | ||
| 153 | serialize_d s d | ||
| 154 | and serialize_d s = function | ||
| 155 | | Constr t -> | ||
| 156 | Serialize.Put.bits 3 s 0; | ||
| 157 | Types.serialize s t | ||
| 158 | | Cup (p1,p2) -> | ||
| 159 | Serialize.Put.bits 3 s 1; | ||
| 160 | serialize_descr s p1; | ||
| 161 | serialize_descr s p2 | ||
| 162 | | Cap (p1,p2) -> | ||
| 163 | Serialize.Put.bits 3 s 2; | ||
| 164 | serialize_descr s p1; | ||
| 165 | serialize_descr s p2 | ||
| 166 | | Times (p1,p2) -> | ||
| 167 | Serialize.Put.bits 3 s 3; | ||
| 168 | serialize s p1; | ||
| 169 | serialize s p2 | ||
| 170 | | Xml (p1,p2) -> | ||
| 171 | Serialize.Put.bits 3 s 4; | ||
| 172 | serialize s p1; | ||
| 173 | serialize s p2 | ||
| 174 | | Record (l,p) -> | ||
| 175 | Serialize.Put.bits 3 s 5; | ||
| 176 | LabelPool.serialize s l; | ||
| 177 | serialize s p | ||
| 178 | | Capture x -> | ||
| 179 | Serialize.Put.bits 3 s 6; | ||
| 180 | Id.serialize s x | ||
| 181 | | Constant (x,c) -> | ||
| 182 | Serialize.Put.bits 3 s 7; | ||
| 183 | Id.serialize s x; | ||
| 184 | Types.Const.serialize s c | ||
| 185 | | Dummy -> assert false | ||
| 186 | |||
| 187 | module DMemo = Map.Make(Custom.Int) | ||
| 188 | let memo = Serialize.Get.mk_property (fun t -> ref DMemo.empty) | ||
| 189 | let rec deserialize t = | ||
| 190 | let l = Serialize.Get.get_property memo t in | ||
| 191 | let id = Serialize.Get.int t in | ||
| 192 | try DMemo.find id !l | ||
| 193 | with Not_found -> | ||
| 194 | let accept = Types.Node.deserialize t in | ||
| 195 | let fv = IdSet.deserialize t in | ||
| 196 | incr counter; | ||
| 197 | abate | 1107 | let n = { id = !counter; descr = dummy; accept = accept; fv = fv } in |
| 198 | abate | 691 | l := DMemo.add id n !l; |
| 199 | n.descr <- deserialize_descr t; | ||
| 200 | n | ||
| 201 | and deserialize_descr s = | ||
| 202 | match Serialize.Get.bits 3 s with | ||
| 203 | | 0 -> constr (Types.deserialize s) | ||
| 204 | | 1 -> | ||
| 205 | (* Avoid unnecessary tests *) | ||
| 206 | let (acc1,fv1,_) as x1 = deserialize_descr s in | ||
| 207 | let (acc2,fv2,_) as x2 = deserialize_descr s in | ||
| 208 | (Types.cup acc1 acc2, IdSet.cup fv1 fv2, Cup (x1,x2)) | ||
| 209 | | 2 -> | ||
| 210 | let (acc1,fv1,_) as x1 = deserialize_descr s in | ||
| 211 | let (acc2,fv2,_) as x2 = deserialize_descr s in | ||
| 212 | (Types.cap acc1 acc2, IdSet.cup fv1 fv2, Cap (x1,x2)) | ||
| 213 | | 3 -> | ||
| 214 | let x = deserialize s in | ||
| 215 | let y = deserialize s in | ||
| 216 | times x y | ||
| 217 | | 4 -> | ||
| 218 | let x = deserialize s in | ||
| 219 | let y = deserialize s in | ||
| 220 | xml x y | ||
| 221 | | 5 -> | ||
| 222 | let l = LabelPool.deserialize s in | ||
| 223 | let x = deserialize s in | ||
| 224 | record l x | ||
| 225 | | 6 -> capture (Id.deserialize s) | ||
| 226 | | 7 -> | ||
| 227 | let x = Id.deserialize s in | ||
| 228 | let c = Types.Const.deserialize s in | ||
| 229 | constant x c | ||
| 230 | | _ -> assert false | ||
| 231 | |||
| 232 | |||
| 233 | end | ||
| 234 | |||
| 235 | abate | 1350 | (* Pretty-print *) |
| 236 | abate | 691 | |
| 237 | abate | 1352 | module Pat = struct |
| 238 | abate | 1350 | type t = descr |
| 239 | abate | 1358 | let rec compare (_,_,d1) (_,_,d2) = if d1 == d2 then 0 else |
| 240 | abate | 1350 | match (d1,d2) with |
| 241 | | Constr t1, Constr t2 -> Types.compare t1 t2 | ||
| 242 | | Constr _, _ -> -1 | _, Constr _ -> 1 | ||
| 243 | |||
| 244 | | Cup (x1,y1), Cup (x2,y2) | Cap (x1,y1), Cap (x2,y2) -> | ||
| 245 | let c = compare x1 x2 in if c <> 0 then c | ||
| 246 | else compare y1 y2 | ||
| 247 | | Cup _, _ -> -1 | _, Cup _ -> 1 | ||
| 248 | | Cap _, _ -> -1 | _, Cap _ -> 1 | ||
| 249 | |||
| 250 | | Times (x1,y1), Times (x2,y2) | Xml (x1,y1), Xml (x2,y2) -> | ||
| 251 | let c = Node.compare x1 x2 in if c <> 0 then c | ||
| 252 | else Node.compare y1 y2 | ||
| 253 | | Times _, _ -> -1 | _, Times _ -> 1 | ||
| 254 | | Xml _, _ -> -1 | _, Xml _ -> 1 | ||
| 255 | |||
| 256 | | Record (x1,y1), Record (x2,y2) -> | ||
| 257 | let c = LabelPool.compare x1 x2 in if c <> 0 then c | ||
| 258 | else Node.compare y1 y2 | ||
| 259 | | Record _, _ -> -1 | _, Record _ -> 1 | ||
| 260 | |||
| 261 | | Capture x1, Capture x2 -> | ||
| 262 | Id.compare x1 x2 | ||
| 263 | | Capture _, _ -> -1 | _, Capture _ -> 1 | ||
| 264 | |||
| 265 | | Constant (x1,y1), Constant (x2,y2) -> | ||
| 266 | let c = Id.compare x1 x2 in if c <> 0 then c | ||
| 267 | else Types.Const.compare y1 y2 | ||
| 268 | | Constant _, _ -> -1 | _, Constant _ -> 1 | ||
| 269 | |||
| 270 | | Dummy, Dummy -> assert false | ||
| 271 | abate | 1358 | |
| 272 | let equal p1 p2 = compare p1 p2 == 0 | ||
| 273 | |||
| 274 | let rec hash (_,_,d) = match d with | ||
| 275 | | Constr t -> 1 + 17 * (Types.hash t) | ||
| 276 | | Cup (p1,p2) -> 2 + 17 * (hash p1) + 257 * (hash p2) | ||
| 277 | | Cap (p1,p2) -> 3 + 17 * (hash p1) + 257 * (hash p2) | ||
| 278 | | Times (q1,q2) -> 4 + 17 * q1.id + 257 * q2.id | ||
| 279 | | Xml (q1,q2) -> 5 + 17 * q1.id + 257 * q2.id | ||
| 280 | | Record (l,q) -> 6 + 17 * (LabelPool.hash l) + 257 * q.id | ||
| 281 | | Capture x -> 7 + (Id.hash x) | ||
| 282 | | Constant (x,c) -> 8 + 17 * (Id.hash x) + 257 * (Types.Const.hash c) | ||
| 283 | | Dummy -> assert false | ||
| 284 | abate | 1350 | end |
| 285 | |||
| 286 | module Print = struct | ||
| 287 | abate | 1352 | module M = Map.Make(Pat) |
| 288 | module S = Set.Make(Pat) | ||
| 289 | abate | 1350 | |
| 290 | let names = ref M.empty | ||
| 291 | let printed = ref S.empty | ||
| 292 | let toprint = Queue.create () | ||
| 293 | let id = ref 0 | ||
| 294 | |||
| 295 | let rec mark seen ((_,_,d) as p) = | ||
| 296 | if (M.mem p !names) then () | ||
| 297 | else if (S.mem p seen) then | ||
| 298 | (incr id; | ||
| 299 | names := M.add p !id !names; | ||
| 300 | Queue.add p toprint) | ||
| 301 | else | ||
| 302 | let seen = S.add p seen in | ||
| 303 | match d with | ||
| 304 | | Cup (p1,p2) | Cap (p1,p2) -> mark seen p1; mark seen p2 | ||
| 305 | | Times (q1,q2) | Xml (q1,q2) -> mark seen q1.descr; mark seen q2.descr | ||
| 306 | | Record (_,q) -> mark seen q.descr | ||
| 307 | | _ -> () | ||
| 308 | |||
| 309 | let rec print ppf p = | ||
| 310 | try | ||
| 311 | let i = M.find p !names in | ||
| 312 | Format.fprintf ppf "P%i" i | ||
| 313 | with Not_found -> | ||
| 314 | real_print ppf p | ||
| 315 | and real_print ppf (_,_,d) = match d with | ||
| 316 | | Constr t -> | ||
| 317 | Types.Print.print ppf t | ||
| 318 | | Cup (p1,p2) -> | ||
| 319 | Format.fprintf ppf "(%a | %a)" print p1 print p2 | ||
| 320 | | Cap (p1,p2) -> | ||
| 321 | Format.fprintf ppf "(%a & %a)" print p1 print p2 | ||
| 322 | | Times (q1,q2) -> | ||
| 323 | Format.fprintf ppf "(%a,%a)" print q1.descr print q2.descr | ||
| 324 | | Xml (q1,{ descr = (_,_,Times(q2,q3)) }) -> | ||
| 325 | Format.fprintf ppf "<(%a) (%a)>(%a)" print q1.descr print q2.descr print q2.descr | ||
| 326 | | Xml _ -> assert false | ||
| 327 | | Record (l,q) -> | ||
| 328 | Format.fprintf ppf "{%a=%a}" Label.print (LabelPool.value l) print q.descr | ||
| 329 | | Capture x -> | ||
| 330 | Format.fprintf ppf "%a" Ident.print x | ||
| 331 | | Constant (x,c) -> | ||
| 332 | Format.fprintf ppf "(%a:=%a)" Ident.print x Types.Print.print_const c | ||
| 333 | | Dummy -> assert false | ||
| 334 | |||
| 335 | let print ppf p = | ||
| 336 | mark S.empty p; | ||
| 337 | print ppf p; | ||
| 338 | let first = ref true in | ||
| 339 | (try while true do | ||
| 340 | let p = Queue.pop toprint in | ||
| 341 | if not (S.mem p !printed) then | ||
| 342 | ( printed := S.add p !printed; | ||
| 343 | Format.fprintf ppf " %s@ @[%a=%a@]" | ||
| 344 | (if !first then (first := false; "where") else "and") | ||
| 345 | print p | ||
| 346 | real_print p | ||
| 347 | ); | ||
| 348 | done with Queue.Empty -> ()); | ||
| 349 | id := 0; | ||
| 350 | names := M.empty; | ||
| 351 | printed := S.empty | ||
| 352 | abate | 1355 | |
| 353 | |||
| 354 | let print_xs ppf xs = | ||
| 355 | Format.fprintf ppf "{"; | ||
| 356 | let rec aux = function | ||
| 357 | | [] -> () | ||
| 358 | | [x] -> Ident.print ppf x | ||
| 359 | | x::q -> Ident.print ppf x; Format.fprintf ppf ","; aux q | ||
| 360 | in | ||
| 361 | aux xs; | ||
| 362 | Format.fprintf ppf "}" | ||
| 363 | abate | 1350 | end |
| 364 | |||
| 365 | |||
| 366 | |||
| 367 | abate | 1 | (* Static semantics *) |
| 368 | |||
| 369 | let cup_res v1 v2 = Types.Positive.cup [v1;v2] | ||
| 370 | abate | 225 | let empty_res fv = IdMap.constant (Types.Positive.ty Types.empty) fv |
| 371 | abate | 1 | let times_res v1 v2 = Types.Positive.times v1 v2 |
| 372 | |||
| 373 | abate | 271 | (* Try with a hash-table *) |
| 374 | abate | 1 | module MemoFilter = Map.Make |
| 375 | abate | 271 | (struct |
| 376 | abate | 653 | type t = Types.t * node |
| 377 | abate | 271 | let compare (t1,n1) (t2,n2) = |
| 378 | if n1.id < n2.id then -1 else if n1.id > n2.id then 1 else | ||
| 379 | abate | 653 | Types.compare t1 t2 |
| 380 | abate | 271 | end) |
| 381 | abate | 1 | |
| 382 | let memo_filter = ref MemoFilter.empty | ||
| 383 | |||
| 384 | abate | 225 | let rec filter_descr t (_,fv,d) : Types.Positive.v id_map = |
| 385 | abate | 121 | (* TODO: avoid is_empty t when t is not changing (Cap) *) |
| 386 | abate | 1 | if Types.is_empty t |
| 387 | then empty_res fv | ||
| 388 | else | ||
| 389 | match d with | ||
| 390 | abate | 225 | | Constr _ -> IdMap.empty |
| 391 | abate | 1 | | Cup ((a,_,_) as d1,d2) -> |
| 392 | abate | 225 | IdMap.merge cup_res |
| 393 | abate | 1 | (filter_descr (Types.cap t a) d1) |
| 394 | (filter_descr (Types.diff t a) d2) | ||
| 395 | abate | 121 | | Cap (d1,d2) -> |
| 396 | abate | 225 | IdMap.merge cup_res (filter_descr t d1) (filter_descr t d2) |
| 397 | abate | 110 | | Times (p1,p2) -> filter_prod fv p1 p2 t |
| 398 | | Xml (p1,p2) -> filter_prod ~kind:`XML fv p1 p2 t | ||
| 399 | abate | 1 | | Record (l,p) -> |
| 400 | filter_node (Types.Record.project t l) p | ||
| 401 | | Capture c -> | ||
| 402 | abate | 225 | IdMap.singleton c (Types.Positive.ty t) |
| 403 | abate | 1 | | Constant (c, cst) -> |
| 404 | abate | 225 | IdMap.singleton c (Types.Positive.ty (Types.constant cst)) |
| 405 | abate | 691 | | Dummy -> assert false |
| 406 | abate | 1 | |
| 407 | abate | 110 | and filter_prod ?kind fv p1 p2 t = |
| 408 | List.fold_left | ||
| 409 | (fun accu (d1,d2) -> | ||
| 410 | let term = | ||
| 411 | abate | 225 | IdMap.merge times_res (filter_node d1 p1) (filter_node d2 p2) |
| 412 | abate | 110 | in |
| 413 | abate | 225 | IdMap.merge cup_res accu term |
| 414 | abate | 110 | ) |
| 415 | (empty_res fv) | ||
| 416 | (Types.Product.normal ?kind t) | ||
| 417 | |||
| 418 | |||
| 419 | abate | 225 | and filter_node t p : Types.Positive.v id_map = |
| 420 | abate | 1 | try MemoFilter.find (t,p) !memo_filter |
| 421 | with Not_found -> | ||
| 422 | let (_,fv,_) as d = descr p in | ||
| 423 | abate | 225 | let res = IdMap.map_from_slist (fun _ -> Types.Positive.forward ()) fv in |
| 424 | abate | 1 | memo_filter := MemoFilter.add (t,p) res !memo_filter; |
| 425 | let r = filter_descr t (descr p) in | ||
| 426 | abate | 225 | IdMap.collide Types.Positive.define res r; |
| 427 | abate | 1 | r |
| 428 | |||
| 429 | let filter t p = | ||
| 430 | let r = filter_node t p in | ||
| 431 | memo_filter := MemoFilter.empty; | ||
| 432 | abate | 225 | IdMap.get (IdMap.map Types.Positive.solve r) |
| 433 | abate | 1 | |
| 434 | abate | 1354 | let filter_descr t p = |
| 435 | let r = filter_descr t p in | ||
| 436 | memo_filter := MemoFilter.empty; | ||
| 437 | IdMap.get (IdMap.map Types.Positive.solve r) | ||
| 438 | abate | 1 | |
| 439 | abate | 1354 | |
| 440 | abate | 1 | (* Normal forms for patterns and compilation *) |
| 441 | |||
| 442 | abate | 229 | let min (a:int) (b:int) = if a < b then a else b |
| 443 | |||
| 444 | abate | 407 | let any_basic = Types.Record.or_absent Types.non_constructed |
| 445 | |||
| 446 | |||
| 447 | abate | 653 | module Normal = struct |
| 448 | abate | 149 | |
| 449 | abate | 1 | type source = |
| 450 | abate | 172 | | SCatch | SConst of Types.const |
| 451 | | SLeft | SRight | SRecompose | ||
| 452 | abate | 225 | type result = source id_map |
| 453 | abate | 1 | |
| 454 | abate | 271 | let compare_source s1 s2 = |
| 455 | if s1 == s2 then 0 | ||
| 456 | else match (s1,s2) with | ||
| 457 | | SCatch, _ -> -1 | _, SCatch -> 1 | ||
| 458 | | SLeft, _ -> -1 | _, SLeft -> 1 | ||
| 459 | | SRight, _ -> -1 | _, SRight -> 1 | ||
| 460 | | SRecompose, _ -> -1 | _, SRecompose -> 1 | ||
| 461 | abate | 691 | | SConst c1, SConst c2 -> Types.Const.compare c1 c2 |
| 462 | abate | 271 | |
| 463 | let hash_source = function | ||
| 464 | | SCatch -> 1 | ||
| 465 | | SLeft -> 2 | ||
| 466 | | SRight -> 3 | ||
| 467 | | SRecompose -> 4 | ||
| 468 | abate | 691 | | SConst c -> Types.Const.hash c |
| 469 | abate | 271 | |
| 470 | let compare_result r1 r2 = | ||
| 471 | IdMap.compare compare_source r1 r2 | ||
| 472 | |||
| 473 | let hash_result r = | ||
| 474 | IdMap.hash hash_source r | ||
| 475 | |||
| 476 | |||
| 477 | abate | 1349 | let print_result ppf r = Format.fprintf ppf "<result>" |
| 478 | let print_result_option ppf = function | ||
| 479 | | Some x -> Format.fprintf ppf "Some(%a)" print_result x | ||
| 480 | | None -> Format.fprintf ppf "None" | ||
| 481 | |||
| 482 | abate | 271 | module NodeSet = |
| 483 | abate | 653 | SortedList.Make(Node) |
| 484 | abate | 271 | |
| 485 | |||
| 486 | abate | 653 | type nnf = NodeSet.t * Types.t (* pl,t; t <= \accept{pl} *) |
| 487 | |||
| 488 | abate | 1349 | let check_nnf (pl,t) = |
| 489 | List.iter (fun p -> assert(Types.subtype t (Types.descr p.accept))) | ||
| 490 | (NodeSet.get pl) | ||
| 491 | |||
| 492 | let print_nnf ppf (pl,t) = | ||
| 493 | Format.fprintf ppf "@[(pl=%a;t=%a)@]" NodeSet.dump pl Types.Print.print t | ||
| 494 | |||
| 495 | |||
| 496 | abate | 271 | let compare_nnf (l1,t1) (l2,t2) = |
| 497 | let c = NodeSet.compare l1 l2 in if c <> 0 then c | ||
| 498 | abate | 653 | else Types.compare t1 t2 |
| 499 | abate | 271 | |
| 500 | let hash_nnf (l,t) = | ||
| 501 | abate | 653 | (NodeSet.hash l) + 17 * (Types.hash t) |
| 502 | abate | 271 | |
| 503 | module NLineBasic = | ||
| 504 | SortedList.Make( | ||
| 505 | struct | ||
| 506 | abate | 653 | include Custom.Dummy |
| 507 | abate | 698 | let serialize s _ = failwith "Patterns.NLineBasic.serialize" |
| 508 | abate | 653 | type t = result * Types.t |
| 509 | abate | 271 | let compare (r1,t1) (r2,t2) = |
| 510 | let c = compare_result r1 r2 in if c <> 0 then c | ||
| 511 | abate | 653 | else Types.compare t1 t2 |
| 512 | abate | 310 | let equal x y = compare x y == 0 |
| 513 | abate | 653 | let hash (r,t) = hash_result r + 17 * Types.hash t |
| 514 | abate | 271 | end |
| 515 | ) | ||
| 516 | |||
| 517 | module NLineProd = | ||
| 518 | SortedList.Make( | ||
| 519 | struct | ||
| 520 | abate | 1349 | (* include Custom.Dummy*) |
| 521 | abate | 698 | let serialize s _ = failwith "Patterns.NLineProd.serialize" |
| 522 | abate | 1349 | let deserialize s = failwith "Patterns.NLineProd.deserialize" |
| 523 | let check x = () | ||
| 524 | let dump ppf (r,x,y) = | ||
| 525 | Format.fprintf ppf "@[(result=%a;x=%a;y=%a)@]" | ||
| 526 | print_result r | ||
| 527 | print_nnf x | ||
| 528 | print_nnf y | ||
| 529 | abate | 653 | type t = result * nnf * nnf |
| 530 | abate | 271 | let compare (r1,x1,y1) (r2,x2,y2) = |
| 531 | let c = compare_result r1 r2 in if c <> 0 then c | ||
| 532 | else let c = compare_nnf x1 x2 in if c <> 0 then c | ||
| 533 | else compare_nnf y1 y2 | ||
| 534 | abate | 310 | let equal x y = compare x y == 0 |
| 535 | abate | 271 | let hash (r,x,y) = |
| 536 | hash_result r + 17 * (hash_nnf x) + 267 * (hash_nnf y) | ||
| 537 | end | ||
| 538 | ) | ||
| 539 | |||
| 540 | abate | 39 | type record = |
| 541 | abate | 230 | | RecNolabel of result option * result option |
| 542 | abate | 653 | | RecLabel of label * NLineProd.t |
| 543 | abate | 43 | type t = { |
| 544 | abate | 42 | nfv : fv; |
| 545 | abate | 57 | ncatchv: fv; |
| 546 | abate | 653 | na : Types.t; |
| 547 | nbasic : NLineBasic.t; | ||
| 548 | nprod : NLineProd.t; | ||
| 549 | nxml : NLineProd.t; | ||
| 550 | abate | 229 | nrecord: record |
| 551 | abate | 39 | } |
| 552 | |||
| 553 | abate | 1349 | let print_record ppf = function |
| 554 | | RecLabel (lab,l) -> | ||
| 555 | Format.fprintf ppf "RecLabel(@[%a@],@ @[%a@])" | ||
| 556 | Label.print (LabelPool.value lab) | ||
| 557 | NLineProd.dump l | ||
| 558 | | RecNolabel (a,b) -> | ||
| 559 | Format.fprintf ppf "RecNolabel(@[%a@],@[%a@])" | ||
| 560 | print_result_option a | ||
| 561 | print_result_option b | ||
| 562 | let print ppf nf = | ||
| 563 | Format.fprintf ppf "@[NF{na=%a;@[nrecord=@ @[%a@]@]}@]" | ||
| 564 | Types.Print.print nf.na | ||
| 565 | print_record nf.nrecord | ||
| 566 | |||
| 567 | |||
| 568 | abate | 271 | let compare_nf t1 t2 = |
| 569 | if t1 == t2 then 0 | ||
| 570 | else | ||
| 571 | (* TODO: reorder; remove comparison of nfv ? *) | ||
| 572 | let c = IdSet.compare t1.nfv t2.nfv in if c <> 0 then c | ||
| 573 | else let c = IdSet.compare t1.ncatchv t2.ncatchv in if c <> 0 then c | ||
| 574 | abate | 653 | else let c = Types.compare t1.na t2.na in if c <> 0 then c |
| 575 | abate | 271 | else let c = NLineBasic.compare t1.nbasic t2.nbasic in if c <> 0 then c |
| 576 | else let c = NLineProd.compare t1.nprod t2.nprod in if c <> 0 then c | ||
| 577 | else let c = NLineProd.compare t1.nxml t2.nxml in if c <> 0 then c | ||
| 578 | else match t1.nrecord, t2.nrecord with | ||
| 579 | | RecNolabel (s1,n1), RecNolabel (s2,n2) -> | ||
| 580 | let c = match (s1,s2) with | ||
| 581 | | None,None -> 0 | ||
| 582 | | Some r1, Some r2 -> compare_result r1 r2 | ||
| 583 | | None, _ -> -1 | ||
| 584 | | _, None -> 1 in | ||
| 585 | if c <> 0 then c | ||
| 586 | else (match (n1,n2) with | ||
| 587 | | None,None -> 0 | ||
| 588 | | Some r1, Some r2 -> compare_result r1 r2 | ||
| 589 | | None, _ -> -1 | ||
| 590 | | _, None -> 1) | ||
| 591 | | RecNolabel (_,_), _ -> -1 | ||
| 592 | | _, RecNolabel (_,_) -> 1 | ||
| 593 | | RecLabel (l1,p1), RecLabel (l2,p2) -> | ||
| 594 | let c = LabelPool.compare l1 l2 in if c <> 0 then c | ||
| 595 | else NLineProd.compare p1 p2 | ||
| 596 | abate | 172 | |
| 597 | abate | 225 | let fus = IdMap.union_disj |
| 598 | abate | 172 | |
| 599 | abate | 229 | let nempty lab = |
| 600 | { nfv = IdSet.empty; ncatchv = IdSet.empty; | ||
| 601 | na = Types.empty; | ||
| 602 | abate | 271 | nbasic = NLineBasic.empty; |
| 603 | nprod = NLineProd.empty; | ||
| 604 | nxml = NLineProd.empty; | ||
| 605 | abate | 229 | nrecord = (match lab with |
| 606 | abate | 271 | | Some l -> RecLabel (l,NLineProd.empty) |
| 607 | abate | 230 | | None -> RecNolabel (None,None)) |
| 608 | abate | 229 | } |
| 609 | abate | 281 | let dummy = nempty None |
| 610 | abate | 149 | |
| 611 | |||
| 612 | let ncup nf1 nf2 = | ||
| 613 | (* assert (Types.is_empty (Types.cap nf1.na nf2.na)); *) | ||
| 614 | (* assert (nf1.nfv = nf2.nfv); *) | ||
| 615 | { nfv = nf1.nfv; | ||
| 616 | abate | 225 | ncatchv = IdSet.cap nf1.ncatchv nf2.ncatchv; |
| 617 | abate | 149 | na = Types.cup nf1.na nf2.na; |
| 618 | abate | 271 | nbasic = NLineBasic.cup nf1.nbasic nf2.nbasic; |
| 619 | nprod = NLineProd.cup nf1.nprod nf2.nprod; | ||
| 620 | nxml = NLineProd.cup nf1.nxml nf2.nxml; | ||
| 621 | abate | 229 | nrecord = (match (nf1.nrecord,nf2.nrecord) with |
| 622 | abate | 230 | | RecLabel (l1,r1), RecLabel (l2,r2) -> |
| 623 | abate | 310 | (* assert (l1 = l2); *) RecLabel (l1, NLineProd.cup r1 r2) |
| 624 | abate | 230 | | RecNolabel (x1,y1), RecNolabel (x2,y2) -> |
| 625 | abate | 310 | RecNolabel((if x1 == None then x2 else x1), |
| 626 | (if y1 == None then y2 else y1)) | ||
| 627 | abate | 229 | | _ -> assert false) |
| 628 | abate | 149 | } |
| 629 | |||
| 630 | let double_fold f l1 l2 = | ||
| 631 | abate | 271 | List.fold_left |
| 632 | (fun accu x1 -> List.fold_left (fun accu x2 -> f accu x1 x2) accu l2) | ||
| 633 | [] l1 | ||
| 634 | |||
| 635 | let double_fold_prod f l1 l2 = | ||
| 636 | double_fold f (NLineProd.get l1) (NLineProd.get l2) | ||
| 637 | abate | 149 | |
| 638 | let ncap nf1 nf2 = | ||
| 639 | abate | 271 | let prod accu (res1,(pl1,t1),(ql1,s1)) (res2,(pl2,t2),(ql2,s2)) = |
| 640 | abate | 149 | let t = Types.cap t1 t2 in |
| 641 | if Types.is_empty t then accu else | ||
| 642 | let s = Types.cap s1 s2 in | ||
| 643 | if Types.is_empty s then accu else | ||
| 644 | abate | 271 | (fus res1 res2, (NodeSet.cup pl1 pl2,t),(NodeSet.cup ql1 ql2,s)) |
| 645 | :: accu | ||
| 646 | abate | 149 | in |
| 647 | let basic accu (res1,t1) (res2,t2) = | ||
| 648 | let t = Types.cap t1 t2 in | ||
| 649 | if Types.is_empty t then accu else | ||
| 650 | (fus res1 res2, t) :: accu | ||
| 651 | in | ||
| 652 | abate | 271 | let record r1 r2 = match r1,r2 with |
| 653 | abate | 230 | | RecLabel (l1,r1), RecLabel (l2,r2) -> |
| 654 | abate | 310 | (* assert (l1 = l2); *) |
| 655 | abate | 271 | RecLabel(l1, NLineProd.from_list (double_fold_prod prod r1 r2)) |
| 656 | abate | 230 | | RecNolabel (x1,y1), RecNolabel (x2,y2) -> |
| 657 | abate | 229 | let x = match x1,x2 with |
| 658 | | Some res1, Some res2 -> Some (fus res1 res2) | ||
| 659 | | _ -> None | ||
| 660 | and y = match y1,y2 with | ||
| 661 | | Some res1, Some res2 -> Some (fus res1 res2) | ||
| 662 | | _ -> None in | ||
| 663 | abate | 230 | RecNolabel (x,y) |
| 664 | abate | 229 | | _ -> assert false |
| 665 | abate | 172 | in |
| 666 | abate | 225 | { nfv = IdSet.cup nf1.nfv nf2.nfv; |
| 667 | ncatchv = IdSet.cup nf1.ncatchv nf2.ncatchv; | ||
| 668 | abate | 149 | na = Types.cap nf1.na nf2.na; |
| 669 | abate | 271 | nbasic = NLineBasic.from_list (double_fold basic |
| 670 | (NLineBasic.get nf1.nbasic) | ||
| 671 | (NLineBasic.get nf2.nbasic)); | ||
| 672 | nprod = NLineProd.from_list (double_fold_prod prod nf1.nprod nf2.nprod); | ||
| 673 | nxml = NLineProd.from_list (double_fold_prod prod nf1.nxml nf2.nxml); | ||
| 674 | nrecord = record nf1.nrecord nf2.nrecord; | ||
| 675 | abate | 149 | } |
| 676 | |||
| 677 | abate | 271 | let nnode p = NodeSet.singleton p, Types.descr p.accept |
| 678 | let nc t = NodeSet.empty, t | ||
| 679 | let ncany = nc Types.any | ||
| 680 | |||
| 681 | abate | 225 | let empty_res = IdMap.empty |
| 682 | abate | 172 | |
| 683 | abate | 229 | let ntimes lab acc p q = |
| 684 | abate | 225 | let src_p = IdMap.constant SLeft p.fv |
| 685 | and src_q = IdMap.constant SRight q.fv in | ||
| 686 | let src = IdMap.merge_elem SRecompose src_p src_q in | ||
| 687 | abate | 229 | { nempty lab with |
| 688 | abate | 225 | nfv = IdSet.cup p.fv q.fv; |
| 689 | abate | 149 | na = acc; |
| 690 | abate | 271 | nprod = NLineProd.singleton (src, nnode p, nnode q); |
| 691 | abate | 149 | } |
| 692 | abate | 172 | |
| 693 | abate | 229 | let nxml lab acc p q = |
| 694 | abate | 225 | let src_p = IdMap.constant SLeft p.fv |
| 695 | and src_q = IdMap.constant SRight q.fv in | ||
| 696 | let src = IdMap.merge_elem SRecompose src_p src_q in | ||
| 697 | abate | 229 | { nempty lab with |
| 698 | abate | 225 | nfv = IdSet.cup p.fv q.fv; |
| 699 | abate | 172 | na = acc; |
| 700 | abate | 271 | nxml = NLineProd.singleton (src, nnode p, nnode q); |
| 701 | abate | 172 | } |
| 702 | abate | 149 | |
| 703 | abate | 229 | let nrecord lab acc l p = |
| 704 | match lab with | ||
| 705 | | None -> assert false | ||
| 706 | | Some label -> | ||
| 707 | assert (label <= l); | ||
| 708 | if l == label then | ||
| 709 | let src = IdMap.constant SLeft p.fv in | ||
| 710 | { nempty lab with | ||
| 711 | nfv = p.fv; | ||
| 712 | na = acc; | ||
| 713 | abate | 230 | nrecord = RecLabel(label, |
| 714 | abate | 271 | NLineProd.singleton (src,nnode p, ncany))} |
| 715 | abate | 229 | else |
| 716 | let src = IdMap.constant SRight p.fv in | ||
| 717 | let p' = make p.fv in (* optimize this ... *) | ||
| 718 | (* cache the results to avoid looping ... *) | ||
| 719 | define p' (record l p); | ||
| 720 | { nempty lab with | ||
| 721 | nfv = p.fv; | ||
| 722 | na = acc; | ||
| 723 | abate | 271 | nrecord = |
| 724 | RecLabel(label, | ||
| 725 | NLineProd.singleton(src,nc Types.Record.any_or_absent, | ||
| 726 | nnode p') )} | ||
| 727 | abate | 229 | |
| 728 | abate | 149 | |
| 729 | abate | 229 | let nconstr lab t = |
| 730 | abate | 271 | let aux l = NLineProd.from_list |
| 731 | (List.map (fun (t1,t2) -> empty_res, nc t1,nc t2) l) in | ||
| 732 | abate | 229 | let record = |
| 733 | match lab with | ||
| 734 | | None -> | ||
| 735 | let (x,y) = Types.Record.empty_cases t in | ||
| 736 | abate | 230 | RecNolabel ((if x then Some empty_res else None), |
| 737 | abate | 229 | (if y then Some empty_res else None)) |
| 738 | | Some l -> | ||
| 739 | abate | 1349 | (* |
| 740 | let ppf = Format.std_formatter in | ||
| 741 | Format.fprintf ppf "Constr record t=%a l=%a@." | ||
| 742 | Types.Print.print t Label.print (LabelPool.value l); | ||
| 743 | let sp = Types.Record.split_normal t l in | ||
| 744 | List.iter (fun (t1,t2) -> | ||
| 745 | Format.fprintf ppf "t1=%a t2=%a@." | ||
| 746 | Types.Print.print t1 | ||
| 747 | Types.Print.print t2) sp; | ||
| 748 | *) | ||
| 749 | abate | 230 | RecLabel (l,aux (Types.Record.split_normal t l)) |
| 750 | abate | 229 | in |
| 751 | { nempty lab with | ||
| 752 | abate | 172 | na = t; |
| 753 | abate | 271 | nbasic = NLineBasic.singleton (empty_res, Types.cap t any_basic); |
| 754 | abate | 229 | nprod = aux (Types.Product.normal t); |
| 755 | nxml = aux (Types.Product.normal ~kind:`XML t); | ||
| 756 | nrecord = record | ||
| 757 | abate | 172 | } |
| 758 | |||
| 759 | abate | 229 | let nconstant lab x c = |
| 760 | abate | 225 | let l = IdMap.singleton x (SConst c) in |
| 761 | { nfv = IdSet.singleton x; | ||
| 762 | ncatchv = IdSet.empty; | ||
| 763 | abate | 172 | na = Types.any; |
| 764 | abate | 271 | nbasic = NLineBasic.singleton (l,any_basic); |
| 765 | nprod = NLineProd.singleton (l,ncany,ncany); | ||
| 766 | nxml = NLineProd.singleton (l,ncany,ncany); | ||
| 767 | abate | 229 | nrecord = match lab with |
| 768 | abate | 230 | | None -> RecNolabel (Some l, Some l) |
| 769 | abate | 229 | | Some lab -> |
| 770 | abate | 271 | RecLabel (lab, NLineProd.singleton |
| 771 | (l,nc Types.Record.any_or_absent, | ||
| 772 | ncany)) | ||
| 773 | abate | 172 | } |
| 774 | |||
| 775 | abate | 229 | let ncapture lab x = |
| 776 | abate | 225 | let l = IdMap.singleton x SCatch in |
| 777 | { nfv = IdSet.singleton x; | ||
| 778 | ncatchv = IdSet.singleton x; | ||
| 779 | abate | 172 | na = Types.any; |
| 780 | abate | 271 | nbasic = NLineBasic.singleton (l,any_basic); |
| 781 | nprod = NLineProd.singleton (l,ncany,ncany); | ||
| 782 | nxml = NLineProd.singleton (l,ncany,ncany); | ||
| 783 | abate | 229 | nrecord = match lab with |
| 784 | abate | 230 | | None -> RecNolabel (Some l, Some l) |
| 785 | abate | 229 | | Some lab -> |
| 786 | abate | 271 | RecLabel (lab, NLineProd.singleton |
| 787 | (l,nc Types.Record.any_or_absent, | ||
| 788 | ncany)) | ||
| 789 | abate | 172 | } |
| 790 | |||
| 791 | abate | 229 | let rec nnormal lab (acc,fv,d) = |
| 792 | abate | 172 | if Types.is_empty acc |
| 793 | abate | 229 | then nempty lab |
| 794 | abate | 172 | else match d with |
| 795 | abate | 229 | | Constr t -> nconstr lab t |
| 796 | | Cap (p,q) -> ncap (nnormal lab p) (nnormal lab q) | ||
| 797 | abate | 172 | | Cup ((acc1,_,_) as p,q) -> |
| 798 | abate | 229 | ncup (nnormal lab p) (ncap (nnormal lab q) |
| 799 | (nconstr lab (Types.neg acc1))) | ||
| 800 | | Times (p,q) -> ntimes lab acc p q | ||
| 801 | | Xml (p,q) -> nxml lab acc p q | ||
| 802 | | Capture x -> ncapture lab x | ||
| 803 | | Constant (x,c) -> nconstant lab x c | ||
| 804 | | Record (l,p) -> nrecord lab acc l p | ||
| 805 | abate | 691 | | Dummy -> assert false |
| 806 | abate | 229 | |
| 807 | (*TODO: when an operand of Cap has its first_label > lab, | ||
| 808 | directly shift it*) | ||
| 809 | |||
| 810 | let rec first_label (acc,fv,d) = | ||
| 811 | if Types.is_empty acc | ||
| 812 | abate | 233 | then LabelPool.dummy_max |
| 813 | abate | 229 | else match d with |
| 814 | | Constr t -> Types.Record.first_label t | ||
| 815 | | Cap (p,q) -> min (first_label p) (first_label q) | ||
| 816 | | Cup ((acc1,_,_) as p,q) -> min (first_label p) (first_label q) | ||
| 817 | (* should "first_label_type acc1" ? *) | ||
| 818 | | Record (l,p) -> l | ||
| 819 | abate | 233 | | _ -> LabelPool.dummy_max |
| 820 | abate | 229 | |
| 821 | abate | 172 | |
| 822 | let remove_catchv n = | ||
| 823 | let ncv = n.ncatchv in | ||
| 824 | abate | 271 | let nlinesbasic l = |
| 825 | NLineBasic.map (fun (res,x) -> (IdMap.diff res ncv,x)) l in | ||
| 826 | let nlinesprod l = | ||
| 827 | NLineProd.map (fun (res,x,y) -> (IdMap.diff res ncv,x,y)) l in | ||
| 828 | abate | 225 | { nfv = IdSet.diff n.nfv ncv; |
| 829 | abate | 172 | ncatchv = n.ncatchv; |
| 830 | na = n.na; | ||
| 831 | abate | 271 | nbasic = nlinesbasic n.nbasic; |
| 832 | nprod = nlinesprod n.nprod; | ||
| 833 | nxml = nlinesprod n.nxml; | ||
| 834 | abate | 229 | nrecord = (match n.nrecord with |
| 835 | abate | 230 | | RecNolabel (x,y) -> |
| 836 | abate | 229 | let x = match x with |
| 837 | | Some res -> Some (IdMap.diff res ncv) | ||
| 838 | | None -> None in | ||
| 839 | let y = match y with | ||
| 840 | | Some res -> Some (IdMap.diff res ncv) | ||
| 841 | | None -> None in | ||
| 842 | abate | 230 | RecNolabel (x,y) |
| 843 | abate | 271 | | RecLabel (lab,l) -> RecLabel (lab, nlinesprod l)) |
| 844 | abate | 172 | } |
| 845 | |||
| 846 | abate | 1349 | let print_node_list ppf pl = |
| 847 | List.iter (fun p -> Format.fprintf ppf "%a;" Node.dump p) pl | ||
| 848 | |||
| 849 | abate | 229 | let normal l t pl = |
| 850 | abate | 172 | remove_catchv |
| 851 | abate | 229 | (List.fold_left |
| 852 | (fun a p -> ncap a (nnormal l (descr p))) | ||
| 853 | (nconstr l t) | ||
| 854 | pl) | ||
| 855 | abate | 1349 | |
| 856 | (* | ||
| 857 | let normal l t pl = | ||
| 858 | let nf = normal l t pl in | ||
| 859 | (match l with Some l -> | ||
| 860 | Format.fprintf Format.std_formatter | ||
| 861 | "normal(l=%a;t=%a;pl=%a)=%a@." | ||
| 862 | Label.print (LabelPool.value l) | ||
| 863 | Types.Print.print t | ||
| 864 | print_node_list pl | ||
| 865 | print nf | ||
| 866 | | None -> Format.fprintf Format.std_formatter | ||
| 867 | "normal(t=%a;pl=%a)=%a@." | ||
| 868 | Types.Print.print t | ||
| 869 | print_node_list pl | ||
| 870 | print nf); | ||
| 871 | nf | ||
| 872 | *) | ||
| 873 | abate | 43 | end |
| 874 | abate | 42 | |
| 875 | |||
| 876 | abate | 43 | module Compile = |
| 877 | struct | ||
| 878 | abate | 56 | type actions = |
| 879 | abate | 172 | | AIgnore of result |
| 880 | | AKind of actions_kind | ||
| 881 | abate | 56 | and actions_kind = { |
| 882 | abate | 653 | basic: (Types.t * result) list; |
| 883 | abate | 243 | atoms: result Atoms.map; |
| 884 | chars: result Chars.map; | ||
| 885 | abate | 43 | prod: result dispatch dispatch; |
| 886 | abate | 110 | xml: result dispatch dispatch; |
| 887 | abate | 43 | record: record option; |
| 888 | } | ||
| 889 | and record = | ||
| 890 | abate | 233 | | RecLabel of label * result dispatch dispatch |
| 891 | abate | 230 | | RecNolabel of result option * result option |
| 892 | abate | 42 | |
| 893 | abate | 45 | and 'a dispatch = |
| 894 | abate | 172 | | Dispatch of dispatcher * 'a array |
| 895 | | TailCall of dispatcher | ||
| 896 | | Ignore of 'a | ||
| 897 | | Impossible | ||
| 898 | abate | 45 | |
| 899 | and result = int * source array | ||
| 900 | abate | 43 | and source = |
| 901 | abate | 172 | | Catch | Const of Types.const |
| 902 | | Left of int | Right of int | Recompose of int * int | ||
| 903 | abate | 43 | |
| 904 | and return_code = | ||
| 905 | abate | 653 | Types.t * int * (* accepted type, arity *) |
| 906 | abate | 225 | (int * int id_map) list |
| 907 | abate | 42 | |
| 908 | abate | 43 | and interface = |
| 909 | abate | 147 | [ `Result of int |
| 910 | | `Switch of interface * interface | ||
| 911 | abate | 43 | | `None ] |
| 912 | abate | 42 | |
| 913 | abate | 43 | and dispatcher = { |
| 914 | id : int; | ||
| 915 | abate | 653 | t : Types.t; |
| 916 | abate | 43 | pl : Normal.t array; |
| 917 | abate | 233 | label : label option; |
| 918 | abate | 43 | interface : interface; |
| 919 | codes : return_code array; | ||
| 920 | abate | 226 | mutable actions : actions option; |
| 921 | mutable printed : bool | ||
| 922 | abate | 43 | } |
| 923 | abate | 45 | |
| 924 | abate | 310 | let equal_array f a1 a2 = |
| 925 | let rec aux i = (i < 0) || ((f a1.(i) a2.(i)) && (aux (i - 1))) in | ||
| 926 | let l1 = Array.length a1 and l2 = Array.length a2 in | ||
| 927 | (l1 == l2) && (aux (l1 - 1)) | ||
| 928 | |||
| 929 | let equal_source s1 s2 = | ||
| 930 | (s1 == s2) || match (s1,s2) with | ||
| 931 | abate | 691 | | Const x, Const y -> Types.Const.equal x y |
| 932 | abate | 310 | | Left x, Left y -> x == y |
| 933 | | Right x, Right y -> x == y | ||
| 934 | | Recompose (x1,x2), Recompose (y1,y2) -> (x1 == y1) && (x2 == y2) | ||
| 935 | | _ -> false | ||
| 936 | |||
| 937 | let equal_result (r1,s1) (r2,s2) = | ||
| 938 | (r1 == r2) && (equal_array equal_source s1 s2) | ||
| 939 | |||
| 940 | let equal_result_dispatch d1 d2 = | ||
| 941 | (d1 == d2) || match (d1,d2) with | ||
| 942 | | Dispatch (d1,a1), Dispatch (d2,a2) -> (d1 == d2) && (equal_array equal_result a1 a2) | ||
| 943 | | TailCall d1, TailCall d2 -> d1 == d2 | ||
| 944 | | Ignore a1, Ignore a2 -> equal_result a1 a2 | ||
| 945 | | _ -> false | ||
| 946 | |||
| 947 | |||
| 948 | abate | 45 | let array_for_all f a = |
| 949 | let rec aux f a i = | ||
| 950 | abate | 310 | if i == Array.length a then true |
| 951 | abate | 45 | else f a.(i) && (aux f a (succ i)) |
| 952 | in | ||
| 953 | aux f a 0 | ||
| 954 | |||
| 955 | let array_for_all_i f a = | ||
| 956 | let rec aux f a i = | ||
| 957 | abate | 310 | if i == Array.length a then true |
| 958 | abate | 45 | else f i a.(i) && (aux f a (succ i)) |
| 959 | in | ||
| 960 | aux f a 0 | ||
| 961 | |||
| 962 | abate | 110 | let combine_kind basic prod xml record = |
| 963 | abate | 56 | try ( |
| 964 | let rs = [] in | ||
| 965 | let rs = match basic with | ||
| 966 | | [_,r] -> r :: rs | ||
| 967 | | [] -> rs | ||
| 968 | | _ -> raise Exit in | ||
| 969 | let rs = match prod with | ||
| 970 | abate | 172 | | Impossible -> rs |
| 971 | | Ignore (Ignore r) -> r :: rs | ||
| 972 | abate | 56 | | _ -> raise Exit in |
| 973 | abate | 110 | let rs = match xml with |
| 974 | abate | 172 | | Impossible -> rs |
| 975 | | Ignore (Ignore r) -> r :: rs | ||
| 976 | abate | 110 | | _ -> raise Exit in |
| 977 | abate | 56 | let rs = match record with |
| 978 | | None -> rs | ||
| 979 | abate | 230 | | Some (RecLabel (_,Ignore (Ignore r))) -> r :: rs |
| 980 | | Some (RecNolabel (Some r1, Some r2)) -> r1 :: r2 :: rs | ||
| 981 | abate | 56 | | _ -> raise Exit in |
| 982 | match rs with | ||
| 983 | abate | 57 | | ((_, ret) as r) :: rs when |
| 984 | abate | 310 | List.for_all ( equal_result r ) rs |
| 985 | abate | 57 | && array_for_all |
| 986 | abate | 172 | (function Catch | Const _ -> true | _ -> false) ret |
| 987 | -> AIgnore r | ||
| 988 | abate | 56 | | _ -> raise Exit |
| 989 | ) | ||
| 990 | abate | 243 | with Exit -> |
| 991 | AKind | ||
| 992 | { basic = basic; | ||
| 993 | atoms = | ||
| 994 | abate | 956 | Atoms.mk_map (List.map (fun (t,r) -> Types.Atom.get t, r) basic); |
| 995 | abate | 243 | chars = |
| 996 | abate | 956 | Chars.mk_map (List.map (fun (t,r) -> Types.Char.get t, r) basic); |
| 997 | abate | 243 | prod = prod; |
| 998 | xml = xml; | ||
| 999 | abate | 956 | record = record; |
| 1000 | } | ||
| 1001 | abate | 243 | |
| 1002 | abate | 310 | let combine f (disp,act) = |
| 1003 | if Array.length act == 0 then Impossible | ||
| 1004 | abate | 45 | else |
| 1005 | abate | 310 | if (array_for_all (fun (_,ar,_) -> ar == 0) disp.codes) |
| 1006 | && (array_for_all ( f act.(0) ) act) then | ||
| 1007 | abate | 172 | Ignore act.(0) |
| 1008 | abate | 45 | else |
| 1009 | abate | 172 | Dispatch (disp, act) |
| 1010 | abate | 45 | |
| 1011 | |||
| 1012 | let detect_right_tail_call = function | ||
| 1013 | abate | 172 | | Dispatch (disp,branches) |
| 1014 | abate | 45 | when |
| 1015 | array_for_all_i | ||
| 1016 | (fun i (code,ret) -> | ||
| 1017 | abate | 310 | (i == code) && |
| 1018 | abate | 45 | (array_for_all_i |
| 1019 | (fun pos -> | ||
| 1020 | abate | 310 | function Right j when pos == j -> true | _ -> false) |
| 1021 | abate | 45 | ret |
| 1022 | ) | ||
| 1023 | ) branches | ||
| 1024 | abate | 172 | -> TailCall disp |
| 1025 | abate | 45 | | x -> x |
| 1026 | |||
| 1027 | let detect_left_tail_call = function | ||
| 1028 | abate | 172 | | Dispatch (disp,branches) |
| 1029 | abate | 45 | when |
| 1030 | array_for_all_i | ||
| 1031 | (fun i -> | ||
| 1032 | function | ||
| 1033 | abate | 172 | | Ignore (code,ret) -> |
| 1034 | abate | 310 | (i == code) && |
| 1035 | abate | 45 | (array_for_all_i |
| 1036 | (fun pos -> | ||
| 1037 | abate | 310 | function Left j when pos == j -> true | _ -> false) |
| 1038 | abate | 45 | ret |
| 1039 | ) | ||
| 1040 | | _ -> false | ||
| 1041 | ) branches | ||
| 1042 | -> | ||
| 1043 | abate | 172 | TailCall disp |
| 1044 | abate | 45 | | x -> x |
| 1045 | |||
| 1046 | abate | 95 | let cur_id = State.ref "Patterns.cur_id" 0 |
| 1047 | (* TODO: save dispatchers ? *) | ||
| 1048 | abate | 43 | |
| 1049 | abate | 281 | module NfMap = Map.Make( |
| 1050 | struct | ||
| 1051 | type t = Normal.t | ||
| 1052 | let compare = Normal.compare_nf | ||
| 1053 | end) | ||
| 1054 | |||
| 1055 | abate | 42 | module DispMap = Map.Make( |
| 1056 | struct | ||
| 1057 | abate | 653 | type t = Types.t * Normal.t array |
| 1058 | abate | 271 | |
| 1059 | let rec compare_rec a1 a2 i = | ||
| 1060 | if i < 0 then 0 | ||
| 1061 | else | ||
| 1062 | let c = Normal.compare_nf a1.(i) a2.(i) in | ||
| 1063 | if c <> 0 then c else compare_rec a1 a2 (i - 1) | ||
| 1064 | |||
| 1065 | let compare (t1,a1) (t2,a2) = | ||
| 1066 | abate | 653 | let c = Types.compare t1 t2 in if c <> 0 then c |
| 1067 | abate | 271 | else let l1 = Array.length a1 and l2 = Array.length a2 in |
| 1068 | if l1 < l2 then -1 else if l1 > l2 then 1 | ||
| 1069 | else compare_rec a1 a2 (l1 - 1) | ||
| 1070 | abate | 42 | end |
| 1071 | ) | ||
| 1072 | abate | 271 | |
| 1073 | (* Try with a hash-table ! *) | ||
| 1074 | abate | 43 | |
| 1075 | abate | 42 | let dispatchers = ref DispMap.empty |
| 1076 | abate | 798 | |
| 1077 | let timer_disp = Stats.Timer.create "Patterns.dispatcher loop" | ||
| 1078 | abate | 1349 | |
| 1079 | let rec print_iface ppf = function | ||
| 1080 | | `Result i -> Format.fprintf ppf "Result(%i)" i | ||
| 1081 | | `Switch (yes,no) -> Format.fprintf ppf "Switch(%a,%a)" | ||
| 1082 | print_iface yes print_iface no | ||
| 1083 | | `None -> Format.fprintf ppf "None" | ||
| 1084 | abate | 798 | |
| 1085 | abate | 229 | let dispatcher t pl lab : dispatcher = |
| 1086 | abate | 42 | try DispMap.find (t,pl) !dispatchers |
| 1087 | with Not_found -> | ||
| 1088 | abate | 1349 | (* let ppf = Format.std_formatter in |
| 1089 | Format.fprintf ppf "dispatcher %i:" !cur_id; | ||
| 1090 | Array.iter (fun x -> Format.fprintf ppf "%a;" Normal.print x) pl; | ||
| 1091 | Format.fprintf ppf "@."; *) | ||
| 1092 | abate | 43 | let nb = ref 0 in |
| 1093 | abate | 147 | let codes = ref [] in |
| 1094 | let rec aux t arity i accu = | ||
| 1095 | abate | 798 | if i == Array.length pl |
| 1096 | then (incr nb; codes := (t,arity,accu)::!codes; `Result (!nb - 1)) | ||
| 1097 | abate | 43 | else |
| 1098 | abate | 798 | let p = pl.(i) in |
| 1099 | let tp = p.Normal.na in | ||
| 1100 | abate | 1349 | (* let tp = Types.normalize tp in *) |
| 1101 | abate | 798 | |
| 1102 | let a1 = Types.cap t tp in | ||
| 1103 | if Types.is_empty a1 then | ||
| 1104 | `Switch (`None,aux t arity (i+1) accu) | ||
| 1105 | abate | 42 | else |
| 1106 | abate | 225 | let v = p.Normal.nfv in |
| 1107 | abate | 798 | let a2 = Types.diff t tp in |
| 1108 | abate | 225 | let accu' = (i,IdMap.num arity v) :: accu in |
| 1109 | abate | 798 | if Types.is_empty a2 then |
| 1110 | `Switch (aux t (arity + (IdSet.length v)) (i+1) accu',`None) | ||
| 1111 | else | ||
| 1112 | `Switch (aux a1 (arity + (IdSet.length v)) (i+1) accu', | ||
| 1113 | aux a2 arity (i+1) accu) | ||
| 1114 | |||
| 1115 | (* Unopt version: | ||
| 1116 | abate | 43 | `Switch |
| 1117 | abate | 147 | ( |
| 1118 | abate | 225 | aux (Types.cap t tp) (arity + (IdSet.length v)) (i+1) accu', |
| 1119 | abate | 147 | aux (Types.diff t tp) arity (i+1) accu |
| 1120 | abate | 43 | ) |
| 1121 | abate | 798 | *) |
| 1122 | |||
| 1123 | abate | 42 | in |
| 1124 | abate | 1349 | (* |
| 1125 | Array.iteri (fun i p -> | ||
| 1126 | abate | 798 | Format.fprintf Format.std_formatter |
| 1127 | "Pattern %i/%i accepts %a@." i (Array.length pl) | ||
| 1128 | abate | 1349 | Types.Print.print p.Normal.na) pl; |
| 1129 | *) | ||
| 1130 | abate | 798 | |
| 1131 | Stats.Timer.start timer_disp; | ||
| 1132 | let iface = | ||
| 1133 | if Types.is_empty t then `None else aux t 0 0 [] in | ||
| 1134 | Stats.Timer.stop timer_disp (); | ||
| 1135 | abate | 1349 | (* Format.fprintf Format.std_formatter "iface=%a@." print_iface iface;*) |
| 1136 | abate | 42 | let res = { id = !cur_id; |
| 1137 | t = t; | ||
| 1138 | abate | 229 | label = lab; |
| 1139 | abate | 42 | pl = pl; |
| 1140 | abate | 43 | interface = iface; |
| 1141 | abate | 147 | codes = Array.of_list (List.rev !codes); |
| 1142 | abate | 226 | actions = None; printed = false } in |
| 1143 | abate | 42 | incr cur_id; |
| 1144 | dispatchers := DispMap.add (t,pl) res !dispatchers; | ||
| 1145 | res | ||
| 1146 | |||
| 1147 | abate | 43 | let find_code d a = |
| 1148 | let rec aux i = function | ||
| 1149 | abate | 147 | | `Result code -> code |
| 1150 | | `None -> assert false | ||
| 1151 | abate | 332 | | `Switch (yes,_) when a.(i) != None -> aux (i + 1) yes |
| 1152 | abate | 147 | | `Switch (_,no) -> aux (i + 1) no |
| 1153 | abate | 43 | in |
| 1154 | abate | 1349 | (* |
| 1155 | let ppf = Format.std_formatter in | ||
| 1156 | Format.fprintf ppf "find_code iface=%a [ " | ||
| 1157 | print_iface d.interface; | ||
| 1158 | for i = 0 to Array.length a - 1 do | ||
| 1159 | if (a.(i) != None) then | ||
| 1160 | Format.fprintf ppf "+ " | ||
| 1161 | else | ||
| 1162 | Format.fprintf ppf "- " | ||
| 1163 | done; | ||
| 1164 | Format.fprintf ppf "]@."; | ||
| 1165 | *) | ||
| 1166 | abate | 43 | aux 0 d.interface |
| 1167 | abate | 42 | |
| 1168 | abate | 43 | let create_result pl = |
| 1169 | abate | 166 | let aux x accu = match x with Some b -> b @ accu | None -> accu in |
| 1170 | Array.of_list (Array.fold_right aux pl []) | ||
| 1171 | abate | 43 | |
| 1172 | let return disp pl f = | ||
| 1173 | let aux = function [x] -> Some (f x) | [] -> None | _ -> assert false in | ||
| 1174 | let final = Array.map aux pl in | ||
| 1175 | (find_code disp final, create_result final) | ||
| 1176 | |||
| 1177 | abate | 225 | let conv_source_basic s = match s with |
| 1178 | abate | 172 | | Normal.SCatch -> Catch |
| 1179 | | Normal.SConst c -> Const c | ||
| 1180 | abate | 42 | | _ -> assert false |
| 1181 | |||
| 1182 | abate | 57 | let assoc v l = |
| 1183 | abate | 225 | try IdMap.assoc v l with Not_found -> -1 |
| 1184 | abate | 57 | |
| 1185 | abate | 225 | let conv_source_prod left right v s = match s with |
| 1186 | abate | 172 | | Normal.SCatch -> Catch |
| 1187 | | Normal.SConst c -> Const c | ||
| 1188 | | Normal.SLeft -> Left (assoc v left) | ||
| 1189 | | Normal.SRight -> Right (assoc v right) | ||
| 1190 | | Normal.SRecompose -> Recompose (assoc v left, assoc v right) | ||
| 1191 | abate | 42 | |
| 1192 | abate | 653 | module TypeList = SortedList.Make(Types) |
| 1193 | let dispatch_basic disp : (Types.t * result) list = | ||
| 1194 | abate | 147 | (* TODO: try other algo, using disp.codes .... *) |
| 1195 | abate | 43 | let pl = Array.map (fun p -> p.Normal.nbasic) disp.pl in |
| 1196 | let tests = | ||
| 1197 | let accu = ref [] in | ||
| 1198 | let aux i (res,x) = accu := (x, [i,res]) :: !accu in | ||
| 1199 | abate | 271 | Array.iteri (fun i -> Normal.NLineBasic.iter (aux i)) pl; |
| 1200 | abate | 653 | TypeList.Map.get (TypeList.Map.from_list (@) !accu) in |
| 1201 | abate | 43 | |
| 1202 | abate | 407 | let t = Types.cap any_basic disp.t in |
| 1203 | abate | 42 | let accu = ref [] in |
| 1204 | abate | 43 | let rec aux (success : (int * Normal.result) list) t l = |
| 1205 | abate | 42 | if Types.non_empty t |
| 1206 | then match l with | ||
| 1207 | | [] -> | ||
| 1208 | abate | 43 | let selected = Array.create (Array.length pl) [] in |
| 1209 | let add (i,res) = selected.(i) <- res :: selected.(i) in | ||
| 1210 | List.iter add success; | ||
| 1211 | |||
| 1212 | abate | 225 | let aux_final res = IdMap.map_to_list conv_source_basic res in |
| 1213 | abate | 43 | accu := (t, return disp selected aux_final) :: !accu |
| 1214 | | (ty,i) :: rem -> | ||
| 1215 | aux (i @ success) (Types.cap t ty) rem; | ||
| 1216 | aux success (Types.diff t ty) rem | ||
| 1217 | abate | 42 | in |
| 1218 | abate | 43 | aux [] t tests; |
| 1219 | abate | 42 | !accu |
| 1220 | |||
| 1221 | |||
| 1222 | abate | 45 | let get_tests pl f t d post = |
| 1223 | abate | 42 | let accu = ref [] in |
| 1224 | let aux i x = | ||
| 1225 | abate | 270 | let (pl,ty), info = f x in |
| 1226 | abate | 271 | let pl = Normal.NodeSet.get pl in |
| 1227 | abate | 270 | accu := (ty,pl,i,info) :: !accu in |
| 1228 | abate | 42 | Array.iteri (fun i -> List.iter (aux i)) pl; |
| 1229 | abate | 52 | |
| 1230 | abate | 229 | let lab = |
| 1231 | List.fold_left | ||
| 1232 | (fun l (ty,pl,_,_) -> | ||
| 1233 | List.fold_left | ||
| 1234 | (fun l p -> min l (Normal.first_label (descr p))) | ||
| 1235 | (min l (Types.Record.first_label ty)) | ||
| 1236 | pl | ||
| 1237 | abate | 233 | ) LabelPool.dummy_max !accu in |
| 1238 | abate | 310 | let lab = if lab == LabelPool.dummy_max then None else Some lab in |
| 1239 | abate | 229 | |
| 1240 | abate | 281 | |
| 1241 | let pats = ref NfMap.empty in | ||
| 1242 | let nb_p = ref 0 in | ||
| 1243 | List.iter | ||
| 1244 | (fun (ty,pl,i,info) -> | ||
| 1245 | let p = Normal.normal lab ty pl in | ||
| 1246 | let x = (i, p.Normal.ncatchv, info) in | ||
| 1247 | try | ||
| 1248 | let s = NfMap.find p !pats in | ||
| 1249 | s := x :: !s | ||
| 1250 | with Not_found -> | ||
| 1251 | pats := NfMap.add p (ref [x]) !pats; | ||
| 1252 | incr nb_p | ||
| 1253 | ) !accu; | ||
| 1254 | let infos = Array.make !nb_p [] in | ||
| 1255 | let ps = Array.make !nb_p Normal.dummy in | ||
| 1256 | let count = ref 0 in | ||
| 1257 | NfMap.iter (fun p l -> | ||
| 1258 | let i = !count in | ||
| 1259 | infos.(i) <- !l; | ||
| 1260 | ps.(i) <- p; | ||
| 1261 | count := succ i) !pats; | ||
| 1262 | abate | 310 | assert( !nb_p == !count ); |
| 1263 | abate | 281 | let disp = dispatcher t ps lab in |
| 1264 | |||
| 1265 | abate | 43 | let result (t,_,m) = |
| 1266 | abate | 1349 | (* Format.fprintf Format.std_formatter "Result=%a@." Types.Print.print t;*) |
| 1267 | abate | 42 | let selected = Array.create (Array.length pl) [] in |
| 1268 | abate | 148 | let add r (i, ncv, inf) = selected.(i) <- (r,ncv,inf) :: selected.(i) in |
| 1269 | abate | 43 | List.iter (fun (j,r) -> List.iter (add r) infos.(j)) m; |
| 1270 | abate | 270 | d t selected |
| 1271 | abate | 42 | in |
| 1272 | abate | 43 | let res = Array.map result disp.codes in |
| 1273 | abate | 46 | post (disp,res) |
| 1274 | abate | 42 | |
| 1275 | abate | 71 | |
| 1276 | abate | 698 | type 'a rhs = Match of (id * int) list * 'a | Fail |
| 1277 | abate | 46 | let make_branches t brs = |
| 1278 | let (_,brs) = | ||
| 1279 | List.fold_left | ||
| 1280 | (fun (t,brs) (p,e) -> | ||
| 1281 | abate | 271 | let p' = (Normal.NodeSet.singleton p,t) in |
| 1282 | abate | 798 | (* let td = Types.descr (accept p) in |
| 1283 | let t' = | ||
| 1284 | if Types.is_empty (Types.cap t td) then t else | ||
| 1285 | Types.diff t td in*) | ||
| 1286 | abate | 148 | let t' = Types.diff t (Types.descr (accept p)) in |
| 1287 | abate | 1107 | (t', (p',(fv p, e)) :: brs) |
| 1288 | abate | 46 | ) (t,[]) brs in |
| 1289 | abate | 52 | |
| 1290 | abate | 46 | let pl = Array.map (fun x -> [x]) (Array.of_list brs) in |
| 1291 | get_tests | ||
| 1292 | pl | ||
| 1293 | abate | 270 | (fun x -> x) |
| 1294 | abate | 46 | t |
| 1295 | abate | 270 | (fun _ pl -> |
| 1296 | abate | 374 | let r = ref Fail in |
| 1297 | abate | 46 | let aux = function |
| 1298 | abate | 698 | | [(res,catchv,(fvl,e))] -> assert (!r == Fail); |
| 1299 | abate | 225 | let catchv = IdMap.constant (-1) catchv in |
| 1300 | abate | 698 | let m = IdMap.union_disj catchv res in |
| 1301 | let m = List.map (fun x -> (x,IdMap.assoc x m)) fvl in | ||
| 1302 | r := Match (m,e) | ||
| 1303 | abate | 46 | | [] -> () | _ -> assert false in |
| 1304 | Array.iter aux pl; | ||
| 1305 | abate | 374 | !r |
| 1306 | abate | 46 | ) |
| 1307 | (fun x -> x) | ||
| 1308 | abate | 42 | |
| 1309 | |||
| 1310 | abate | 110 | let rec dispatch_prod ?(kind=`Normal) disp = |
| 1311 | let pl = | ||
| 1312 | match kind with | ||
| 1313 | abate | 271 | | `Normal -> |
| 1314 | Array.map (fun p -> Normal.NLineProd.get p.Normal.nprod) disp.pl | ||
| 1315 | | `XML -> | ||
| 1316 | Array.map (fun p -> Normal.NLineProd.get p.Normal.nxml) disp.pl | ||
| 1317 | abate | 110 | in |
| 1318 | let t = Types.Product.get ~kind disp.t in | ||
| 1319 | abate | 229 | dispatch_prod0 disp t pl |
| 1320 | and dispatch_prod0 disp t pl = | ||
| 1321 | abate | 42 | get_tests pl |
| 1322 | abate | 271 | (fun (res,p,q) -> p, (res,q)) |
| 1323 | abate | 42 | (Types.Product.pi1 t) |
| 1324 | (dispatch_prod1 disp t) | ||
| 1325 | abate | 310 | (fun x -> detect_left_tail_call (combine equal_result_dispatch x)) |
| 1326 | abate | 270 | and dispatch_prod1 disp t t1 pl = |
| 1327 | abate | 42 | get_tests pl |
| 1328 | abate | 270 | (fun (ret1, ncatchv, (res,q)) -> q, (ret1,res) ) |
| 1329 | abate | 229 | (Types.Product.pi2_restricted t1 t) |
| 1330 | (dispatch_prod2 disp) | ||
| 1331 | abate | 310 | (fun x -> detect_right_tail_call (combine equal_result x)) |
| 1332 | abate | 270 | and dispatch_prod2 disp t2 pl = |
| 1333 | abate | 148 | let aux_final (ret2, ncatchv, (ret1, res)) = |
| 1334 | abate | 225 | IdMap.mapi_to_list (conv_source_prod ret1 ret2) res in |
| 1335 | abate | 43 | return disp pl aux_final |
| 1336 | abate | 42 | |
| 1337 | |||
| 1338 | abate | 1349 | let dispatch_record disp : record option = |
| 1339 | abate | 229 | let t = disp.t in |
| 1340 | if not (Types.Record.has_record t) then None | ||
| 1341 | else | ||
| 1342 | match disp.label with | ||
| 1343 | | None -> | ||
| 1344 | let (some,none) = Types.Record.empty_cases t in | ||
| 1345 | let some = | ||
| 1346 | if some then | ||
| 1347 | let pl = Array.map (fun p -> match p.Normal.nrecord with | ||
| 1348 | abate | 230 | | Normal.RecNolabel (Some x,_) -> [x] |
| 1349 | | Normal.RecNolabel (None,_) -> [] | ||
| 1350 | abate | 229 | | _ -> assert false) disp.pl in |
| 1351 | Some (return disp pl (IdMap.map_to_list conv_source_basic)) | ||
| 1352 | else None | ||
| 1353 | in | ||
| 1354 | let none = | ||
| 1355 | if none then | ||
| 1356 | let pl = Array.map (fun p -> match p.Normal.nrecord with | ||
| 1357 | abate | 230 | | Normal.RecNolabel (_,Some x) -> [x] |
| 1358 | | Normal.RecNolabel (_,None) -> [] | ||
| 1359 | abate | 229 | | _ -> assert false) disp.pl in |
| 1360 | Some (return disp pl (IdMap.map_to_list conv_source_basic)) | ||
| 1361 | else None | ||
| 1362 | in | ||
| 1363 | abate | 230 | Some (RecNolabel (some,none)) |
| 1364 | abate | 229 | | Some lab -> |
| 1365 | abate | 1349 | (* Format.fprintf Format.std_formatter "lab=%a Split:@." Label.print (LabelPool.value lab);*) |
| 1366 | abate | 229 | let t = Types.Record.split t lab in |
| 1367 | abate | 1349 | (* List.iter (fun (t1,t2) -> |
| 1368 | Format.fprintf Format.std_formatter "t1=%a t2=%a@." | ||
| 1369 | Types.Print.print t1 | ||
| 1370 | Types.Print.print t2) t; *) | ||
| 1371 | abate | 229 | let pl = Array.map (fun p -> match p.Normal.nrecord with |
| 1372 | abate | 271 | | Normal.RecLabel (_,l) -> |
| 1373 | Normal.NLineProd.get l | ||
| 1374 | abate | 229 | | _ -> assert false) disp.pl in |
| 1375 | abate | 230 | Some (RecLabel (lab,dispatch_prod0 disp t pl)) |
| 1376 | abate | 229 | (* soucis avec les ncatchv ?? *) |
| 1377 | abate | 119 | |
| 1378 | abate | 75 | |
| 1379 | abate | 42 | let actions disp = |
| 1380 | match disp.actions with | ||
| 1381 | | Some a -> a | ||
| 1382 | | None -> | ||
| 1383 | abate | 56 | let a = combine_kind |
| 1384 | (dispatch_basic disp) | ||
| 1385 | (dispatch_prod disp) | ||
| 1386 | abate | 110 | (dispatch_prod ~kind:`XML disp) |
| 1387 | abate | 56 | (dispatch_record disp) |
| 1388 | in | ||
| 1389 | abate | 42 | disp.actions <- Some a; |
| 1390 | a | ||
| 1391 | |||
| 1392 | let to_print = ref [] | ||
| 1393 | |||
| 1394 | abate | 226 | module DSET = Set.Make (struct type t = int let compare (x:t) (y:t) = x - y end) |
| 1395 | let printed = ref DSET.empty | ||
| 1396 | |||
| 1397 | abate | 42 | let queue d = |
| 1398 | abate | 226 | if not d.printed then ( |
| 1399 | d.printed <- true; | ||
| 1400 | abate | 42 | to_print := d :: !to_print |
| 1401 | ) | ||
| 1402 | |||
| 1403 | abate | 57 | let rec print_source ppf = function |
| 1404 | abate | 172 | | Catch -> Format.fprintf ppf "v" |
| 1405 | | Const c -> Types.Print.print_const ppf c | ||
| 1406 | | Left (-1) -> Format.fprintf ppf "v1" | ||
| 1407 | | Right (-1) -> Format.fprintf ppf "v2" | ||
| 1408 | | Left i -> Format.fprintf ppf "l%i" i | ||
| 1409 | | Right j -> Format.fprintf ppf "r%i" j | ||
| 1410 | | Recompose (i,j) -> | ||
| 1411 | abate | 57 | Format.fprintf ppf "(%a,%a)" |
| 1412 | abate | 172 | print_source (Left i) |
| 1413 | print_source (Right j) | ||
| 1414 | abate | 56 | |
| 1415 | let print_result ppf = | ||
| 1416 | Array.iteri | ||
| 1417 | (fun i s -> | ||
| 1418 | if i > 0 then Format.fprintf ppf ","; | ||
| 1419 | print_source ppf s; | ||
| 1420 | ) | ||
| 1421 | |||
| 1422 | let print_ret ppf (code,ret) = | ||
| 1423 | Format.fprintf ppf "$%i" code; | ||
| 1424 | if Array.length ret <> 0 then | ||
| 1425 | Format.fprintf ppf "(%a)" print_result ret | ||
| 1426 | |||
| 1427 | abate | 229 | let print_ret_opt ppf = function |
| 1428 | | None -> Format.fprintf ppf "*" | ||
| 1429 | | Some r -> print_ret ppf r | ||
| 1430 | |||
| 1431 | abate | 56 | let print_kind ppf actions = |
| 1432 | abate | 42 | let print_lhs ppf (code,prefix,d) = |
| 1433 | abate | 43 | let arity = match d.codes.(code) with (_,a,_) -> a in |
| 1434 | abate | 42 | Format.fprintf ppf "$%i(" code; |
| 1435 | for i = 0 to arity - 1 do | ||
| 1436 | if i > 0 then Format.fprintf ppf ","; | ||
| 1437 | Format.fprintf ppf "%s%i" prefix i; | ||
| 1438 | done; | ||
| 1439 | Format.fprintf ppf ")" in | ||
| 1440 | let print_basic (t,ret) = | ||
| 1441 | abate | 43 | Format.fprintf ppf " | %a -> %a@\n" |
| 1442 | abate | 367 | Types.Print.print t |
| 1443 | abate | 42 | print_ret ret |
| 1444 | in | ||
| 1445 | abate | 45 | let print_prod2 = function |
| 1446 | abate | 172 | | Impossible -> assert false |
| 1447 | | Ignore r -> | ||
| 1448 | abate | 45 | Format.fprintf ppf " %a\n" |
| 1449 | print_ret r | ||
| 1450 | abate | 172 | | TailCall d -> |
| 1451 | abate | 45 | queue d; |
| 1452 | Format.fprintf ppf " disp_%i v2@\n" d.id | ||
| 1453 | abate | 172 | | Dispatch (d, branches) -> |
| 1454 | abate | 45 | queue d; |
| 1455 | Format.fprintf ppf " match v2 with disp_%i@\n" d.id; | ||
| 1456 | Array.iteri | ||
| 1457 | (fun code r -> | ||
| 1458 | Format.fprintf ppf " | %a -> %a\n" | ||
| 1459 | print_lhs (code, "r", d) | ||
| 1460 | print_ret r; | ||
| 1461 | ) | ||
| 1462 | branches | ||
| 1463 | abate | 42 | in |
| 1464 | abate | 229 | let print_prod prefix ppf = function |
| 1465 | abate | 172 | | Impossible -> () |
| 1466 | | Ignore d2 -> | ||
| 1467 | abate | 110 | Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix; |
| 1468 | abate | 45 | print_prod2 d2 |
| 1469 | abate | 172 | | TailCall d -> |
| 1470 | abate | 45 | queue d; |
| 1471 | abate | 110 | Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix; |
| 1472 | abate | 45 | Format.fprintf ppf " disp_%i v1@\n" d.id |
| 1473 | abate | 172 | | Dispatch (d,branches) -> |
| 1474 | abate | 45 | queue d; |
| 1475 | abate | 110 | Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix; |
| 1476 | abate | 45 | Format.fprintf ppf " match v1 with disp_%i@\n" d.id; |
| 1477 | Array.iteri | ||
| 1478 | (fun code d2 -> | ||
| 1479 | Format.fprintf ppf " | %a -> @\n" | ||
| 1480 | print_lhs (code, "l", d); | ||
| 1481 | print_prod2 d2; | ||
| 1482 | ) | ||
| 1483 | branches | ||
| 1484 | abate | 42 | in |
| 1485 | let rec print_record_opt ppf = function | ||
| 1486 | | None -> () | ||
| 1487 | abate | 1349 | | Some (RecLabel (l,d)) -> |
| 1488 | let l = LabelPool.value l in | ||
| 1489 | print_prod ("record:"^(Label.to_string l)) ppf d | ||
| 1490 | | Some (RecNolabel (r1,r2)) -> | ||
| 1491 | abate | 42 | Format.fprintf ppf " | Record -> @\n"; |
| 1492 | abate | 1349 | Format.fprintf ppf " SomeField:%a;NoField:%a@\n" |
| 1493 | print_ret_opt r1 print_ret_opt r2 | ||
| 1494 | in | ||
| 1495 | abate | 42 | |
| 1496 | List.iter print_basic actions.basic; | ||
| 1497 | abate | 229 | print_prod "" ppf actions.prod; |
| 1498 | print_prod "XML" ppf actions.xml; | ||
| 1499 | abate | 42 | print_record_opt ppf actions.record |
| 1500 | |||
| 1501 | abate | 56 | let print_actions ppf = function |
| 1502 | abate | 172 | | AKind k -> print_kind ppf k |
| 1503 | | AIgnore r -> Format.fprintf ppf "v -> %a@\n" print_ret r | ||
| 1504 | abate | 56 | |
| 1505 | abate | 229 | let print_dispatcher ppf d = |
| 1506 | abate | 1349 | Format.fprintf ppf "Dispatcher %i accepts [%a]@\n" |
| 1507 | abate | 367 | d.id Types.Print.print (Types.normalize d.t); |
| 1508 | abate | 229 | let print_code code (t, arity, m) = |
| 1509 | Format.fprintf ppf " Returns $%i(arity=%i) for [%a]" | ||
| 1510 | code arity | ||
| 1511 | abate | 367 | Types.Print.print (Types.normalize t); |
| 1512 | abate | 229 | (* |
| 1513 | List.iter | ||
| 1514 | (fun (i,b) -> | ||
| 1515 | Format.fprintf ppf "[%i:" i; | ||
| 1516 | List.iter | ||
| 1517 | (fun (v,i) -> Format.fprintf ppf "%s=>%i;" v i) | ||
| 1518 | b; | ||
| 1519 | Format.fprintf ppf "]" | ||
| 1520 | ) m; *) | ||
| 1521 | |||
| 1522 | Format.fprintf ppf "@\n"; | ||
| 1523 | in | ||
| 1524 | abate | 1349 | Array.iteri print_code d.codes; |
| 1525 | abate | 229 | Format.fprintf ppf "let disp_%i = function@\n" d.id; |
| 1526 | print_actions ppf (actions d); | ||
| 1527 | Format.fprintf ppf "====================================@\n" | ||
| 1528 | |||
| 1529 | |||
| 1530 | abate | 42 | let rec print_dispatchers ppf = |
| 1531 | match !to_print with | ||
| 1532 | | [] -> () | ||
| 1533 | abate | 229 | | d :: rem -> |
| 1534 | to_print := rem; | ||
| 1535 | print_dispatcher ppf d; | ||
| 1536 | abate | 42 | print_dispatchers ppf |
| 1537 | |||
| 1538 | abate | 229 | |
| 1539 | let show ppf t pl lab = | ||
| 1540 | let disp = dispatcher t pl lab in | ||
| 1541 | abate | 42 | queue disp; |
| 1542 | print_dispatchers ppf | ||
| 1543 | |||
| 1544 | abate | 149 | let debug_compile ppf t pl = |
| 1545 | let t = Types.descr t in | ||
| 1546 | abate | 229 | let lab = |
| 1547 | List.fold_left | ||
| 1548 | (fun l p -> min l (Normal.first_label (descr p))) | ||
| 1549 | (Types.Record.first_label t) pl in | ||
| 1550 | abate | 310 | let lab = if lab == LabelPool.dummy_max then None else Some lab in |
| 1551 | abate | 229 | |
| 1552 | let pl = Array.of_list | ||
| 1553 | abate | 281 | (List.map (fun p -> Normal.normal lab (*t*) Types.Record.any_or_absent [p]) pl) in |
| 1554 | abate | 229 | |
| 1555 | show ppf t pl lab; | ||
| 1556 | abate | 172 | Format.fprintf ppf "# compiled dispatchers: %i@\n" !cur_id |
| 1557 | abate | 43 | end |
| 1558 | abate | 42 | |
| 1559 | |||
| 1560 | abate | 1352 | |
| 1561 | |||
| 1562 | (* New compilation procedure *) | ||
| 1563 | |||
| 1564 | module Compile2 = struct | ||
| 1565 | |||
| 1566 | abate | 1359 | module PatList = SortedList.Make(struct include Custom.Dummy include Pat end) |
| 1567 | abate | 1352 | module TypesFv = Custom.Pair(Types)(IdSet) |
| 1568 | abate | 1358 | module Req = PatList.MakeMap(TypesFv) |
| 1569 | abate | 1352 | (* Invariant for (p |-> (t,X)): |
| 1570 | i) t != Empty | ||
| 1571 | ii) X \subset fv(p) *) | ||
| 1572 | |||
| 1573 | abate | 1358 | let empty_reqs = PatList.Map.empty |
| 1574 | |||
| 1575 | let merge_reqs = | ||
| 1576 | PatList.Map.merge | ||
| 1577 | (fun (t1,xs1) (t2,xs2) -> Types.cup t1 t2, IdSet.cup xs1 xs2) | ||
| 1578 | |||
| 1579 | let add_req reqs p t xs = | ||
| 1580 | merge_reqs reqs (PatList.Map.singleton p (t,xs)) | ||
| 1581 | |||
| 1582 | abate | 1353 | module NodeSet = Set.Make(Node) |
| 1583 | |||
| 1584 | let pi1 t = Types.Product.pi1 (Types.Product.get t) | ||
| 1585 | let pi2 t = Types.Product.pi2 (Types.Product.get t) | ||
| 1586 | |||
| 1587 | abate | 1352 | module Approx = struct |
| 1588 | |||
| 1589 | abate | 1354 | (* Note: this is incomplete because of non-atomic constant patterns: |
| 1590 | # debug approx (_,(x:=(1,2))) (1,2);; | ||
| 1591 | [DEBUG:approx] | ||
| 1592 | x=(1,2) | ||
| 1593 | *) | ||
| 1594 | abate | 1355 | let rec approx_var seen ((a,fv,d) as p) t xs = |
| 1595 | assert (Types.subtype t a); | ||
| 1596 | assert (IdSet.subset xs fv); | ||
| 1597 | if (IdSet.is_empty xs) || (Types.is_empty t) then xs | ||
| 1598 | else match d with | ||
| 1599 | | Cup ((a1,_,_) as p1,p2) -> | ||
| 1600 | IdSet.cap | ||
| 1601 | (approx_var seen p1 (Types.cap t a1) xs) | ||
| 1602 | (approx_var seen p2 (Types.diff t a1) xs) | ||
| 1603 | | Cap ((_,fv1,_) as p1,((_,fv2,_) as p2)) -> | ||
| 1604 | IdSet.cup | ||
| 1605 | (approx_var seen p1 t (IdSet.cap fv1 xs)) | ||
| 1606 | (approx_var seen p2 t (IdSet.cap fv2 xs)) | ||
| 1607 | | Capture _ -> | ||
| 1608 | xs | ||
| 1609 | | Constant (_,c) -> | ||
| 1610 | if (Types.subtype t (Types.constant c |