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

Contents of /types/patterns.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1378 - (show annotations)
Tue Jul 10 18:44:06 2007 UTC (5 years, 11 months ago) by abate
File size: 75345 byte(s)
[r2004-12-27 16:03:23 by afrisch] Cleanup

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