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

Contents of /types/patterns.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1726 - (show annotations)
Tue Jul 10 19:17:16 2007 UTC (5 years, 10 months ago) by abate
File size: 70668 byte(s)
[r2005-06-16 15:44:40 by afrisch] Begin automaton minimization

Original author: afrisch
Date: 2005-06-16 15:44:41+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" Ident.print x
63 | Constant (x,c) ->
64 Format.fprintf ppf "(%a := %a)" Ident.print 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 " ^ (Ident.to_string 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 " ^ (Ident.to_string 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 let print_node = ref (fun _ _ -> assert false)
142
143 module Node = struct
144 type t = node
145 let compare n1 n2 = n1.id - n2.id
146 let equal n1 n2 = n1.id == n2.id
147 let hash n = n.id
148
149 let check n = ()
150 let dump ppf x = !print_node ppf x
151
152
153 module SMemo = Set.Make(Custom.Int)
154 let memo = Serialize.Put.mk_property (fun t -> ref SMemo.empty)
155 let rec serialize t n =
156 let l = Serialize.Put.get_property memo t in
157 Serialize.Put.int t n.id;
158 if not (SMemo.mem n.id !l) then (
159 l := SMemo.add n.id !l;
160 Types.Node.serialize t n.accept;
161 IdSet.serialize t n.fv;
162 serialize_descr t n.descr
163 )
164 and serialize_descr s (_,_,d) =
165 serialize_d s d
166 and serialize_d s = function
167 | Constr t ->
168 Serialize.Put.bits 3 s 0;
169 Types.serialize s t
170 | Cup (p1,p2) ->
171 Serialize.Put.bits 3 s 1;
172 serialize_descr s p1;
173 serialize_descr s p2
174 | Cap (p1,p2) ->
175 Serialize.Put.bits 3 s 2;
176 serialize_descr s p1;
177 serialize_descr s p2
178 | Times (p1,p2) ->
179 Serialize.Put.bits 3 s 3;
180 serialize s p1;
181 serialize s p2
182 | Xml (p1,p2) ->
183 Serialize.Put.bits 3 s 4;
184 serialize s p1;
185 serialize s p2
186 | Record (l,p) ->
187 Serialize.Put.bits 3 s 5;
188 LabelPool.serialize s l;
189 serialize s p
190 | Capture x ->
191 Serialize.Put.bits 3 s 6;
192 Id.serialize s x
193 | Constant (x,c) ->
194 Serialize.Put.bits 3 s 7;
195 Id.serialize s x;
196 Types.Const.serialize s c
197 | Dummy -> assert false
198
199 module DMemo = Map.Make(Custom.Int)
200 let memo = Serialize.Get.mk_property (fun t -> ref DMemo.empty)
201 let rec deserialize t =
202 let l = Serialize.Get.get_property memo t in
203 let id = Serialize.Get.int t in
204 try DMemo.find id !l
205 with Not_found ->
206 let accept = Types.Node.deserialize t in
207 let fv = IdSet.deserialize t in
208 incr counter;
209 let n = { id = !counter; descr = dummy; accept = accept; fv = fv } in
210 l := DMemo.add id n !l;
211 n.descr <- deserialize_descr t;
212 n
213 and deserialize_descr s =
214 match Serialize.Get.bits 3 s with
215 | 0 -> constr (Types.deserialize s)
216 | 1 ->
217 (* Avoid unnecessary tests *)
218 let (acc1,fv1,_) as x1 = deserialize_descr s in
219 let (acc2,fv2,_) as x2 = deserialize_descr s in
220 (Types.cup acc1 acc2, IdSet.cup fv1 fv2, Cup (x1,x2))
221 | 2 ->
222 let (acc1,fv1,_) as x1 = deserialize_descr s in
223 let (acc2,fv2,_) as x2 = deserialize_descr s in
224 (Types.cap acc1 acc2, IdSet.cup fv1 fv2, Cap (x1,x2))
225 | 3 ->
226 let x = deserialize s in
227 let y = deserialize s in
228 times x y
229 | 4 ->
230 let x = deserialize s in
231 let y = deserialize s in
232 xml x y
233 | 5 ->
234 let l = LabelPool.deserialize s in
235 let x = deserialize s in
236 record l x
237 | 6 -> capture (Id.deserialize s)
238 | 7 ->
239 let x = Id.deserialize s in
240 let c = Types.Const.deserialize s in
241 constant x c
242 | _ -> assert false
243
244
245 end
246
247 (* Pretty-print *)
248
249 module Pat = struct
250 type t = descr
251 let rec compare (_,_,d1) (_,_,d2) = if d1 == d2 then 0 else
252 match (d1,d2) with
253 | Constr t1, Constr t2 -> Types.compare t1 t2
254 | Constr _, _ -> -1 | _, Constr _ -> 1
255
256 | Cup (x1,y1), Cup (x2,y2) | Cap (x1,y1), Cap (x2,y2) ->
257 let c = compare x1 x2 in if c <> 0 then c
258 else compare y1 y2
259 | Cup _, _ -> -1 | _, Cup _ -> 1
260 | Cap _, _ -> -1 | _, Cap _ -> 1
261
262 | Times (x1,y1), Times (x2,y2) | Xml (x1,y1), Xml (x2,y2) ->
263 let c = Node.compare x1 x2 in if c <> 0 then c
264 else Node.compare y1 y2
265 | Times _, _ -> -1 | _, Times _ -> 1
266 | Xml _, _ -> -1 | _, Xml _ -> 1
267
268 | Record (x1,y1), Record (x2,y2) ->
269 let c = LabelPool.compare x1 x2 in if c <> 0 then c
270 else Node.compare y1 y2
271 | Record _, _ -> -1 | _, Record _ -> 1
272
273 | Capture x1, Capture x2 ->
274 Id.compare x1 x2
275 | Capture _, _ -> -1 | _, Capture _ -> 1
276
277 | Constant (x1,y1), Constant (x2,y2) ->
278 let c = Id.compare x1 x2 in if c <> 0 then c
279 else Types.Const.compare y1 y2
280 | Constant _, _ -> -1 | _, Constant _ -> 1
281
282 | Dummy, Dummy -> assert false
283
284 let equal p1 p2 = compare p1 p2 == 0
285
286 let rec hash (_,_,d) = match d with
287 | Constr t -> 1 + 17 * (Types.hash t)
288 | Cup (p1,p2) -> 2 + 17 * (hash p1) + 257 * (hash p2)
289 | Cap (p1,p2) -> 3 + 17 * (hash p1) + 257 * (hash p2)
290 | Times (q1,q2) -> 4 + 17 * q1.id + 257 * q2.id
291 | Xml (q1,q2) -> 5 + 17 * q1.id + 257 * q2.id
292 | Record (l,q) -> 6 + 17 * (LabelPool.hash l) + 257 * q.id
293 | Capture x -> 7 + (Id.hash x)
294 | Constant (x,c) -> 8 + 17 * (Id.hash x) + 257 * (Types.Const.hash c)
295 | Dummy -> assert false
296
297 let serialize _ _ = assert false
298 let deserialize _ = assert false
299 let check _ = assert false
300 let dump _ = assert false
301 end
302
303 module Print = struct
304 module M = Map.Make(Pat)
305 module S = Set.Make(Pat)
306
307 let names = ref M.empty
308 let printed = ref S.empty
309 let toprint = Queue.create ()
310 let id = ref 0
311
312 let rec mark seen ((_,_,d) as p) =
313 if (M.mem p !names) then ()
314 else if (S.mem p seen) then
315 (incr id;
316 names := M.add p !id !names;
317 Queue.add p toprint)
318 else
319 let seen = S.add p seen in
320 match d with
321 | Cup (p1,p2) | Cap (p1,p2) -> mark seen p1; mark seen p2
322 | Times (q1,q2) | Xml (q1,q2) -> mark seen q1.descr; mark seen q2.descr
323 | Record (_,q) -> mark seen q.descr
324 | _ -> ()
325
326 let rec print ppf p =
327 try
328 let i = M.find p !names in
329 Format.fprintf ppf "P%i" i
330 with Not_found ->
331 real_print ppf p
332 and real_print ppf (_,_,d) = match d with
333 | Constr t ->
334 Types.Print.print ppf t
335 | Cup (p1,p2) ->
336 Format.fprintf ppf "(%a | %a)" print p1 print p2
337 | Cap (p1,p2) ->
338 Format.fprintf ppf "(%a & %a)" print p1 print p2
339 | Times (q1,q2) ->
340 Format.fprintf ppf "(%a,%a)" print q1.descr print q2.descr
341 | Xml (q1,{ descr = (_,_,Times(q2,q3)) }) ->
342 Format.fprintf ppf "<(%a) (%a)>(%a)" print q1.descr print q2.descr print q3.descr
343 | Xml _ -> assert false
344 | Record (l,q) ->
345 Format.fprintf ppf "{%a=%a}" Label.print (LabelPool.value l) print q.descr
346 | Capture x ->
347 Format.fprintf ppf "%a" Ident.print x
348 | Constant (x,c) ->
349 Format.fprintf ppf "(%a:=%a)" Ident.print x Types.Print.print_const c
350 | Dummy -> assert false
351
352 let print ppf p =
353 mark S.empty p;
354 print ppf p;
355 let first = ref true in
356 (try while true do
357 let p = Queue.pop toprint in
358 if not (S.mem p !printed) then
359 ( printed := S.add p !printed;
360 Format.fprintf ppf " %s@ @[%a=%a@]"
361 (if !first then (first := false; "where") else "and")
362 print p
363 real_print p
364 );
365 done with Queue.Empty -> ());
366 id := 0;
367 names := M.empty;
368 printed := S.empty
369
370
371 let print_xs ppf xs =
372 Format.fprintf ppf "{";
373 let rec aux = function
374 | [] -> ()
375 | [x] -> Ident.print ppf x
376 | x::q -> Ident.print ppf x; Format.fprintf ppf ","; aux q
377 in
378 aux xs;
379 Format.fprintf ppf "}"
380 end
381
382 let () = print_node := (fun ppf n -> Print.print ppf (descr n))
383
384
385 (* Static semantics *)
386
387 let cup_res v1 v2 = Types.Positive.cup [v1;v2]
388 let empty_res fv = IdMap.constant (Types.Positive.ty Types.empty) fv
389 let times_res v1 v2 = Types.Positive.times v1 v2
390
391 (* Try with a hash-table *)
392 module MemoFilter = Map.Make
393 (struct
394 type t = Types.t * node
395 let compare (t1,n1) (t2,n2) =
396 if n1.id < n2.id then -1 else if n1.id > n2.id then 1 else
397 Types.compare t1 t2
398 end)
399
400 let memo_filter = ref MemoFilter.empty
401
402 let rec filter_descr t (_,fv,d) : Types.Positive.v id_map =
403 (* TODO: avoid is_empty t when t is not changing (Cap) *)
404 if Types.is_empty t
405 then empty_res fv
406 else
407 match d with
408 | Constr _ -> IdMap.empty
409 | Cup ((a,_,_) as d1,d2) ->
410 IdMap.merge cup_res
411 (filter_descr (Types.cap t a) d1)
412 (filter_descr (Types.diff t a) d2)
413 | Cap (d1,d2) ->
414 IdMap.merge cup_res (filter_descr t d1) (filter_descr t d2)
415 | Times (p1,p2) -> filter_prod fv p1 p2 t
416 | Xml (p1,p2) -> filter_prod ~kind:`XML fv p1 p2 t
417 | Record (l,p) ->
418 filter_node (Types.Record.project t l) p
419 | Capture c ->
420 IdMap.singleton c (Types.Positive.ty t)
421 | Constant (c, cst) ->
422 IdMap.singleton c (Types.Positive.ty (Types.constant cst))
423 | Dummy -> assert false
424
425 and filter_prod ?kind fv p1 p2 t =
426 List.fold_left
427 (fun accu (d1,d2) ->
428 let term =
429 IdMap.merge times_res (filter_node d1 p1) (filter_node d2 p2)
430 in
431 IdMap.merge cup_res accu term
432 )
433 (empty_res fv)
434 (Types.Product.normal ?kind t)
435
436
437 and filter_node t p : Types.Positive.v id_map =
438 try MemoFilter.find (t,p) !memo_filter
439 with Not_found ->
440 let (_,fv,_) as d = descr p in
441 let res = IdMap.map_from_slist (fun _ -> Types.Positive.forward ()) fv in
442 memo_filter := MemoFilter.add (t,p) res !memo_filter;
443 let r = filter_descr t (descr p) in
444 IdMap.collide Types.Positive.define res r;
445 r
446
447 let filter t p =
448 let r = filter_node t p in
449 memo_filter := MemoFilter.empty;
450 IdMap.map Types.Positive.solve r
451 let filter_descr t p =
452 let r = filter_descr t p in
453 memo_filter := MemoFilter.empty;
454 IdMap.get (IdMap.map Types.Positive.solve r)
455
456
457 (* Factorization of capture variables and constant patterns *)
458
459 module Factorize = struct
460 module NodeTypeSet = Set.Make(Custom.Pair(Node)(Types))
461
462 let pi1 ~kind t = Types.Product.pi1 (Types.Product.get ~kind t)
463 let pi2 ~kind t = Types.Product.pi2 (Types.Product.get ~kind t)
464
465 (* Note: this is incomplete because of non-atomic constant patterns:
466 # debug approx (_,(x:=(1,2))) (1,2);;
467 [DEBUG:approx]
468 x=(1,2)
469 *)
470 let rec approx_var seen ((a,fv,d) as p) t xs =
471 (* assert (Types.subtype t a);
472 assert (IdSet.subset xs fv); *)
473 if (IdSet.is_empty xs) || (Types.is_empty t) then xs
474 else match d with
475 | Cup ((a1,_,_) as p1,p2) ->
476 approx_var seen p2 (Types.diff t a1)
477 (approx_var seen p1 (Types.cap t a1) xs)
478 | Cap ((_,fv1,_) as p1,((_,fv2,_) as p2)) ->
479 IdSet.cup
480 (approx_var seen p1 t (IdSet.cap fv1 xs))
481 (approx_var seen p2 t (IdSet.cap fv2 xs))
482 | Capture _ ->
483 xs
484 | Constant (_,c) ->
485 if (Types.subtype t (Types.constant c)) then xs else IdSet.empty
486 | Times (q1,q2) ->
487 let xs = IdSet.cap xs (IdSet.cap q1.fv q2.fv) in
488 IdSet.cap
489 (approx_var_node seen q1 (pi1 ~kind:`Normal t) xs)
490 (approx_var_node seen q2 (pi2 ~kind:`Normal t) xs)
491 | Xml (q1,q2) ->
492 let xs = IdSet.cap xs (IdSet.cap q1.fv q2.fv) in
493 IdSet.cap
494 (approx_var_node seen q1 (pi1 ~kind:`XML t) xs)
495 (approx_var_node seen q2 (pi2 ~kind:`XML t) xs)
496 | Record _ -> IdSet.empty
497 | _ -> assert false
498
499 and approx_var_node seen q t xs =
500 if (NodeTypeSet.mem (q,t) seen)
501 then xs
502 else approx_var (NodeTypeSet.add (q,t) seen) q.descr t xs
503
504
505 (* Obviously not complete ! *)
506 let rec approx_nil seen ((a,fv,d) as p) t xs =
507 assert (Types.subtype t a);
508 assert (IdSet.subset xs fv);
509 if (IdSet.is_empty xs) || (Types.is_empty t) then xs
510 else match d with
511 | Cup ((a1,_,_) as p1,p2) ->
512 approx_nil seen p2 (Types.diff t a1)
513 (approx_nil seen p1 (Types.cap t a1) xs)
514 | Cap ((_,fv1,_) as p1,((_,fv2,_) as p2)) ->
515 IdSet.cup
516 (approx_nil seen p1 t (IdSet.cap fv1 xs))
517 (approx_nil seen p2 t (IdSet.cap fv2 xs))
518 | Constant (_,c) when Types.Const.equal c Sequence.nil_cst -> xs
519 | Times (q1,q2) ->
520 let xs = IdSet.cap q2.fv (IdSet.diff xs q1.fv) in
521 approx_nil_node seen q2 (pi2 ~kind:`Normal t) xs
522 | _ -> IdSet.empty
523
524 and approx_nil_node seen q t xs =
525 if (NodeTypeSet.mem (q,t) seen)
526 then xs
527 else approx_nil (NodeTypeSet.add (q,t) seen) q.descr t xs
528
529 let cst ((a,_,_) as p) t xs =
530 if IdSet.is_empty xs then IdMap.empty
531 else
532 let rec aux accu (x,t) =
533 if (IdSet.mem xs x) then
534 match Sample.single_opt (Types.descr t) with
535 | Some c -> (x,c)::accu
536 | None -> accu
537 else accu in
538 let t = Types.cap t a in
539 IdMap.from_list_disj (List.fold_left aux [] (filter_descr t p))
540
541 let var ((a,_,_) as p) t =
542 approx_var NodeTypeSet.empty p (Types.cap t a)
543
544 let nil ((a,_,_) as p) t =
545 approx_nil NodeTypeSet.empty p (Types.cap t a)
546 end
547
548
549
550
551 (* Normal forms for patterns and compilation *)
552
553 let min (a:int) (b:int) = if a < b then a else b
554
555 let any_basic = Types.Record.or_absent Types.non_constructed
556
557 let rec first_label (acc,fv,d) =
558 if Types.is_empty acc
559 then LabelPool.dummy_max
560 else match d with
561 | Constr t -> Types.Record.first_label t
562 | Cap (p,q) -> min (first_label p) (first_label q)
563 | Cup ((acc1,_,_) as p,q) -> min (first_label p) (first_label q)
564 | Record (l,p) -> l
565 | _ -> LabelPool.dummy_max
566
567 module Normal = struct
568
569 type source = SCatch | SConst of Types.const
570 type result = source id_map
571
572 let compare_source s1 s2 =
573 if s1 == s2 then 0
574 else match (s1,s2) with
575 | SCatch, _ -> -1 | _, SCatch -> 1
576 | SConst c1, SConst c2 -> Types.Const.compare c1 c2
577
578 (*
579 let hash_source = function
580 | SCatch -> 1
581 | SConst c -> Types.Const.hash c
582 *)
583
584 let compare_result r1 r2 =
585 IdMap.compare compare_source r1 r2
586
587 module ResultMap = Map.Make(struct
588 type t = result
589 let compare = compare_result
590 end)
591
592 module NodeSet = SortedList.Make(Node)
593
594 module Nnf = struct
595 include Custom.Dummy
596
597 type t = NodeSet.t * Types.t * IdSet.t (* pl,t; t <= \accept{pl} *)
598
599 let check (pl,t,xs) =
600 List.iter (fun p -> assert(Types.subtype t (Types.descr p.accept)))
601 (NodeSet.get pl)
602 let print ppf (pl,t,xs) =
603 Format.fprintf ppf "@[(pl=%a;t=%a)@]" NodeSet.dump pl Types.Print.print t
604 let compare (l1,t1,xs1) (l2,t2,xs2) =
605 let c = NodeSet.compare l1 l2 in if c <> 0 then c
606 else let c = Types.compare t1 t2 in if c <> 0 then c
607 else IdSet.compare xs1 xs2
608 let hash (l,t,xs) =
609 (NodeSet.hash l) + 17 * (Types.hash t) + 257 * (IdSet.hash xs)
610 let equal x y = compare x y == 0
611
612
613 let first_label (pl,t,xs) =
614 List.fold_left
615 (fun l p -> min l (first_label (descr p)))
616 (Types.Record.first_label t)
617 pl
618
619
620 end
621
622 module NProd = struct
623 type t = result * Nnf.t * Nnf.t
624
625 let compare (r1,x1,y1) (r2,x2,y2) =
626 let c = compare_result r1 r2 in if c <> 0 then c
627 else let c = Nnf.compare x1 x2 in if c <> 0 then c
628 else Nnf.compare y1 y2
629 end
630
631 module NLineProd = Set.Make(NProd)
632
633 type record =
634 | RecNolabel of result option * result option
635 | RecLabel of label * NLineProd.t
636 type t = {
637 nprod : NLineProd.t;
638 nxml : NLineProd.t;
639 nrecord: record
640 }
641
642 let fus = IdMap.union_disj
643
644 let nempty lab =
645 { nprod = NLineProd.empty;
646 nxml = NLineProd.empty;
647 nrecord = (match lab with
648 | Some l -> RecLabel (l,NLineProd.empty)
649 | None -> RecNolabel (None,None))
650 }
651 let dummy = nempty None
652
653
654 let ncup nf1 nf2 =
655 { nprod = NLineProd.union nf1.nprod nf2.nprod;
656 nxml = NLineProd.union nf1.nxml nf2.nxml;
657 nrecord = (match (nf1.nrecord,nf2.nrecord) with
658 | RecLabel (l1,r1), RecLabel (l2,r2) ->
659 (* assert (l1 = l2); *)
660 RecLabel (l1, NLineProd.union r1 r2)
661 | RecNolabel (x1,y1), RecNolabel (x2,y2) ->
662 RecNolabel((if x1 == None then x2 else x1),
663 (if y1 == None then y2 else y1))
664 | _ -> assert false)
665 }
666
667 let double_fold_prod f l1 l2 =
668 NLineProd.fold
669 (fun x1 accu -> NLineProd.fold (fun x2 accu -> f accu x1 x2) l2 accu)
670 l1 NLineProd.empty
671
672 let ncap nf1 nf2 =
673 let prod accu (res1,(pl1,t1,xs1),(ql1,s1,ys1)) (res2,(pl2,t2,xs2),(ql2,s2,ys2)) =
674 let t = Types.cap t1 t2 in
675 if Types.is_empty t then accu else
676 let s = Types.cap s1 s2 in
677 if Types.is_empty s then accu else
678 NLineProd.add (fus res1 res2,
679 (NodeSet.cup pl1 pl2, t, IdSet.cup xs1 xs2),
680 (NodeSet.cup ql1 ql2, s, IdSet.cup ys1 ys2))
681 accu
682 in
683 let record r1 r2 = match r1,r2 with
684 | RecLabel (l1,r1), RecLabel (l2,r2) ->
685 (* assert (l1 = l2); *)
686 RecLabel(l1, double_fold_prod prod r1 r2)
687 | RecNolabel (x1,y1), RecNolabel (x2,y2) ->
688 let x = match x1,x2 with
689 | Some res1, Some res2 -> Some (fus res1 res2)
690 | _ -> None
691 and y = match y1,y2 with
692 | Some res1, Some res2 -> Some (fus res1 res2)
693 | _ -> None in
694 RecNolabel (x,y)
695 | _ -> assert false
696 in
697 { nprod = double_fold_prod prod nf1.nprod nf2.nprod;
698 nxml = double_fold_prod prod nf1.nxml nf2.nxml;
699 nrecord = record nf1.nrecord nf2.nrecord;
700 }
701
702 let nnode p xs = NodeSet.singleton p, Types.descr p.accept, xs
703 let nc t = NodeSet.empty, t, IdSet.empty
704 let ncany = nc Types.any
705 let ncany_abs = nc Types.Record.any_or_absent
706
707 let empty_res = IdMap.empty
708
709 let single_prod src p q = NLineProd.singleton (src, p,q)
710
711 let ntimes lab acc p q xs =
712 let xsp = IdSet.cap xs p.fv and xsq = IdSet.cap xs q.fv in
713 { (nempty lab) with
714 nprod = single_prod empty_res (nnode p xsp) (nnode q xsq)
715 }
716
717 let nxml lab acc p q xs =
718 let xsp = IdSet.cap xs p.fv and xsq = IdSet.cap xs q.fv in
719 { (nempty lab) with
720 nxml = single_prod empty_res (nnode p xsp) (nnode q xsq)
721 }
722
723 let nrecord lab acc l p xs =
724 match lab with
725 | None -> assert false
726 | Some label ->
727 assert (label <= l);
728 let lft,rgt =
729 if l == label
730 then nnode p xs, ncany
731 else ncany_abs, nnode (cons p.fv (record l p)) xs
732 in
733 { (nempty lab) with
734 nrecord = RecLabel(label, single_prod empty_res lft rgt) }
735
736 let nconstr lab t =
737 let aux l =
738 List.fold_left (fun accu (t1,t2) ->
739 NLineProd.add (empty_res, nc t1,nc t2) accu)
740 NLineProd.empty l in
741 let record = match lab with
742 | None ->
743 let (x,y) = Types.Record.empty_cases t in
744 RecNolabel ((if x then Some empty_res else None),
745 (if y then Some empty_res else None))
746 | Some l ->
747 RecLabel (l,aux (Types.Record.split_normal t l)) in
748 { nprod = aux (Types.Product.normal t);
749 nxml = aux (Types.Product.normal ~kind:`XML t);
750 nrecord = record
751 }
752
753 let nany lab res =
754 { nprod = single_prod res ncany ncany;
755 nxml = single_prod res ncany ncany;
756 nrecord = match lab with
757 | None -> RecNolabel (Some res, Some res)
758 | Some lab -> RecLabel (lab, single_prod res ncany_abs ncany)
759 }
760
761 let nconstant lab x c = nany lab (IdMap.singleton x (SConst c))
762 let ncapture lab x = nany lab (IdMap.singleton x SCatch)
763
764 let rec nnormal lab ((acc,fv,d) as p) xs =
765 let xs = IdSet.cap xs fv in
766 if Types.is_empty acc then nempty lab
767 else if IdSet.is_empty xs then nconstr lab acc
768 else match d with
769 | Constr t -> assert false
770 | Cap (p,q) -> ncap (nnormal lab p xs) (nnormal lab q xs)
771 | Cup ((acc1,_,_) as p,q) ->
772 ncup
773 (nnormal lab p xs)
774 (ncap (nnormal lab q xs) (nconstr lab (Types.neg acc1)))
775 | Times (p,q) -> ntimes lab acc p q xs
776 | Xml (p,q) -> nxml lab acc p q xs
777 | Capture x -> ncapture lab x
778 | Constant (x,c) -> nconstant lab x c
779 | Record (l,p) -> nrecord lab acc l p xs
780 | Dummy -> assert false
781
782 (*TODO: when an operand of Cap has its first_label > lab,
783 directly shift it*)
784
785
786 let facto f t xs pl =
787 List.fold_left
788 (fun vs p -> IdSet.cup vs (f (descr p) t (IdSet.cap (fv p) xs)))
789 IdSet.empty
790 pl
791
792 let factorize t0 (pl,t,xs) =
793 let t0 = if Types.subtype t t0 then t else Types.cap t t0 in
794 let vs_var = facto Factorize.var t0 xs pl in
795 let xs = IdSet.diff xs vs_var in
796 let vs_nil = facto Factorize.nil t0 xs pl in
797 let xs = IdSet.diff xs vs_nil in
798 (vs_var,vs_nil,(pl,t,xs))
799
800 let normal l t pl xs =
801 List.fold_left
802 (fun a p -> ncap a (nnormal l (descr p) xs)) (nconstr l t) pl
803
804 let nnf lab t0 (pl,t,xs) =
805 (* assert (not (Types.disjoint t t0)); *)
806 let t = if Types.subtype t t0 then t else Types.cap t t0 in
807 normal lab t (NodeSet.get pl) xs
808
809 let basic_tests f (pl,t,xs) =
810 let rec aux more s accu t res = function
811 (* Invariant: t and s disjoint, t not empty *)
812 | [] ->
813 let accu =
814 try
815 let t' = ResultMap.find res accu in
816 ResultMap.add res (Types.cup t t') accu
817 with Not_found -> ResultMap.add res t accu in
818 cont (Types.cup t s) accu more
819 | (tp,xp,d) :: r ->
820 if (IdSet.disjoint xp xs)
821 then aux_check more s accu (Types.cap t tp) res r
822 else match d with
823 | Cup (p1,p2) -> aux ((t,res,p2::r)::more) s accu t res (p1::r)
824 | Cap (p1,p2) -> aux more s accu t res (p1 :: p2 :: r)
825 | Capture x -> aux more s accu t (IdMap.add x SCatch res) r
826 | Constant (x,c) ->
827 aux more s accu t (IdMap.add x (SConst c) res) r
828 | _ -> cont s accu more
829 and aux_check more s accu t res pl =
830 if Types.is_empty t then cont s accu more else aux more s accu t res pl
831 and cont s accu = function
832 | [] -> ResultMap.iter f accu
833 | (t,res,pl)::tl -> aux_check tl s accu (Types.diff t s) res pl
834 in
835 aux_check [] Types.empty ResultMap.empty (Types.cap t any_basic)
836 IdMap.empty (List.map descr pl)
837
838 let prod_tests (pl,t,xs) =
839 let rec aux accu q1 q2 res = function
840 | [] -> (res,q1,q2) :: accu
841 | (tp,xp,d) :: r ->
842 if (IdSet.disjoint xp xs)
843 then aux_check accu q1 q2 res tp r
844 else match d with
845 | Cup (p1,p2) -> aux (aux accu q1 q2 res (p2::r)) q1 q2 res (p1::r)
846 | Cap (p1,p2) -> aux accu q1 q2 res (p1 :: p2 :: r)
847 | Capture x -> aux accu q1 q2 (IdMap.add x SCatch res) r
848 | Constant (x,c) -> aux accu q1 q2 (IdMap.add x (SConst c) res) r
849 | Times (p1,p2) ->
850 let (pl1,t1,xs1) = q1 and (pl2,t2,xs2) = q2 in
851 let t1 = Types.cap t1 (Types.descr (accept p1)) in
852 if Types.is_empty t1 then accu
853 else let t2 = Types.cap t2 (Types.descr (accept p2)) in
854 if Types.is_empty t2 then accu
855 else
856 let q1 =
857 let xs1' = IdSet.cap (fv p1) xs in
858 if IdSet.is_empty xs1' then (pl1,t1,xs1)
859 else (NodeSet.add p1 pl1, t1, IdSet.cup xs1 xs1')
860 and q2 =
861 let xs2' = IdSet.cap (fv p2) xs in
862 if IdSet.is_empty xs2' then (pl2,t2,xs2)
863 else (NodeSet.add p2 pl2, t2, IdSet.cup xs2 xs2')
864 in
865 aux accu q1 q2 res r
866 | _ -> accu
867 and aux_check accu q1 q2 res t r =
868 List.fold_left
869 (fun accu (t1',t2') ->
870 let (pl1,t1,xs1) = q1 and (pl2,t2,xs2) = q2 in
871 let t1 = Types.cap t1 t1' in
872 if Types.is_empty t1 then accu
873 else let t2 = Types.cap t2 t2' in
874 if Types.is_empty t2 then accu
875 else aux accu (pl1,t1,xs1) (pl2,t2,xs2) res r)
876 accu (Types.Product.clean_normal (Types.Product.normal t))
877 in
878 aux_check [] ncany ncany IdMap.empty t (List.map descr pl)
879
880 end
881
882
883 module Compile =
884 struct
885 type actions =
886 | AIgnore of result
887 | AKind of actions_kind
888 and actions_kind = {
889 basic: (Types.t * result) list;
890 atoms: result Atoms.map;
891 chars: result Chars.map;
892 prod: result dispatch dispatch;
893 xml: result dispatch dispatch;
894 record: record option;
895 }
896 and record =
897 | RecLabel of label * result dispatch dispatch
898 | RecNolabel of result option * result option
899
900 and 'a dispatch =
901 | Dispatch of dispatcher * 'a array
902 | TailCall of dispatcher
903 | Ignore of 'a
904 | Impossible
905
906 and result = int * source array * int
907 and source =
908 | Catch | Const of Types.const
909 | Stack of int | Left | Right | Nil | Recompose of int * int
910
911 and return_code =
912 Types.t * int * (* accepted type, arity *)
913 int id_map option array
914
915 and interface =
916 [ `Result of int
917 | `Switch of interface * interface
918 | `None ]
919
920 and dispatcher = {
921 id : int;
922 t : Types.t;
923 pl : Normal.Nnf.t array;
924 label : label option;
925 interface : interface;
926 codes : return_code array;
927 mutable actions : actions option;
928 mutable printed : bool
929 }
930
931 let id d = d.id
932
933 let types_of_codes d = Array.map (fun (t,ar,_) -> t) d.codes
934
935 let equal_array f a1 a2 =
936 let rec aux i = (i < 0) || ((f a1.(i) a2.(i)) && (aux (i - 1))) in
937 let l1 = Array.length a1 and l2 = Array.length a2 in
938 (l1 == l2) && (aux (l1 - 1))
939
940 let array_for_all f a =
941 let rec aux f a i = (i < 0) || (f a.(i) && (aux f a (pred i))) in
942 aux f a (Array.length a - 1)
943
944 let array_for_all_i f a =
945 let rec aux f a i = (i < 0) || (f i a.(i) && (aux f a (pred i))) in
946 aux f a (Array.length a - 1)
947
948 let equal_source s1 s2 =
949 (s1 == s2) || match (s1,s2) with
950 | Const x, Const y -> Types.Const.equal x y
951 | Stack x, Stack y -> x == y
952 | Recompose (x1,x2), Recompose (y1,y2) -> (x1 == y1) && (x2 == y2)
953 | _ -> false
954
955 let equal_result (r1,s1,l1) (r2,s2,l2) =
956 (r1 == r2) && (equal_array equal_source s1 s2) && (l1 == l2)
957
958 let equal_result_dispatch d1 d2 = (d1 == d2) || match (d1,d2) with
959 | Dispatch (d1,a1), Dispatch (d2,a2) ->
960 (d1 == d2) && (equal_array equal_result a1 a2)
961 | TailCall d1, TailCall d2 -> d1 == d2
962 | Ignore a1, Ignore a2 -> equal_result a1 a2
963 | _ -> false
964
965 let immediate_res basic prod xml record =
966 let res : result option ref = ref None in
967 let chk = function Catch | Const _ -> true | _ -> false in
968 let f ((_,ret,_) as r) =
969 match !res with
970 | Some r0 when equal_result r r0 -> ()
971 | None when array_for_all chk ret -> res := Some r
972 | _ -> raise Exit in
973 (match basic with [_,r] -> f r | [] -> () | _ -> raise Exit);
974 (match prod with Ignore (Ignore r) -> f r |Impossible ->()| _->raise Exit);
975 (match xml with Ignore (Ignore r) -> f r |Impossible ->()| _->raise Exit);
976 (match record with
977 | None -> ()
978 | Some (RecLabel (_,Ignore (Ignore r))) -> f r
979 | Some (RecNolabel (Some r1, Some r2)) -> f r1; f r2
980 | _ -> raise Exit);
981 match !res with Some r -> r | None -> raise Exit
982
983 let split_kind basic prod xml record = {
984 basic = basic;
985 atoms = Atoms.mk_map (List.map (fun (t,r) -> Types.Atom.get t, r) basic);
986 chars = Chars.mk_map (List.map (fun (t,r) -> Types.Char.get t, r) basic);
987 prod = prod;
988 xml = xml;
989 record = record
990 }
991
992 let combine_kind basic prod xml record =
993 try AIgnore (immediate_res basic prod xml record)
994 with Exit -> AKind (split_kind basic prod xml record)
995
996 let combine f (disp,act) =
997 if Array.length act == 0 then Impossible
998 else
999 if (array_for_all (fun (_,ar,_) -> ar == 0) disp.codes)
1000 && (array_for_all ( f act.(0) ) act) then
1001 Ignore act.(0)
1002 else
1003 Dispatch (disp, act)
1004
1005 let detect_tail_call f = function
1006 | Dispatch (disp,branches) when array_for_all_i f branches -> TailCall disp
1007 | x -> x
1008
1009 let detect_right_tail_call =
1010 detect_tail_call
1011 (fun i (code,ret,_) ->
1012 (i == code) &&
1013 let ar = Array.length ret in
1014 (array_for_all_i
1015 (fun pos ->
1016 function Stack j when pos + j == ar -> true | _ -> false)
1017 ret
1018 )
1019 )
1020
1021 let detect_left_tail_call =
1022 detect_tail_call
1023 (fun i ->
1024 function
1025 | Ignore (code,ret,_) when (i == code) ->
1026 let ar = Array.length ret in
1027 array_for_all_i
1028 (fun pos ->
1029 function Stack j when pos + j == ar -> true | _ -> false)
1030 ret
1031 | _ -> false
1032 )
1033
1034 let cur_id = State.ref "Patterns.cur_id" 0
1035 (* TODO: save dispatchers ? *)
1036
1037 module NfMap = Map.Make(Normal.Nnf)
1038 module NfSet = Set.Make(Normal.Nnf)
1039
1040 module DispMap = Map.Make(Custom.Pair(Types)(Custom.Array(Normal.Nnf)))
1041
1042 (* Try with a hash-table ! *)
1043
1044 let dispatchers = ref DispMap.empty
1045
1046
1047 let generated = ref 0
1048 let to_generate = ref []
1049 let timer_disp = Stats.Timer.create "Patterns.dispatcher loop"
1050
1051 let rec print_iface ppf = function
1052 | `Result i -> Format.fprintf ppf "Result(%i)" i
1053 | `Switch (yes,no) -> Format.fprintf ppf "Switch(%a,%a)"
1054 print_iface yes print_iface no
1055 | `None -> Format.fprintf ppf "None"
1056
1057 let dump_disp disp =
1058 let ppf = Format.std_formatter in
1059 Format.fprintf ppf "Dispatcher t=%a@." Types.Print.print disp.t;
1060 Array.iter (fun p ->
1061 Format.fprintf ppf " pat %a@." Normal.Nnf.print p;
1062 ) disp.pl
1063
1064 let first_lab t reqs =
1065 let aux l req = min l (Normal.Nnf.first_label req) in
1066 let lab =
1067 Array.fold_left aux (Types.Record.first_label t) reqs in
1068 if lab == LabelPool.dummy_max then None else Some lab
1069
1070 let dispatcher t pl : dispatcher =
1071 try DispMap.find (t,pl) !dispatchers
1072 with Not_found ->
1073 let lab = first_lab t pl in
1074 let nb = ref 0 in
1075 let codes = ref [] in
1076 let rec aux t arity i accu =
1077 if i == Array.length pl
1078 then (incr nb; let r = Array.of_list (List.rev accu) in
1079 codes := (t,arity,r)::!codes; `Result (!nb - 1))
1080 else
1081 let (_,tp,v) = pl.(i) in
1082 let a1 = Types.cap t tp in
1083 if Types.is_empty a1 then
1084 `Switch (`None,aux t arity (i+1) (None::accu))
1085 else
1086 let a2 = Types.diff t tp in
1087 let accu' = Some (IdMap.num arity v) :: accu in
1088 if Types.is_empty a2 then
1089 `Switch (aux t (arity + (IdSet.length v)) (i+1) accu',`None)
1090 else
1091 `Switch (aux a1 (arity + (IdSet.length v)) (i+1) accu',
1092 aux a2 arity (i+1) (None::accu))
1093
1094 (* Unopt version:
1095 `Switch
1096 (
1097 aux (Types.cap t tp) (arity + (IdSet.length v)) (i+1) accu',
1098 aux (Types.diff t tp) arity (i+1) accu
1099 )
1100 *)
1101
1102 in
1103 Stats.Timer.start timer_disp;
1104 let iface = if Types.is_empty t then `None else aux t 0 0 [] in
1105 Stats.Timer.stop timer_disp ();
1106 let res = {
1107 id = !cur_id;
1108 t = t;
1109 label = lab;
1110 pl = pl;
1111 interface = iface;
1112 codes = Array.of_list (List.rev !codes);
1113 actions = None; printed = false
1114 } in
1115 incr cur_id;
1116 dispatchers := DispMap.add (t,pl) res !dispatchers;
1117 res
1118
1119 let find_code d a =
1120 let rec aux i = function
1121 | `Result code -> code
1122 | `None ->
1123 Format.fprintf Format.std_formatter
1124 "IFACE=%a@." print_iface d.interface;
1125 for i = 0 to Array.length a - 1 do
1126 Format.fprintf Format.std_formatter
1127 "a.(i)=%b@." (a.(i) != None)
1128 done;
1129 assert false
1130 | `Switch (yes,_) when a.(i) != None -> aux (i + 1) yes
1131 | `Switch (_,no) -> aux (i + 1) no in
1132 aux 0 d.interface
1133
1134 let create_result pl =
1135 let aux x accu = match x with Some b -> b @ accu | None -> accu in
1136 Array.of_list (Array.fold_right aux pl [])
1137
1138 let return disp pl f ar =
1139 let aux = function x::_ -> Some (f x) | [] -> None in
1140 let final = Array.map aux pl in
1141 (find_code disp final, create_result final, ar)
1142
1143 let conv_source = function
1144 | Normal.SCatch -> Catch
1145 | Normal.SConst c -> Const c
1146
1147 let return_basic disp selected =
1148 let aux_final res = IdMap.map_to_list conv_source res in
1149 return disp selected aux_final 0
1150
1151 (* let print_idset ppf s =
1152 let s = String.concat "," (List.map (fun x -> Ident.to_string x) s) in
1153 Format.fprintf ppf "{%s}" s
1154 let print_idmap ppf s =
1155 print_idset ppf (IdMap.domain s) *)
1156
1157 let merge_res_prod ofs1 ofs2 (lvars,lnils,lres) (rvars,rnils,rres) extra =
1158 let lres =
1159 IdMap.union_disj
1160 (IdMap.map (fun i -> Stack (ofs1 + ofs2 - i)) lres)
1161 (IdMap.union_disj
1162 (IdMap.constant Left lvars) (IdMap.constant Nil lnils)) in
1163 let rres =
1164 IdMap.union_disj
1165 (IdMap.map (fun i -> Stack (ofs2 - i)) rres)
1166 (IdMap.union_disj
1167 (IdMap.constant Right rvars) (IdMap.constant Nil rnils)) in
1168 let sub =
1169 IdMap.merge
1170 (fun l r ->
1171 match l,r with
1172 | Left,Right -> Catch
1173 | _ ->
1174 let l =
1175 match l with Left -> (-1) | Nil -> (-2)
1176 | Stack i -> i | _ -> assert false in
1177 let r =
1178 match r with Right -> (-1) | Nil -> (-2)
1179 | Stack i -> i | _ -> assert false in
1180 Recompose (l,r)) lres rres in
1181 IdMap.map_to_list (fun x -> x)
1182 (IdMap.union_disj sub (IdMap.map conv_source extra))
1183
1184
1185 module TypeList = SortedList.Make(Types)
1186
1187 let dispatch_basic disp : (Types.t * result) list =
1188 let tests =
1189 let accu = ref [] in
1190 let aux i res t = accu := (t, [i,res]) :: !accu in
1191 Array.iteri (fun i p -> Normal.basic_tests (aux i) p) disp.pl;
1192 TypeList.Map.get (TypeList.Map.from_list (@) !accu) in
1193
1194 let t = Types.cap any_basic disp.t in
1195 let accu = ref [] in
1196 let rec aux (success : (int * Normal.result) list) t l =
1197 if Types.non_empty t
1198 then match l with
1199 | [] ->
1200 let selected = Array.create (Array.length disp.pl) [] in
1201 let add (i,res) = selected.(i) <- res :: selected.(i) in
1202 List.iter add success;
1203 accu := (t, return_basic disp selected) :: !accu
1204 | (ty,i) :: rem ->
1205 aux (i @ success) (Types.cap t ty) rem;
1206 aux success (Types.diff t ty) rem
1207 in
1208 aux [] t tests;
1209 !accu
1210
1211 let get_tests facto pl f t d post =
1212 let pl = Array.map (List.map f) pl in
1213
1214 (* Collect all subrequests *)
1215 let aux reqs (req,_) = NfSet.add req reqs in
1216 let reqs = Array.fold_left (List.fold_left aux) NfSet.empty pl in
1217 let reqs = Array.of_list (NfSet.elements reqs) in
1218
1219 (* Map subrequest -> idx in reqs *)
1220 let idx = ref NfMap.empty in
1221 Array.iteri (fun i req -> idx := NfMap.add req i !idx) reqs;
1222 let idx = !idx in
1223
1224 (* Build dispatcher *)
1225 let reqs_facto =
1226 if facto then Array.map (Normal.factorize t) reqs
1227 else Array.map (fun r -> [],[],r) reqs in
1228 let reqs = Array.map (fun (_,_,req) -> req) reqs_facto in
1229
1230 let disp = dispatcher t reqs in
1231
1232 (* Build continuation *)
1233 let result (t,ar,m) =
1234 let get (req,info) a =
1235 let i = NfMap.find req idx in
1236 let (var,nil,_) = reqs_facto.(i) in
1237 match m.(i) with Some res -> ((var,nil,res),info)::a | _ -> a in
1238 let pl = Array.map (fun l -> List.fold_right get l []) pl in
1239 d t ar pl
1240 in
1241 let res = Array.map result disp.codes in
1242 post (disp,res)
1243
1244 type 'a rhs = Match of (id * int) list * 'a | Fail
1245 let make_branches t brs =
1246 let t0 = ref t in
1247 let aux (p,e) =
1248 let xs = fv p in
1249 let tp = Types.descr (accept p) in
1250 let nnf = (Normal.NodeSet.singleton p, Types.cap !t0 tp, xs) in
1251 t0 := Types.diff !t0 tp;
1252 [(nnf, (xs, e))] in
1253 let res _ _ pl =
1254 let aux r = function
1255 | [(([],[],res), (xs,e))] -> assert (r == Fail);
1256 let m = List.map (fun x -> (x,IdMap.assoc x res)) xs in
1257 Match (m,e)
1258 | [] -> r | _ -> assert false in
1259 Array.fold_left aux Fail pl in
1260 let pl = Array.map aux (Array.of_list brs) in
1261 get_tests false pl (fun x -> x) t res (fun x -> x)
1262
1263
1264 let rec dispatch_prod0 disp t pl =
1265 get_tests true pl
1266 (fun (res,p,q) -> p, (res,q))
1267 (Types.Product.pi1 t)
1268 (dispatch_prod1 disp t)
1269 (fun x -> detect_left_tail_call (combine equal_result_dispatch x))
1270 and dispatch_prod1 disp t t1 ar1 pl =
1271 get_tests true pl
1272 (fun (ret1, (res,q)) -> q, (ret1,res) )
1273 (Types.Product.pi2_restricted t1 t)
1274 (dispatch_prod2 disp ar1)
1275 (fun x -> detect_right_tail_call (combine equal_result x))
1276 and dispatch_prod2 disp ar1 t2 ar2 pl =
1277 let aux_final (ret2, (ret1, res)) = merge_res_prod ar1 ar2 ret1 ret2 res in
1278 return disp pl aux_final (ar1 + ar2)
1279
1280 let dispatch_prod disp pl =
1281 let t = Types.Product.get disp.t in
1282 dispatch_prod0 disp t
1283 (Array.map (fun p -> Normal.NLineProd.elements p.Normal.nprod) pl)
1284 (* dispatch_prod0 disp t (Array.map Normal.prod_tests disp.pl) *)
1285
1286 let dispatch_xml disp pl =
1287 let t = Types.Product.get ~kind:`XML disp.t in
1288 dispatch_prod0 disp t
1289 (Array.map (fun p -> Normal.NLineProd.elements p.Normal.nxml) pl)
1290
1291 let dispatch_record disp pl : record option =
1292 let t = disp.t in
1293 if not (Types.Record.has_record t) then None
1294 else
1295 match disp.label with
1296 | None ->
1297 let (some,none) = Types.Record.empty_cases t in
1298 let some =
1299 if some then
1300 let pl = Array.map (fun p -> match p.Normal.nrecord with
1301 | Normal.RecNolabel (Some x,_) -> [x]
1302 | Normal.RecNolabel (None,_) -> []
1303 | _ -> assert false) pl in
1304 Some (return disp pl (IdMap.map_to_list conv_source) 0)
1305 else None
1306 in
1307 let none =
1308 if none then
1309 let pl = Array.map (fun p -> match p.Normal.nrecord with
1310 | Normal.RecNolabel (_,Some x) -> [x]
1311 | Normal.RecNolabel (_,None) -> []
1312 | _ -> assert false) pl in
1313 Some (return disp pl (IdMap.map_to_list conv_source) 0)
1314 else None
1315 in
1316 Some (RecNolabel (some,none))
1317 | Some lab ->
1318 let t = Types.Record.split t lab in
1319 let pl = Array.map (fun p -> match p.Normal.nrecord with
1320 | Normal.RecLabel (_,l) ->
1321 Normal.NLineProd.elements l
1322 | _ -> assert false) pl in
1323 Some (RecLabel (lab,dispatch_prod0 disp t pl))
1324
1325 let iter_disp_disp f g = function
1326 | Dispatch (d,a) -> f d; Array.iter g a
1327 | TailCall d -> f d
1328 | Ignore a -> g a
1329 | Impossible -> ()
1330
1331 let iter_disp_prod f = iter_disp_disp f (iter_disp_disp f (fun _ -> ()))
1332
1333 let rec iter_disp_actions f = function
1334 | AIgnore _ -> ()
1335 | AKind k ->
1336 iter_disp_prod f k.prod;
1337 iter_disp_prod f k.xml;
1338 (match k.record with Some (RecLabel (_,p)) -> iter_disp_prod f p
1339 | _ -> ())
1340
1341 let actions disp =
1342 match disp.actions with
1343 | Some a -> a
1344 | None ->
1345 let pl = Array.map (Normal.nnf disp.label disp.t) disp.pl in
1346
1347 let a = combine_kind
1348 (dispatch_basic disp)
1349 (dispatch_prod disp pl)
1350 (dispatch_xml disp pl)
1351 (dispatch_record disp pl)
1352 in
1353 disp.actions <- Some a;
1354 iter_disp_actions (fun d -> to_generate := d :: !to_generate) a;
1355 incr generated;
1356 a
1357
1358 let to_print = ref []
1359
1360 module DSET = Set.Make (struct type t = int let compare (x:t) (y:t) = x - y end)
1361 let printed = ref DSET.empty
1362
1363 let queue d =
1364 if not d.printed then (
1365 d.printed <- true;
1366 to_print := d :: !to_print
1367 )
1368
1369 let rec print_source lhs ppf = function
1370 | Catch -> Format.fprintf ppf "v"
1371 | Const c -> Types.Print.print_const ppf c
1372 | Nil -> Format.fprintf ppf "`nil"
1373 | Left -> Format.fprintf ppf "v1"
1374 | Right -> Format.fprintf ppf "v2"
1375 | Stack i -> Format.fprintf ppf "%s" (List.nth lhs (i-1))
1376 | Recompose (i,j) ->
1377 Format.fprintf ppf "(%s,%s)"
1378 (match i with (-1) -> "v1" | (-2) -> "nil"
1379 | i -> List.nth lhs (i-1))
1380 (match j with (-1) -> "v2" | (-2) -> "nil"
1381 | j -> List.nth lhs (j-1))
1382
1383 let print_result lhs ppf =
1384 Array.iteri
1385 (fun i s ->
1386 if i > 0 then Format.fprintf ppf ",";
1387 print_source lhs ppf s;
1388 )
1389
1390 let print_ret lhs ppf (code,ret,ar) =
1391 Format.fprintf ppf "$%i" code;
1392 if Array.length ret <> 0 then
1393 Format.fprintf ppf "(%a)" (print_result lhs) ret
1394
1395 let print_ret_opt ppf = function
1396 | None -> Format.fprintf ppf "*"
1397 | Some r -> print_ret [] ppf r
1398
1399 let gen_lhs (code,prefix,d) =
1400 let arity = match d.codes.(code) with (_,a,_) -> a in
1401 let r = ref [] in
1402 for i = 0 to arity - 1 do r := Format.sprintf "%s%i" prefix i :: !r done;
1403 !r
1404
1405 let print_kind ppf actions =
1406 let print_lhs ppf (code,lhs) =
1407 Format.fprintf ppf "$%i(" code;
1408 let rec aux = function
1409 | [] -> ()
1410 | [x] -> Format.fprintf ppf "%s" x
1411 | x::r -> Format.fprintf ppf "%s,x" x; aux r
1412 in aux lhs;
1413 Format.fprintf ppf ")" in
1414 let print_basic (t,ret) =
1415 Format.fprintf ppf " | %a -> %a@\n"
1416 Types.Print.print t
1417 (print_ret []) ret
1418 in
1419 let print_prod2 lhs = function
1420 | Impossible -> assert false
1421 | Ignore r ->
1422 Format.fprintf ppf "%a\n"
1423 (print_ret lhs) r
1424 | TailCall d ->
1425 queue d;
1426 Format.fprintf ppf "disp_%i v2@\n" d.id
1427 | Dispatch (d, branches) ->
1428 queue d;
1429 Format.fprintf ppf "@\n match disp_%i v2 with@\n" d.id;
1430 Array.iteri
1431 (fun code r ->
1432 let rhs = gen_lhs (code,"r",d) in
1433 Format.fprintf ppf " | %a -> %a@\n"
1434 print_lhs (code,rhs)
1435 (print_ret (rhs@lhs)) r;
1436 )
1437 branches
1438 in
1439 let print_prod prefix ppf = function
1440 | Impossible -> ()
1441 | Ignore d2 ->
1442 Format.fprintf ppf " | %s(v1,v2) -> " prefix;
1443 print_prod2 [] d2
1444 | TailCall d ->
1445 queue d;
1446 Format.fprintf ppf " | %s(v1,v2) -> disp_%i v1@\n" prefix d.id
1447 | Dispatch (d,branches) ->
1448 queue d;
1449 Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix;
1450 Format.fprintf ppf " match disp_%i v1 with@\n" d.id;
1451 Array.iteri
1452 (fun code d2 ->
1453 let lhs = gen_lhs (code, "l", d) in
1454 Format.fprintf ppf " | %a -> " print_lhs (code,lhs);
1455 print_prod2 lhs d2;
1456 )
1457 branches
1458 in
1459 let rec print_record_opt ppf = function
1460 | None -> ()
1461 | Some (RecLabel (l,d)) ->
1462 let l = LabelPool.value l in
1463 print_prod ("record:"^(Label.to_string l)) ppf d
1464 | Some (RecNolabel (r1,r2)) ->
1465 Format.fprintf ppf " | Record -> @\n";
1466 Format.fprintf ppf " SomeField:%a;NoField:%a@\n"
1467 print_ret_opt r1 print_ret_opt r2
1468 in
1469
1470 List.iter print_basic actions.basic;
1471 print_prod "" ppf actions.prod;
1472 print_prod "XML" ppf actions.xml;
1473 print_record_opt ppf actions.record
1474
1475 let print_actions ppf = function
1476 | AKind k -> print_kind ppf k
1477 | AIgnore r -> Format.fprintf ppf "v -> %a@\n" (print_ret []) r
1478
1479 let print_dispatcher ppf d =
1480 Format.fprintf ppf "Dispatcher %i accepts [%a]@\n"
1481 d.id Types.Print.print (Types.normalize d.t);
1482 let print_code code (t, arity, m) =
1483 Format.fprintf ppf " Returns $%i(arity=%i) for [%a]"
1484 code arity
1485 Types.Print.print (Types.normalize t);
1486 Format.fprintf ppf "@\n";
1487 in
1488 Array.iteri print_code d.codes;
1489 Array.iter (fun p ->
1490 Format.fprintf ppf " pat %a@." Normal.Nnf.print p;
1491 ) d.pl;
1492
1493 Format.fprintf ppf "let disp_%i = function@\n" d.id;
1494 print_actions ppf (actions d);
1495 Format.fprintf ppf "====================================@\n"
1496
1497
1498 let rec print_dispatchers ppf =
1499 match !to_print with
1500 | [] -> ()
1501 | d :: rem ->
1502 to_print := rem;
1503 print_dispatcher ppf d;
1504 print_dispatchers ppf
1505
1506
1507 let show ppf t pl =
1508 let disp = dispatcher t pl in
1509 queue disp;
1510 print_dispatchers ppf
1511
1512 let debug_compile ppf t pl =
1513 let t = Types.descr t in
1514
1515 let pl = Array.of_list
1516 (List.map (fun p -> ([p],Types.descr (accept p),fv p)) pl) in
1517 show ppf t pl;
1518 Format.fprintf ppf "# compiled states: %i@\n" !generated
1519
1520 let () =
1521 Stats.register Stats.Summary
1522 (fun ppf ->
1523 let i = !generated in
1524 Format.fprintf ppf "Number of compiled states: %i@." i;
1525 while !to_generate != [] do
1526 let d = List.hd !to_generate in
1527 to_generate := List.tl !to_generate;
1528 ignore (actions d)
1529 done;
1530 let j = !generated in
1531 Format.fprintf ppf "Total number of states: %i@." j)
1532 end
1533
1534
1535 (****** More efficient compilation (less optimized) ******)
1536
1537 (*
1538 module Compile2 =
1539 struct
1540 type source =
1541 | Catch | Const of Types.const
1542 | Stack of int | Left | Right | Nil | Recompose of int * int
1543
1544 let compare_source s1 s2 = match (s1,s2) with
1545 | Catch, Catch | Left,Left | Right,Right | Nil,Nil -> 0
1546 | Catch, _ -> -1 | _,Catch -> 1
1547 | Left,_ -> -1 | _, Left -> 1
1548 | Right,_ -> -1 | _, Right -> 1
1549 | Nil,_ -> -1 | _, Nil -> 1
1550 | Const c1, Const c2 -> Types.Const.compare c1 c2
1551 | Const _, _ -> -1 | _, Const _ -> 1
1552 | Stack i, Stack j -> i - j
1553 | Stack _, _ -> -1
1554 | _, Stack _ -> 1
1555 | Recompose (i,j), Recompose (i',j') -> if i == j then i' - j' else i - j
1556
1557 module Req = struct
1558 include Custom.Dummy
1559
1560 type t =
1561 | RFail
1562 | RBinds of source id_map
1563 | RCap of t * t
1564 | RCup of t * t
1565 | RConstr of Types.t
1566 | RTimes of node * node * IdSet.t * Types.t
1567 | RXml of node * node * IdSet.t * Types.t
1568 | RRecord of label * node * IdSet.t * Types.t
1569
1570 let rec compare r1 r2 = match r1,r2 with
1571 | RFail, RFail -> 0
1572 | RFail, _ -> -1
1573 | _, RFail -> 1
1574 | RBinds b1, RBinds b2 -> IdMap.compare compare_source b1 b2
1575 | RBinds _, _ -> -1
1576 | _, RBinds _ -> 1
1577 | RCap (r1,r2), RCap (r1',r2')
1578 | RCup (r1,r2), RCup (r1',r2') ->
1579 let c = compare r1 r1' in if c !=0 then c else compare r2 r2'
1580 | RCap _, _ -> -1
1581 | _, RCap _ -> 1
1582 | RCup _, _ -> -1
1583 | _, RCup _ -> 1
1584 | RConstr t1, RConstr t2 -> Types.compare t1 t2
1585 | RConstr _, _ -> -1
1586 | _, RConstr _ -> 1
1587 | RTimes (q1,q2,xs,_), RTimes (q1',q2',xs',_)
1588 | RXml (q1,q2,xs,_), RXml (q1', q2',xs',_) ->
1589 let c = Node.compare q1 q1' in if c != 0 then c
1590 else let c = Node.compare q2 q2' in if c !=0 then c
1591 else IdSet.compare xs xs'
1592 | RTimes _, _ -> -1
1593 | _, RTimes _ -> 1
1594 | RXml _, _ -> -1
1595 | _, RXml _ -> 1
1596 | RRecord (l,q,xs,_), RRecord (l',q',xs',_) ->
1597 let c = LabelPool.compare l l' in if c != 0 then c
1598 else let c = Node.compare q q' in if c != 0 then c
1599 else IdSet.compare xs xs'
1600
1601 let rec acc = function
1602 | RFail -> Types.empty
1603 | RBinds _ -> Types.any
1604 | RCap (r1,r2) -> Types.cap (acc r1) (acc r2)
1605 | RCup (r1,r2) -> Types.cup (acc r1) (acc r2)
1606 | RConstr t | RTimes (_,_,_,t) | RXml (_,_,_,t) | RRecord (_,_,_,t) -> t
1607
1608 let rec vars = function
1609 | RFail | RConstr _ -> IdSet.empty
1610 | RBinds b -> IdMap.domain b
1611 | RCap (r1,r2) -> IdSet.cup (vars r1) (vars r2)
1612 | RCup (r1,r2) -> vars r1
1613 | RTimes (_,_,xs,_) | RXml (_,_,xs,_) | RRecord (_,_,xs,_) -> xs
1614
1615 let rec first_label = function
1616 | RConstr t -> Types.Record.first_label t
1617 | RCap (r1,r2) | RCup (r1,r2) -> min (first_label r1) (first_label r2)
1618 | RRecord (l,_,_,_) -> l
1619 | _ -> LabelPool.dummy_max
1620
1621 let accpat (t,_,_) = t
1622
1623 let rec make t (tp,vp,d) xs =
1624 if Types.disjoint t tp then RFail
1625 else if IdSet.disjoint xs vp
1626 then if Types.subtype t tp then RBinds IdMap.empty
1627 else RConstr tp
1628 else match d with
1629 | Constr t -> assert false
1630 | Cup (p1,p2) ->
1631 (match make t p1 xs with
1632 | RFail -> make t p2 xs
1633 | RBinds _ as r1 -> r1
1634 | r1 -> match make t p2 xs with
1635 | RFail -> r1
1636 | r2 -> RCup (r1,r2))
1637 | Cap (p1,p2) ->
1638 (match make t p1 xs, make t p2 xs with
1639 | RBinds b1, RBinds b2 -> RBinds (IdMap.union_disj b1 b2)
1640 | r1,r2 -> RCap (r1,r2))
1641 | Times (q1,q2) ->
1642 RTimes (q1,q2, IdSet.cap xs vp, tp)
1643 | Xml (q1,q2) ->
1644 RXml (q1,q2, IdSet.cap xs vp, tp)
1645 | Record (l,q) ->
1646 RRecord (l,q, IdSet.cap xs vp, tp)
1647 | Capture x ->
1648 RBinds (IdMap.singleton x Catch)
1649 | Constant (x,c) ->
1650 RBinds (IdMap.singleton x (Const c))
1651 | Dummy -> assert false
1652
1653 let rec simplify t = function
1654 | (RFail | RBinds _) as r -> r
1655 | RConstr s as r ->
1656 if Types.subtype t s then RBinds IdMap.empty
1657 else if Types.disjoint t s then RFail
1658 else r
1659 | RCup (r1,r2) ->
1660 (match simplify t r1 with
1661 | RBinds _ as r -> r
1662 | RFail -> simplify t r2
1663 | r1 -> match simplify t r2 with
1664 | RFail -> r1
1665 | r2 -> RCup (r1,r2))
1666 | RCap (r1,r2) ->
1667 (match simplify t r1 with
1668 | RFail -> RFail
1669 | r1 ->
1670 match simplify t r2 with
1671 | RFail -> RFail
1672 | RBinds b2 ->
1673 (match r1 with
1674 | RBinds b1 -> RBinds (IdMap.union_disj b1 b2)
1675 | _ -> RCap (r1,r2))
1676 | r2 -> RCap (r1,r2))
1677 | (RTimes (_,_,_,s) | RXml (_,_,_,s) | RRecord (_,_,_,s)) as r ->
1678 if Types.disjoint t s then RFail
1679 else r
1680 end
1681
1682
1683 type actions =
1684 | AIgnore of result
1685 | AKind of actions_kind
1686 and actions_kind = {
1687 basic: (Types.t * result) list;
1688 atoms: result Atoms.map;
1689 chars: result Chars.map;
1690 prod: result dispatch dispatch;
1691 xml: result dispatch dispatch;
1692 record: record option;
1693 }
1694 and record =
1695 | RecLabel of label * result dispatch dispatch
1696 | RecNolabel of result option * result option
1697
1698 and 'a dispatch =
1699 | Dispatch of dispatcher * 'a array
1700 | TailCall of dispatcher
1701 | Ignore of 'a
1702 | Impossible
1703
1704 and result = int * source array * int
1705
1706 and return_code =
1707 Types.t * int * (* accepted type, arity *)
1708 int id_map option array
1709
1710 and interface =
1711 [ `Result of int
1712 | `Switch of interface * interface
1713 | `None ]
1714
1715 and dispatcher = {
1716 id : int;
1717 t : Types.t;
1718 pl : Req.t array;
1719 label : label option;
1720 interface : interface;
1721 codes : return_code array;
1722 mutable actions : actions option;
1723 mutable printed : bool
1724 }
1725
1726 let types_of_codes d = Array.map (fun (t,ar,_) -> t) d.codes
1727
1728 let equal_array f a1 a2 =
1729 let rec aux i = (i < 0) || ((f a1.(i) a2.(i)) && (aux (i - 1))) in
1730 let l1 = Array.length a1 and l2 = Array.length a2 in
1731 (l1 == l2) && (aux (l1 - 1))
1732
1733 let array_for_all f a =
1734 let rec aux f a i = (i < 0) || (f a.(i) && (aux f a (pred i))) in
1735 aux f a (Array.length a - 1)
1736
1737 let array_for_all_i f a =
1738 let rec aux f a i = (i < 0) || (f i a.(i) && (aux f a (pred i))) in
1739 aux f a (Array.length a - 1)
1740
1741 let equal_source s1 s2 =
1742 (s1 == s2) || match (s1,s2) with
1743 | Const x, Const y -> Types.Const.equal x y
1744 | Stack x, Stack y -> x == y
1745 | Recompose (x1,x2), Recompose (y1,y2) -> (x1 == y1) && (x2 == y2)
1746 | _ -> false
1747
1748 let equal_result (r1,s1,l1) (r2,s2,l2) =
1749 (r1 == r2) && (equal_array equal_source s1 s2) && (l1 == l2)
1750
1751 let equal_result_dispatch d1 d2 = (d1 == d2) || match (d1,d2) with
1752 | Dispatch (d1,a1), Dispatch (d2,a2) ->
1753 (d1 == d2) && (equal_array equal_result a1 a2)
1754 | TailCall d1, TailCall d2 -> d1 == d2
1755 | Ignore a1, Ignore a2 -> equal_result a1 a2
1756 | _ -> false
1757
1758 let immediate_res basic prod xml record =
1759 let res : result option ref = ref None in
1760 let chk = function Catch | Const _ -> true | _ -> false in
1761 let f ((_,ret,_) as r) =
1762 match !res with
1763 | Some r0 when equal_result r r0 -> ()
1764 | None when array_for_all chk ret -> res := Some r
1765 | _ -> raise Exit in
1766 (match basic with [_,r] -> f r | [] -> () | _ -> raise Exit);
1767 (match prod with Ignore (Ignore r) -> f r |Impossible ->()| _->raise Exit);
1768 (match xml with Ignore (Ignore r) -> f r |Impossible ->()| _->raise Exit);
1769 (match record with
1770 | None -> ()
1771 | Some (RecLabel (_,Ignore (Ignore r))) -> f r
1772 | Some (RecNolabel (Some r1, Some r2)) -> f r1; f r2
1773 | _ -> raise Exit);
1774 match !res with Some r -> r | None -> raise Exit
1775
1776 let split_kind basic prod xml record = {
1777 basic = basic;
1778 atoms = Atoms.mk_map (List.map (fun (t,r) -> Types.Atom.get t, r) basic);
1779 chars = Chars.mk_map (List.map (fun (t,r) -> Types.Char.get t, r) basic);
1780 prod = prod;
1781 xml = xml;
1782 record = record
1783 }
1784
1785 let combine_kind basic prod xml record =
1786 try AIgnore (immediate_res basic prod xml record)
1787 with Exit -> AKind (split_kind basic prod xml record)
1788
1789 let combine f (disp,act) =
1790 if Array.length act == 0 then Impossible
1791 else
1792 if (array_for_all (fun (_,ar,_) -> ar == 0) disp.codes)
1793 && (array_for_all ( f act.(0) ) act) then
1794 Ignore act.(0)
1795 else
1796 Dispatch (disp, act)
1797
1798 let detect_tail_call f = function
1799 | Dispatch (disp,branches) when array_for_all_i f branches -> TailCall disp
1800 | x -> x
1801
1802 let detect_right_tail_call =
1803 detect_tail_call
1804 (fun i (code,ret,_) ->
1805 (i == code) &&
1806 let ar = Array.length ret in
1807 (array_for_all_i
1808 (fun pos ->
1809 function Stack j when pos + j == ar -> true | _ -> false)
1810 ret
1811 )
1812 )
1813
1814 let detect_left_tail_call =
1815 detect_tail_call
1816 (fun i ->
1817 function
1818 | Ignore (code,ret,_) when (i == code) ->
1819 let ar = Array.length ret in
1820 array_for_all_i
1821 (fun pos ->
1822 function Stack j when pos + j == ar -> true | _ -> false)
1823 ret
1824 | _ -> false
1825 )
1826
1827 let cur_id = State.ref "Patterns.cur_id" 0
1828 (* TODO: save dispatchers ? *)
1829
1830 module DispMap = Map.Make(Custom.Pair(Types)(Custom.Array(Req)))
1831
1832 (* Try with a hash-table ! *)
1833
1834 let dispatchers = ref DispMap.empty
1835
1836
1837 let generated = ref 0
1838 let to_generate = ref []
1839 let timer_disp = Stats.Timer.create "Patterns.dispatcher loop"
1840
1841 let rec print_iface ppf = function
1842 | `Result i -> Format.fprintf ppf "Result(%i)" i
1843 | `Switch (yes,no) -> Format.fprintf ppf "Switch(%a,%a)"
1844 print_iface yes print_iface no
1845 | `None -> Format.fprintf ppf "None"
1846
1847 let first_lab t pl =
1848 let aux l r = min l (Req.first_label r) in
1849 let lab = Array.fold_left aux (Types.Record.first_label t) pl in
1850 if lab == LabelPool.dummy_max then None else Some lab
1851
1852 let dispatcher t pl : dispatcher =
1853 try DispMap.find (t,pl) !dispatchers
1854 with Not_found ->
1855 let lab = first_lab t pl in
1856 let nb = ref 0 in
1857 let codes = ref [] in
1858 let rec aux t arity i accu =
1859 if i == Array.length pl
1860 then (incr nb; let r = Array.of_list (List.rev accu) in
1861 codes := (t,arity,r)::!codes; `Result (!nb - 1))
1862 else
1863 let r = pl.(i) in
1864 let tp = Req.acc r in
1865 let v = Req.vars r in
1866
1867 let a1 = Types.cap t tp in
1868 if Types.is_empty a1 then
1869 `Switch (`None,aux t arity (i+1) (None::accu))
1870 else
1871 let a2 = Types.diff t tp in
1872 let accu' = Some (IdMap.num arity v) :: accu in
1873 if Types.is_empty a2 then
1874 `Switch (aux t (arity + (IdSet.length v)) (i+1) accu',`None)
1875 else
1876 `Switch (aux a1 (arity + (IdSet.length v)) (i+1) accu',
1877 aux a2 arity (i+1) (None::accu))
1878
1879 (* Unopt version:
1880 `Switch
1881 (
1882 aux (Types.cap t tp) (arity + (IdSet.length v)) (i+1) accu',
1883 aux (Types.diff t tp) arity (i+1) accu
1884 )
1885 *)
1886
1887 in
1888 Stats.Timer.start timer_disp;
1889 let iface = if Types.is_empty t then `None else aux t 0 0 [] in
1890 Stats.Timer.stop timer_disp ();
1891 let res = {
1892 id = !cur_id;
1893 t = t;
1894 label = lab;
1895 pl = pl;
1896 interface = iface;
1897 codes = Array.of_list (List.rev !codes);
1898 actions = None; printed = false
1899 } in
1900 incr cur_id;
1901 dispatchers := DispMap.add (t,pl) res !dispatchers;
1902 res
1903
1904 let find_code d a =
1905 let rec aux i = function
1906 | `Result code -> code
1907 | `Switch (yes,no) -> aux (i + 1) (if a.(i) == None then no else yes)
1908 | `None -> assert false in
1909 aux 0 d.interface
1910
1911 let create_result pl =
1912 let aux x accu = match x with
1913 | Some b -> (List.map snd (IdMap.get b)) @ accu
1914 | None -> accu in
1915 Array.of_list (Array.fold_right aux pl [])
1916
1917 let rec basic_tests t0 d tests = match d with
1918 | Req.RBinds b -> (fun () -> Some b)
1919 | Req.RCup (p1,p2) ->
1920 let f1 = basic_tests t0 p1 tests and f2 = basic_tests t0 p2 tests in
1921 (fun () -> match f1 () with
1922 | None -> f2 ()
1923 | Some _ as r -> r)
1924 | Req.RCap (p1,p2) ->
1925 let f1 = basic_tests t0 p1 tests and f2 = basic_tests t0 p2 tests in
1926 (fun () -> match f1 () with
1927 | None -> None
1928 | Some b1 -> match f2 () with
1929 | None -> None
1930 | Some b2 -> Some (IdMap.union_disj b1 b2))
1931 | Req.RConstr s ->
1932 let test = ref false in
1933 tests := (test,Types.cap any_basic s) :: !tests;
1934 (fun () -> if !test then Some IdMap.empty else None)
1935 | _ -> (fun () -> None)
1936
1937 let reg_test tests t0 q xs : int Ident.id_map option ref =
1938 let test = ref None in
1939 tests := (test, Req.make t0 q.descr xs) :: !tests;
1940 test
1941
1942 let reg_test_type tests t : int Ident.id_map option ref =
1943 let test = ref None in
1944 tests := (test, Req.RConstr t) :: !tests;
1945 test
1946
1947 let rec map_filter f = function
1948 | [] -> []
1949 | hd::tl ->
1950 match f hd with
1951 | None -> map_filter f tl
1952 | Some x -> x :: (map_filter f tl)
1953
1954 (*
1955 let cup x y t =
1956 match x t with
1957 | `Binds _ as r1 -> r1
1958 | `Fail -> y t
1959 | r1 -> match y t with
1960 | `Fail -> r1
1961 | r2 -> `Cup (r1,r2)
1962
1963 let cap x y t =
1964 match x t with
1965 | `Fail -> `Fail
1966 | `Binds b1 as r1 ->
1967 (match y t with
1968 | `Fail -> `Fail
1969 | `Binds b2 -> `Binds (LabelMap.union_disj b1 b2)
1970 | r2 -> `Cap (r1,r2))
1971 | r1 -> match y t with
1972 | `Fail -> `Fail
1973 | r2 -> `Cap (r1,r2)
1974
1975 let rec prod_tests t0 d tests1 = match d with
1976 | Req.RBinds b -> `Binds b
1977 | Req.RTimes (q1,q2,xs,_) ->
1978 `Times (reg_test tests1 (Types.Product.pi1 t0) q1 xs,q2,xs)
1979 | Req.RCup (p1,p2) -> cup (prod_tests t0 p1) (prod_tests t0 p2) tests1
1980 | Req.RCap (p2,p1) -> cap (prod_tests t0 p1) (prod_tests t0 p2) tests1
1981 | Req.RConstr s ->
1982 let rects = Types.Product.get ~kind:`Normal s in
1983 let rects = List.map (fun (s1,s2) -> reg_test_type tests1 s1, s2) rects in
1984 `Prod rects
1985 | _ -> `Fail
1986 *)
1987
1988
1989 let rec prod_tests t0 d tests1 = match d with
1990 | Req.RBinds b -> (fun t1 ar1 tests2 ar2 -> Some b)
1991 | Req.RTimes (q1,q2,xs,_) ->
1992 let t0 = Types.Product.get ~kind:`Normal t0 in
1993 let test1 = reg_test tests1 (Types.Product.pi1 t0) q1 xs in
1994 (fun t1 ar1 tests2 -> match !test1 with
1995 | None -> (fun ar2 -> None)
1996 | Some b1 -> let test2 =
1997 reg_test tests2 (Types.Product.pi2_restricted t1 t0) q2 xs in
1998 fun ar2 -> match !test2 with
1999 | None -> None
2000 | Some b2 ->
2001 let b1 = IdMap.map (fun i -> Stack (ar1 + ar2 - i)) b1
2002 and b2 = IdMap.map (fun i -> Stack (ar2 - i)) b2 in
2003 Some
2004 (IdMap.merge
2005 (fun l r -> match l,r with
2006 | Stack i, Stack j -> Recompose (i,j)
2007 | _ -> assert false) b1 b2))
2008 | Req.RCup (p1,p2) ->
2009 let f1 = prod_tests t0 p1 tests1
2010 and f2 = prod_tests t0 p2 tests1 in
2011 (fun t1 ar1 tests2 ->
2012 let f1 = f1 t1 ar1 tests2 and f2 = f2 t1 ar1 tests2 in
2013 fun ar2 -> match f1 ar2 with
2014 | None -> f2 ar2
2015 | Some _ as r -> r)
2016 | Req.RCap (p2,p1) ->
2017 let f1 = prod_tests t0 p1 tests1 and f2 = prod_tests t0 p2 tests1 in
2018 (fun t1 ar1 tests2 ->
2019 let f1 = f1 t1 ar1 tests2 in
2020 let f2 = f2 t1 ar1 tests2 in
2021 fun ar2 -> match f1 ar2 with
2022 | None -> None
2023 | Some b1 -> match f2 ar2 with
2024 | None -> None
2025 | Some b2 -> Some (IdMap.union_disj b1 b2))
2026 | Req.RConstr s ->
2027 (* TODO: don't compute intersection, only filter rectangles *)
2028 let rects = Types.Product.get ~kind:`Normal (Types.cap s t0) in
2029 let rects = List.map (fun (s1,s2) -> reg_test_type tests1 s1, s2) rects in
2030 (fun t1 ar1 tests2 ->
2031 let rects = map_filter
2032 (function
2033 | ({ contents = Some _},s2) -> Some (reg_test_type tests2 s2)
2034 | _ -> None)
2035 rects in
2036 fun ar2 ->
2037 if List.exists (function { contents = Some _ } -> true | _ -> false)
2038 rects then Some IdMap.empty else None)
2039 | _ -> (fun t1 ar1 tests2 ar2 -> None)
2040
2041 let collect f t disp =
2042 let pl = Array.map (Req.simplify t) disp.pl in
2043 let tests = ref [] in
2044 let conts = Array.map (fun r -> f t r tests) pl in
2045 !tests,conts
2046
2047 let dispatch_basic disp : (Types.t * result) list =
2048 let t = Types.cap any_basic disp.t in
2049 let tests,conts = collect basic_tests t disp in
2050
2051 let rec aux t l accu =
2052 if Types.is_empty t then accu
2053 else match l with
2054 | [] ->
2055 let r = Array.map (fun f -> f ()) conts in
2056 let code = find_code disp r in
2057 (t, (code, create_result r, 0)) :: accu
2058 | (tst,ty) :: rem ->
2059 let accu = tst := true; aux (Types.cap t ty) rem accu in
2060 let accu = tst := false; aux (Types.diff t ty) rem accu in
2061 accu
2062 in
2063 aux t tests []
2064
2065
2066 module ReqMap = Map.Make(Req)
2067
2068 let get_tests
2069 (t0 : Types.t)
2070 (tests : (int id_map option ref * Req.t) list)
2071 (f : Types.t -> int -> 'a) : 'a dispatch =
2072 if Types.is_empty t0 then Impossible
2073 else
2074 let tests =
2075 List.filter (fun (slot,r) ->
2076 if IdSet.is_empty (Req.vars r) &&
2077 Types.subtype t0 (Req.acc r) then
2078 (slot := Some IdMap.empty; false)
2079 else true) tests in
2080
2081 if tests == [] then Ignore (f Types.any 0)
2082 else
2083
2084 (* Build a map (req)->(result slots) *)
2085 let slots_map =
2086 List.fold_left
2087 (fun accu (slot,r) ->
2088 let slots = slot :: (try ReqMap.find r accu with Not_found -> []) in
2089 ReqMap.add r slots accu)
2090 ReqMap.empty tests in
2091
2092 (* Collect subrequests *)
2093 let reqs =
2094 Array.of_list (ReqMap.fold (fun r _ accu -> r :: accu) slots_map []) in
2095
2096 (* Build dispatcher *)
2097 let disp = dispatcher t0 reqs in
2098
2099 (* Continuation *)
2100 let result (t,ar,b) : 'a =
2101 Array.iteri
2102 (fun i r ->
2103 let slots = ReqMap.find r slots_map in
2104 List.iter (fun slot -> slot := b.(i)) slots)
2105 reqs;
2106 f t ar in
2107
2108 Dispatch (disp, Array.map result disp.codes)
2109
2110 let rec dispatch_prod disp =
2111 let t = Types.cap Types.Product.any disp.t in
2112 let tests1,conts1 = collect prod_tests t disp in
2113 let t = Types.Product.get t in
2114 get_tests (Types.Product.pi1 t) tests1
2115 (fun t1 ar1 ->
2116 let tests2 = ref [] in
2117 let conts2 = Array.map (fun f -> f t1 ar1 tests2) conts1 in
2118 (*detect_right_tail_call*)
2119 (get_tests (Types.Product.pi2_restricted t1 t) !tests2
2120 (fun _ ar2 ->
2121 let r = Array.map (fun f -> f ar2) conts2 in
2122 let code = find_code disp r in
2123 (code, create_result r, 0))))
2124
2125 let dispatch_xml disp = Impossible
2126 let dispatch_record disp = None
2127
2128
2129 let iter_disp_disp f g = function
2130 | Dispatch (d,a) -> f d; Array.iter g a
2131 | TailCall d -> f d
2132 | Ignore a -> g a
2133 | Impossible -> ()
2134
2135 let iter_disp_prod f = iter_disp_disp f (iter_disp_disp f (fun _ -> ()))
2136
2137 let rec iter_disp_actions f = function
2138 | AIgnore _ -> ()
2139 | AKind k ->
2140 iter_disp_prod f k.prod;
2141 iter_disp_prod f k.xml;
2142 (match k.record with Some (RecLabel (_,p)) -> iter_disp_prod f p
2143 | _ -> ())
2144
2145 let actions disp =
2146 match disp.actions with
2147 | Some a -> a
2148 | None ->
2149 let a = combine_kind
2150 (dispatch_basic disp)
2151 (dispatch_prod disp)
2152 (dispatch_xml disp)
2153 (dispatch_record disp)
2154 in
2155 disp.actions <- Some a;
2156 iter_disp_actions (fun d -> to_generate := d :: !to_generate) a;
2157 incr generated;
2158 a
2159
2160 let to_print = ref []
2161
2162
2163
2164 module DSET = Set.Make (struct type t = int let compare (x:t) (y:t) = x - y end)
2165 let printed = ref DSET.empty
2166
2167 let queue d =
2168 if not d.printed then (
2169 d.printed <- true;
2170 to_print := d :: !to_print
2171 )
2172
2173 let rec print_source lhs ppf = function
2174 | Catch -> Format.fprintf ppf "v"
2175 | Const c -> Types.Print.print_const ppf c
2176 | Nil -> Format.fprintf ppf "`nil"
2177 | Left -> Format.fprintf ppf "v1"
2178 | Right -> Format.fprintf ppf "v2"
2179 | Stack i -> Format.fprintf ppf "%s" (List.nth lhs (i-1))
2180 | Recompose (i,j) ->
2181 Format.fprintf ppf "(%s,%s)"
2182 (match i with (-1) -> "v1" | (-2) -> "nil"
2183 | i -> List.nth lhs (i-1))
2184 (match j with (-1) -> "v2" | (-2) -> "nil"
2185 | j -> List.nth lhs (j-1))
2186
2187 let print_result lhs ppf =
2188 Array.iteri
2189 (fun i s ->
2190 if i > 0 then Format.fprintf ppf ",";
2191 print_source lhs ppf s;
2192 )
2193
2194 let print_ret lhs ppf (code,ret,ar) =
2195 Format.fprintf ppf "$%i" code;
2196 if Array.length ret <> 0 then
2197 Format.fprintf ppf "(%a)" (print_result lhs) ret
2198
2199 let print_ret_opt ppf = function
2200 | None -> Format.fprintf ppf "*"
2201 | Some r -> print_ret [] ppf r
2202
2203 let gen_lhs (code,prefix,d) =
2204 let arity = match d.codes.(code) with (_,a,_) -> a in
2205 let r = ref [] in
2206 for i = 0 to arity - 1 do r := Format.sprintf "%s%i" prefix i :: !r done;
2207 !r
2208
2209 let print_kind ppf actions =
2210 let print_lhs ppf (code,lhs) =
2211 Format.fprintf ppf "$%i(" code;
2212 let rec aux = function
2213 | [] -> ()
2214 | [x] -> Format.fprintf ppf "%s" x
2215 | x::r -> Format.fprintf ppf "%s,x" x; aux r
2216 in aux lhs;
2217 Format.fprintf ppf ")" in
2218 let print_basic (t,ret) =
2219 Format.fprintf ppf " | %a -> %a@\n"
2220 Types.Print.print t
2221 (print_ret []) ret
2222 in
2223 let print_prod2 lhs = function
2224 | Impossible -> assert false
2225 | Ignore r ->
2226 Format.fprintf ppf "%a\n"
2227 (print_ret lhs) r
2228 | TailCall d ->
2229 queue d;
2230 Format.fprintf ppf "disp_%i v2@\n" d.id
2231 | Dispatch (d, branches) ->
2232 queue d;
2233 Format.fprintf ppf "@\n match disp_%i v2 with@\n" d.id;
2234 Array.iteri
2235 (fun code r ->
2236 let rhs = gen_lhs (code,"r",d) in
2237 Format.fprintf ppf " | %a -> %a@\n"
2238 print_lhs (code,rhs)
2239 (print_ret (rhs@lhs)) r;
2240 )
2241 branches
2242 in
2243 let print_prod prefix ppf = function
2244 | Impossible -> ()
2245 | Ignore d2 ->
2246 Format.fprintf ppf " | %s(v1,v2) -> " prefix;
2247 print_prod2 [] d2
2248 | TailCall d ->
2249 queue d;
2250 Format.fprintf ppf " | %s(v1,v2) -> disp_%i v1@\n" prefix d.id
2251 | Dispatch (d,branches) ->
2252 queue d;
2253 Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix;
2254 Format.fprintf ppf " match disp_%i v1 with@\n" d.id;
2255 Array.iteri
2256 (fun code d2 ->
2257 let lhs = gen_lhs (code, "l", d) in
2258 Format.fprintf ppf " | %a -> " print_lhs (code,lhs);
2259 print_prod2 lhs d2;
2260 )
2261 branches
2262 in
2263 let rec print_record_opt ppf = function
2264 | None -> ()
2265 | Some (RecLabel (l,d)) ->
2266 let l = LabelPool.value l in
2267 print_prod ("record:"^(Label.to_string l)) ppf d
2268 | Some (RecNolabel (r1,r2)) ->
2269 Format.fprintf ppf " | Record -> @\n";
2270 Format.fprintf ppf " SomeField:%a;NoField:%a@\n"
2271 print_ret_opt r1 print_ret_opt r2
2272 in
2273
2274 List.iter print_basic actions.basic;
2275 print_prod "" ppf actions.prod;
2276 print_prod "XML" ppf actions.xml;
2277 print_record_opt ppf actions.record
2278
2279 let print_actions ppf = function
2280 | AKind k -> print_kind ppf k
2281 | AIgnore r -> Format.fprintf ppf "v -> %a@\n" (print_ret []) r
2282
2283 let print_dispatcher ppf d =
2284 (*
2285 Format.fprintf ppf "Dispatcher %i accepts [%a]@\n"
2286 d.id Types.Print.print (Types.normalize d.t);
2287 let print_code code (t, arity, m) =
2288 Format.fprintf ppf " Returns $%i(arity=%i) for [%a]"
2289 code arity
2290 Types.Print.print (Types.normalize t);
2291 (*
2292 List.iter
2293 (fun (i,b) ->
2294 Format.fprintf ppf "[%i:" i;
2295 List.iter
2296 (fun (v,i) -> Format.fprintf ppf "%s=>%i;" v i)
2297 b;
2298 Format.fprintf ppf "]"
2299 ) m; *)
2300
2301 Format.fprintf ppf "@\n";
2302 in
2303 Array.iteri print_code d.codes;
2304 *)
2305 Format.fprintf ppf "let disp_%i = function@\n" d.id;
2306 print_actions ppf (actions d);
2307 Format.fprintf ppf "====================================@\n"
2308
2309
2310 let rec print_dispatchers ppf =
2311 match !to_print with
2312 | [] -> ()
2313 | d :: rem ->
2314 to_print := rem;
2315 print_dispatcher ppf d;
2316 print_dispatchers ppf
2317
2318
2319 let show ppf t pl =
2320 let disp = dispatcher t pl in
2321 queue disp;
2322 print_dispatchers ppf
2323
2324 let debug_compile ppf t pl =
2325 let t = Types.descr t in
2326 let lab =
2327 List.fold_left
2328 (fun l p -> min l (first_label (descr p)))
2329 (Types.Record.first_label t) pl in
2330 let lab = if lab == LabelPool.dummy_max then None else Some lab in
2331
2332 let pl = Array.of_list (List.map (fun p -> Req.make t p.descr (fv p)) pl) in
2333 show ppf t pl;
2334 Format.fprintf ppf "# compiled states: %i@\n" !generated
2335
2336 let () =
2337 Stats.register Stats.Summary
2338 (fun ppf ->
2339 let i = !generated in
2340 Format.fprintf ppf "Number of compiled states: %i@." i;
2341 while !to_generate != [] do
2342 let d = List.hd !to_generate in
2343 to_generate := List.tl !to_generate;
2344 ignore (actions d)
2345 done;
2346 let j = !generated in
2347 Format.fprintf ppf "Total number of states: %i@." j)
2348 end
2349
2350 (* debug compile Any (Int,Int) & (x,y) *)
2351 *)

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