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

Contents of /types/patterns.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 243 - (show annotations)
Tue Jul 10 17:18:44 2007 UTC (5 years, 10 months ago) by abate
File size: 30039 byte(s)
[r2003-03-15 10:59:53 by cvscast] map pour les chars et les atoms

Original author: cvscast
Date: 2003-03-15 10:59:54+00:00
1 exception Error of string
2 open Ident
3
4 (* Syntactic algebra *)
5 (* Constraint: any node except Constr has fv<>[] ... *)
6 type d =
7 | Constr of Types.descr
8 | Cup of descr * descr
9 | Cap of descr * descr
10 | Times of node * node
11 | Xml of node * node
12 | Record of label * node
13 | Capture of id
14 | Constant of id * Types.const
15 and node = {
16 id : int;
17 mutable descr : descr option;
18 accept : Types.node;
19 fv : fv
20 } and descr = Types.descr * fv * d
21
22 let id x = x.id
23 let descr x = match x.descr with Some d -> d | None -> failwith "Patterns.descr"
24 let fv x = x.fv
25 let accept x = Types.internalize x.accept
26
27 let printed = ref []
28 let to_print = ref []
29 let rec print ppf (a,_,d) =
30 (* Format.fprintf ppf "[%a]" Types.Print.print_descr a; *)
31 match d with
32 | Constr t -> Types.Print.print_descr ppf t
33 | Cup (p1,p2) -> Format.fprintf ppf "(%a | %a)" print p1 print p2
34 | Cap (p1,p2) -> Format.fprintf ppf "(%a & %a)" print p1 print p2
35 | Times (n1,n2) ->
36 Format.fprintf ppf "(P%i,P%i)" n1.id n2.id;
37 to_print := n1 :: n2 :: !to_print
38 | Xml (n1,n2) ->
39 Format.fprintf ppf "XML(P%i,P%i)" n1.id n2.id;
40 to_print := n1 :: n2 :: !to_print
41 | Record (l,n) ->
42 Format.fprintf ppf "{ %s = P%i }" (LabelPool.value l) n.id;
43 to_print := n :: !to_print
44 | Capture x ->
45 Format.fprintf ppf "%s" (Id.value x)
46 | Constant (x,c) ->
47 Format.fprintf ppf "(%s := %a)" (Id.value x)
48 Types.Print.print_const c
49
50 let dump_print ppf =
51 while !to_print <> [] do
52 let p = List.hd !to_print in
53 to_print := List.tl !to_print;
54 if not (List.mem p.id !printed) then
55 ( printed := p.id :: !printed;
56 Format.fprintf ppf "P%i:=%a\n" p.id print (descr p)
57 )
58 done
59
60 let print ppf d =
61 Format.fprintf ppf "%a@\n" print d;
62 dump_print ppf
63
64
65 let counter = State.ref "Patterns.counter" 0
66
67 let make fv =
68 incr counter;
69 { id = !counter; descr = None; accept = Types.make (); fv = fv }
70
71 let define x ((accept,fv,_) as d) =
72 assert (x.fv = fv);
73 Types.define x.accept accept;
74 x.descr <- Some d
75
76 let constr x = (x,IdSet.empty,Constr x)
77 let cup ((acc1,fv1,_) as x1) ((acc2,fv2,_) as x2) =
78 if not (IdSet.equal fv1 fv2) then (
79 let x = match IdSet.pick (IdSet.diff fv1 fv2) with
80 | Some x -> x
81 | None -> match IdSet.pick (IdSet.diff fv2 fv1) with Some x -> x
82 | None -> assert false
83 in
84 raise
85 (Error
86 ("The capture variable " ^ (Id.value x) ^
87 " should appear on both side of this | pattern"))
88 );
89 (Types.cup acc1 acc2, IdSet.cup fv1 fv2, Cup (x1,x2))
90 let cap ((acc1,fv1,_) as x1) ((acc2,fv2,_) as x2) =
91 if not (IdSet.disjoint fv1 fv2) then (
92 match IdSet.pick (IdSet.cap fv1 fv2) with
93 | Some x ->
94 raise
95 (Error
96 ("The capture variable " ^ (Id.value x) ^
97 " cannot appear on both side of this & pattern"))
98 | None -> assert false
99 );
100 (Types.cap acc1 acc2, IdSet.cup fv1 fv2, Cap (x1,x2))
101 let times x y =
102 (Types.times x.accept y.accept, IdSet.cup x.fv y.fv, Times (x,y))
103 let xml x y =
104 (Types.xml x.accept y.accept, IdSet.cup x.fv y.fv, Xml (x,y))
105 let record l x =
106 (Types.record l x.accept, x.fv, Record (l,x))
107 let capture x = (Types.any, IdSet.singleton x, Capture x)
108 let constant x c = (Types.any, IdSet.singleton x, Constant (x,c))
109
110
111
112
113 (* Static semantics *)
114
115 let cup_res v1 v2 = Types.Positive.cup [v1;v2]
116 let empty_res fv = IdMap.constant (Types.Positive.ty Types.empty) fv
117 let times_res v1 v2 = Types.Positive.times v1 v2
118
119 module MemoFilter = Map.Make
120 (struct type t = Types.descr * node let compare = compare end)
121
122 let memo_filter = ref MemoFilter.empty
123
124 let rec filter_descr t (_,fv,d) : Types.Positive.v id_map =
125 (* TODO: avoid is_empty t when t is not changing (Cap) *)
126 if Types.is_empty t
127 then empty_res fv
128 else
129 match d with
130 | Constr _ -> IdMap.empty
131 | Cup ((a,_,_) as d1,d2) ->
132 IdMap.merge cup_res
133 (filter_descr (Types.cap t a) d1)
134 (filter_descr (Types.diff t a) d2)
135 | Cap (d1,d2) ->
136 IdMap.merge cup_res (filter_descr t d1) (filter_descr t d2)
137 | Times (p1,p2) -> filter_prod fv p1 p2 t
138 | Xml (p1,p2) -> filter_prod ~kind:`XML fv p1 p2 t
139 | Record (l,p) ->
140 filter_node (Types.Record.project t l) p
141 | Capture c ->
142 IdMap.singleton c (Types.Positive.ty t)
143 | Constant (c, cst) ->
144 IdMap.singleton c (Types.Positive.ty (Types.constant cst))
145
146 and filter_prod ?kind fv p1 p2 t =
147 List.fold_left
148 (fun accu (d1,d2) ->
149 let term =
150 IdMap.merge times_res (filter_node d1 p1) (filter_node d2 p2)
151 in
152 IdMap.merge cup_res accu term
153 )
154 (empty_res fv)
155 (Types.Product.normal ?kind t)
156
157
158 and filter_node t p : Types.Positive.v id_map =
159 try MemoFilter.find (t,p) !memo_filter
160 with Not_found ->
161 let (_,fv,_) as d = descr p in
162 let res = IdMap.map_from_slist (fun _ -> Types.Positive.forward ()) fv in
163 memo_filter := MemoFilter.add (t,p) res !memo_filter;
164 let r = filter_descr t (descr p) in
165 IdMap.collide Types.Positive.define res r;
166 r
167
168 let filter t p =
169 let r = filter_node t p in
170 memo_filter := MemoFilter.empty;
171 IdMap.get (IdMap.map Types.Positive.solve r)
172
173
174 (* Normal forms for patterns and compilation *)
175
176 let min (a:int) (b:int) = if a < b then a else b
177
178 module Normal : sig
179 type 'a sl = 'a SortedList.t
180 type ('a,'b) sm = ('a,'b) SortedMap.t
181
182 type source =
183 | SCatch | SConst of Types.const
184 | SLeft | SRight | SRecompose
185 type result = source id_map
186
187 type nnf = node sl * Types.descr
188 type 'a nline = (result * 'a) list
189 type record =
190 | RecNolabel of result option * result option
191 | RecLabel of label * (nnf * nnf) nline
192 type t = {
193 nfv : fv;
194 ncatchv: fv;
195 na : Types.descr;
196 nbasic : Types.descr nline;
197 nprod : (nnf * nnf) nline;
198 nxml : (nnf * nnf) nline;
199 nrecord: record;
200 }
201
202 val any_basic: Types.descr
203 val first_label: descr -> label
204 val normal: label option -> Types.descr -> node list -> t
205 end =
206 struct
207 let any_basic =
208 Types.Record.or_absent
209 (Types.neg (List.fold_left Types.cup Types.empty
210 [Types.Product.any_xml;
211 Types.Product.any;
212 Types.Record.any]))
213
214
215 type 'a sl = 'a SortedList.t
216 type ('a,'b) sm = ('a,'b) SortedMap.t
217
218 type source =
219 | SCatch | SConst of Types.const
220 | SLeft | SRight | SRecompose
221 type result = source id_map
222
223 type nnf = node sl * Types.descr (* pl,t; t <= \accept{pl} *)
224 type 'a nline = (result * 'a) sl
225 type record =
226 | RecNolabel of result option * result option
227 | RecLabel of label * (nnf * nnf) nline
228 type t = {
229 nfv : fv;
230 ncatchv: fv;
231 na : Types.descr;
232 nbasic : Types.descr nline;
233 nprod : (nnf * nnf) nline;
234 nxml : (nnf * nnf) nline;
235 nrecord: record
236 }
237
238
239 let fus = IdMap.union_disj
240 let slcup = SortedList.cup
241
242 let nempty lab =
243 { nfv = IdSet.empty; ncatchv = IdSet.empty;
244 na = Types.empty;
245 nbasic = []; nprod = []; nxml = [];
246 nrecord = (match lab with
247 | Some l -> RecLabel (l,[])
248 | None -> RecNolabel (None,None))
249 }
250
251
252 let ncup nf1 nf2 =
253 (* assert (Types.is_empty (Types.cap nf1.na nf2.na)); *)
254 (* assert (nf1.nfv = nf2.nfv); *)
255 { nfv = nf1.nfv;
256 ncatchv = IdSet.cap nf1.ncatchv nf2.ncatchv;
257 na = Types.cup nf1.na nf2.na;
258 nbasic = SortedList.cup nf1.nbasic nf2.nbasic;
259 nprod = SortedList.cup nf1.nprod nf2.nprod;
260 nxml = SortedList.cup nf1.nxml nf2.nxml;
261 nrecord = (match (nf1.nrecord,nf2.nrecord) with
262 | RecLabel (l1,r1), RecLabel (l2,r2) ->
263 assert (l1 = l2); RecLabel (l1, slcup r1 r2)
264 | RecNolabel (x1,y1), RecNolabel (x2,y2) ->
265 RecNolabel((if x1 = None then x2 else x1),
266 (if y1 = None then y2 else y1))
267 | _ -> assert false)
268 }
269
270 let double_fold f l1 l2 =
271 SortedList.from_list
272 (List.fold_left
273 (fun accu x1 ->
274 List.fold_left
275 (fun accu x2 ->
276 f accu x1 x2
277 )
278 accu l2
279 ) [] l1)
280
281 let ncap nf1 nf2 =
282 let prod accu (res1,((pl1,t1),(ql1,s1))) (res2,((pl2,t2),(ql2,s2))) =
283 let t = Types.cap t1 t2 in
284 if Types.is_empty t then accu else
285 let s = Types.cap s1 s2 in
286 if Types.is_empty s then accu else
287 (fus res1 res2, ((slcup pl1 pl2,t),(slcup ql1 ql2,s))) :: accu
288 in
289 let basic accu (res1,t1) (res2,t2) =
290 let t = Types.cap t1 t2 in
291 if Types.is_empty t then accu else
292 (fus res1 res2, t) :: accu
293 in
294 let do_record r1 r2 = match r1,r2 with
295 | RecLabel (l1,r1), RecLabel (l2,r2) ->
296 assert (l1 = l2);
297 RecLabel(l1, double_fold prod r1 r2)
298 | RecNolabel (x1,y1), RecNolabel (x2,y2) ->
299 let x = match x1,x2 with
300 | Some res1, Some res2 -> Some (fus res1 res2)
301 | _ -> None
302 and y = match y1,y2 with
303 | Some res1, Some res2 -> Some (fus res1 res2)
304 | _ -> None in
305 RecNolabel (x,y)
306 | _ -> assert false
307 in
308 { nfv = IdSet.cup nf1.nfv nf2.nfv;
309 ncatchv = IdSet.cup nf1.ncatchv nf2.ncatchv;
310 na = Types.cap nf1.na nf2.na;
311 nbasic = double_fold basic nf1.nbasic nf2.nbasic;
312 nprod = double_fold prod nf1.nprod nf2.nprod;
313 nxml = double_fold prod nf1.nxml nf2.nxml;
314 nrecord = do_record nf1.nrecord nf2.nrecord;
315 }
316
317 let nnode p = [p], Types.descr p.accept
318 let empty_res = IdMap.empty
319
320 let ntimes lab acc p q =
321 let src_p = IdMap.constant SLeft p.fv
322 and src_q = IdMap.constant SRight q.fv in
323 let src = IdMap.merge_elem SRecompose src_p src_q in
324 { nempty lab with
325 nfv = IdSet.cup p.fv q.fv;
326 na = acc;
327 nprod = [ (src, (nnode p, nnode q)) ];
328 }
329
330 let nxml lab acc p q =
331 let src_p = IdMap.constant SLeft p.fv
332 and src_q = IdMap.constant SRight q.fv in
333 let src = IdMap.merge_elem SRecompose src_p src_q in
334 { nempty lab with
335 nfv = IdSet.cup p.fv q.fv;
336 na = acc;
337 nxml = [ (src, (nnode p, nnode q)) ];
338 }
339
340 let nrecord lab acc l p =
341 match lab with
342 | None -> assert false
343 | Some label ->
344 (* Printf.eprintf "[ l = %s; label = %s ]\n"
345 (LabelPool.value l)
346 (LabelPool.value label); *)
347 assert (label <= l);
348 if l == label then
349 let src = IdMap.constant SLeft p.fv in
350 { nempty lab with
351 nfv = p.fv;
352 na = acc;
353 nrecord = RecLabel(label,
354 [ (src,(nnode p, ([], Types.any))) ])}
355 else
356 let src = IdMap.constant SRight p.fv in
357 let p' = make p.fv in (* optimize this ... *)
358 (* cache the results to avoid looping ... *)
359 define p' (record l p);
360 { nempty lab with
361 nfv = p.fv;
362 na = acc;
363 nrecord = RecLabel(label,
364 [ (src,(([], Types.Record.any_or_absent),
365 nnode p')) ])}
366
367
368 let nconstr lab t =
369 let aux = List.map (fun (t1,t2) -> empty_res, (([],t1),([],t2))) in
370 let record =
371 match lab with
372 | None ->
373 let (x,y) = Types.Record.empty_cases t in
374 RecNolabel ((if x then Some empty_res else None),
375 (if y then Some empty_res else None))
376 | Some l ->
377 RecLabel (l,aux (Types.Record.split_normal t l))
378 in
379 { nempty lab with
380 na = t;
381 nbasic = [ empty_res, Types.cap t any_basic ];
382 nprod = aux (Types.Product.normal t);
383 nxml = aux (Types.Product.normal ~kind:`XML t);
384 nrecord = record
385 }
386
387 let nconstant lab x c =
388 let l = IdMap.singleton x (SConst c) in
389 { nfv = IdSet.singleton x;
390 ncatchv = IdSet.empty;
391 na = Types.any;
392 nbasic = [ (l,any_basic) ];
393 nprod = [ (l,(([], Types.any),([], Types.any))) ];
394 nxml = [ (l,(([], Types.any),([], Types.any))) ];
395 nrecord = match lab with
396 | None -> RecNolabel (Some l, Some l)
397 | Some lab ->
398 RecLabel (lab, [ (l,(([], Types.Record.any_or_absent),
399 ([], Types.any))) ])
400 }
401
402 let ncapture lab x =
403 let l = IdMap.singleton x SCatch in
404 { nfv = IdSet.singleton x;
405 ncatchv = IdSet.singleton x;
406 na = Types.any;
407 nbasic = [ (l,any_basic) ];
408 nprod = [ (l,(([], Types.any),([], Types.any))) ];
409 nxml = [ (l,(([], Types.any),([], Types.any))) ];
410 nrecord = match lab with
411 | None -> RecNolabel (Some l, Some l)
412 | Some lab ->
413 RecLabel (lab, [ (l,(([], Types.Record.any_or_absent),([], Types.any))) ])
414 }
415
416 let rec nnormal lab (acc,fv,d) =
417 if Types.is_empty acc
418 then nempty lab
419 else match d with
420 | Constr t -> nconstr lab t
421 | Cap (p,q) -> ncap (nnormal lab p) (nnormal lab q)
422 | Cup ((acc1,_,_) as p,q) ->
423 ncup (nnormal lab p) (ncap (nnormal lab q)
424 (nconstr lab (Types.neg acc1)))
425 | Times (p,q) -> ntimes lab acc p q
426 | Xml (p,q) -> nxml lab acc p q
427 | Capture x -> ncapture lab x
428 | Constant (x,c) -> nconstant lab x c
429 | Record (l,p) -> nrecord lab acc l p
430
431 (*TODO: when an operand of Cap has its first_label > lab,
432 directly shift it*)
433
434 let rec first_label (acc,fv,d) =
435 if Types.is_empty acc
436 then LabelPool.dummy_max
437 else match d with
438 | Constr t -> Types.Record.first_label t
439 | Cap (p,q) -> min (first_label p) (first_label q)
440 | Cup ((acc1,_,_) as p,q) -> min (first_label p) (first_label q)
441 (* should "first_label_type acc1" ? *)
442 | Record (l,p) -> l
443 | _ -> LabelPool.dummy_max
444
445
446 let remove_catchv n =
447 let ncv = n.ncatchv in
448 let nlines l =
449 let l = List.map (fun (res,x) -> (IdMap.diff res ncv,x)) l in
450 (* let l = SortedList.from_list l in (* Can get rid of it ? *) *)
451 l in
452 { nfv = IdSet.diff n.nfv ncv;
453 ncatchv = n.ncatchv;
454 na = n.na;
455 nbasic = nlines n.nbasic;
456 nprod = nlines n.nprod;
457 nxml = nlines n.nxml;
458 nrecord = (match n.nrecord with
459 | RecNolabel (x,y) ->
460 let x = match x with
461 | Some res -> Some (IdMap.diff res ncv)
462 | None -> None in
463 let y = match y with
464 | Some res -> Some (IdMap.diff res ncv)
465 | None -> None in
466 RecNolabel (x,y)
467 | RecLabel (lab,l) -> RecLabel (lab, nlines l))
468 }
469
470 let normal l t pl =
471 remove_catchv
472 (List.fold_left
473 (fun a p -> ncap a (nnormal l (descr p)))
474 (nconstr l t)
475 pl)
476 end
477
478
479 module Compile =
480 struct
481 type actions =
482 | AIgnore of result
483 | AKind of actions_kind
484 and actions_kind = {
485 basic: (Types.descr * result) list;
486 atoms: result Atoms.map;
487 chars: result Chars.map;
488 prod: result dispatch dispatch;
489 xml: result dispatch dispatch;
490 record: record option;
491 }
492 and record =
493 | RecLabel of label * result dispatch dispatch
494 | RecNolabel of result option * result option
495
496 and 'a dispatch =
497 | Dispatch of dispatcher * 'a array
498 | TailCall of dispatcher
499 | Ignore of 'a
500 | Impossible
501
502 and result = int * source array
503 and source =
504 | Catch | Const of Types.const
505 | Left of int | Right of int | Recompose of int * int
506
507 and return_code =
508 Types.descr * int * (* accepted type, arity *)
509 (int * int id_map) list
510
511 and interface =
512 [ `Result of int
513 | `Switch of interface * interface
514 | `None ]
515
516 and dispatcher = {
517 id : int;
518 t : Types.descr;
519 pl : Normal.t array;
520 label : label option;
521 interface : interface;
522 codes : return_code array;
523 mutable actions : actions option;
524 mutable printed : bool
525 }
526
527 let array_for_all f a =
528 let rec aux f a i =
529 if i = Array.length a then true
530 else f a.(i) && (aux f a (succ i))
531 in
532 aux f a 0
533
534 let array_for_all_i f a =
535 let rec aux f a i =
536 if i = Array.length a then true
537 else f i a.(i) && (aux f a (succ i))
538 in
539 aux f a 0
540
541 let combine_kind basic prod xml record =
542 try (
543 let rs = [] in
544 let rs = match basic with
545 | [_,r] -> r :: rs
546 | [] -> rs
547 | _ -> raise Exit in
548 let rs = match prod with
549 | Impossible -> rs
550 | Ignore (Ignore r) -> r :: rs
551 | _ -> raise Exit in
552 let rs = match xml with
553 | Impossible -> rs
554 | Ignore (Ignore r) -> r :: rs
555 | _ -> raise Exit in
556 let rs = match record with
557 | None -> rs
558 | Some (RecLabel (_,Ignore (Ignore r))) -> r :: rs
559 | Some (RecNolabel (Some r1, Some r2)) -> r1 :: r2 :: rs
560 | _ -> raise Exit in
561 match rs with
562 | ((_, ret) as r) :: rs when
563 List.for_all ( (=) r ) rs
564 && array_for_all
565 (function Catch | Const _ -> true | _ -> false) ret
566 -> AIgnore r
567 | _ -> raise Exit
568 )
569 with Exit ->
570 AKind
571 { basic = basic;
572 atoms =
573 Atoms.mk_map (List.map (fun (t,r) -> Types.Atom.get t, r) basic);
574 chars =
575 Chars.mk_map (List.map (fun (t,r) -> Types.Char.get t, r) basic);
576 prod = prod;
577 xml = xml;
578 record = record }
579
580 let combine (disp,act) =
581 if Array.length act = 0 then Impossible
582 else
583 if (array_for_all (fun (_,ar,_) -> ar = 0) disp.codes)
584 && (array_for_all ( (=) act.(0) ) act) then
585 Ignore act.(0)
586 else
587 Dispatch (disp, act)
588
589
590 let detect_right_tail_call = function
591 | Dispatch (disp,branches)
592 when
593 array_for_all_i
594 (fun i (code,ret) ->
595 (i = code) &&
596 (array_for_all_i
597 (fun pos ->
598 function Right j when pos = j -> true | _ -> false)
599 ret
600 )
601 ) branches
602 -> TailCall disp
603 | x -> x
604
605 let detect_left_tail_call = function
606 | Dispatch (disp,branches)
607 when
608 array_for_all_i
609 (fun i ->
610 function
611 | Ignore (code,ret) ->
612 (i = code) &&
613 (array_for_all_i
614 (fun pos ->
615 function Left j when pos = j -> true | _ -> false)
616 ret
617 )
618 | _ -> false
619 ) branches
620 ->
621 TailCall disp
622 | x -> x
623
624 let cur_id = State.ref "Patterns.cur_id" 0
625 (* TODO: save dispatchers ? *)
626
627 module DispMap = Map.Make(
628 struct
629 type t = Types.descr * Normal.t array
630 let compare = compare
631 end
632 )
633
634 let dispatchers = ref DispMap.empty
635
636 let dispatcher t pl lab : dispatcher =
637 try DispMap.find (t,pl) !dispatchers
638 with Not_found ->
639 let nb = ref 0 in
640 let codes = ref [] in
641 let rec aux t arity i accu =
642 if Types.is_empty t then `None
643 else
644 if i = Array.length pl
645 then (incr nb; codes := (t,arity,accu)::!codes; `Result (!nb - 1))
646 else
647 let p = pl.(i) in
648 let tp = p.Normal.na in
649 assert(IdSet.disjoint p.Normal.nfv p.Normal.ncatchv);
650 let v = p.Normal.nfv in
651 (* let v = IdSet.diff p.Normal.nfv p.Normal.ncatchv in*)
652
653 (* let tp = Types.normalize tp in *)
654 let accu' = (i,IdMap.num arity v) :: accu in
655 `Switch
656 (
657 aux (Types.cap t tp) (arity + (IdSet.length v)) (i+1) accu',
658 aux (Types.diff t tp) arity (i+1) accu
659 )
660 in
661 let iface = aux t 0 0 [] in
662 let res = { id = !cur_id;
663 t = t;
664 label = lab;
665 pl = pl;
666 interface = iface;
667 codes = Array.of_list (List.rev !codes);
668 actions = None; printed = false } in
669 incr cur_id;
670 dispatchers := DispMap.add (t,pl) res !dispatchers;
671 res
672
673 let find_code d a =
674 let rec aux i = function
675 | `Result code -> code
676 | `None -> assert false
677 | `Switch (yes,_) when a.(i) <> None -> aux (i + 1) yes
678 | `Switch (_,no) -> aux (i + 1) no
679 in
680 aux 0 d.interface
681
682 let create_result pl =
683 let aux x accu = match x with Some b -> b @ accu | None -> accu in
684 Array.of_list (Array.fold_right aux pl [])
685
686 let return disp pl f =
687 let aux = function [x] -> Some (f x) | [] -> None | _ -> assert false in
688 let final = Array.map aux pl in
689 (find_code disp final, create_result final)
690
691 let conv_source_basic s = match s with
692 | Normal.SCatch -> Catch
693 | Normal.SConst c -> Const c
694 | _ -> assert false
695
696 let assoc v l =
697 try IdMap.assoc v l with Not_found -> -1
698
699 let conv_source_prod left right v s = match s with
700 | Normal.SCatch -> Catch
701 | Normal.SConst c -> Const c
702 | Normal.SLeft -> Left (assoc v left)
703 | Normal.SRight -> Right (assoc v right)
704 | Normal.SRecompose -> Recompose (assoc v left, assoc v right)
705
706 let dispatch_basic disp : (Types.descr * result) list =
707 (* TODO: try other algo, using disp.codes .... *)
708 let pl = Array.map (fun p -> p.Normal.nbasic) disp.pl in
709 let tests =
710 let accu = ref [] in
711 let aux i (res,x) = accu := (x, [i,res]) :: !accu in
712 Array.iteri (fun i -> List.iter (aux i)) pl;
713 SortedMap.from_list SortedList.cup !accu in
714
715 let t = Types.cap Normal.any_basic disp.t in
716 let accu = ref [] in
717 let rec aux (success : (int * Normal.result) list) t l =
718 if Types.non_empty t
719 then match l with
720 | [] ->
721 let selected = Array.create (Array.length pl) [] in
722 let add (i,res) = selected.(i) <- res :: selected.(i) in
723 List.iter add success;
724
725 let aux_final res = IdMap.map_to_list conv_source_basic res in
726 accu := (t, return disp selected aux_final) :: !accu
727 | (ty,i) :: rem ->
728 aux (i @ success) (Types.cap t ty) rem;
729 aux success (Types.diff t ty) rem
730 in
731 aux [] t tests;
732 !accu
733
734
735 let get_tests pl f t d post =
736 let accu = ref [] in
737 let unselect = Array.create (Array.length pl) [] in
738 let aux i x =
739 let yes, no = f x in
740 List.iter (fun ( (pl,ty), info) -> accu := (ty,pl,i,info) :: !accu
741 ) yes;
742 unselect.(i) <- no @ unselect.(i) in
743 Array.iteri (fun i -> List.iter (aux i)) pl;
744
745 let lab =
746 List.fold_left
747 (fun l (ty,pl,_,_) ->
748 List.fold_left
749 (fun l p -> min l (Normal.first_label (descr p)))
750 (min l (Types.Record.first_label ty))
751 pl
752 ) LabelPool.dummy_max !accu in
753 let lab = if lab= LabelPool.dummy_max then None else Some lab in
754
755 let accu =
756 List.map (fun (ty,pl,i,info) ->
757 let p = Normal.normal lab ty pl in
758 (p,[i, p.Normal.ncatchv, info]))
759 !accu in
760 let sorted = Array.of_list (SortedMap.from_list SortedList.cup accu) in
761 let infos = Array.map snd sorted in
762 let disp = dispatcher t (Array.map fst sorted) lab in
763 let result (t,_,m) =
764 let selected = Array.create (Array.length pl) [] in
765 let add r (i, ncv, inf) = selected.(i) <- (r,ncv,inf) :: selected.(i) in
766 List.iter (fun (j,r) -> List.iter (add r) infos.(j)) m;
767 d t selected unselect
768 in
769 let res = Array.map result disp.codes in
770 post (disp,res)
771
772
773 let make_branches t brs =
774 let (_,brs) =
775 List.fold_left
776 (fun (t,brs) (p,e) ->
777 let p' = ([p],t) in
778 let t' = Types.diff t (Types.descr (accept p)) in
779 (t', (p',e) :: brs)
780 ) (t,[]) brs in
781
782 let pl = Array.map (fun x -> [x]) (Array.of_list brs) in
783 get_tests
784 pl
785 (fun x -> [x],[])
786 t
787 (fun _ pl _ ->
788 let r = ref None in
789 let aux = function
790 | [(res,catchv,e)] -> assert (!r = None);
791 let catchv = IdMap.constant (-1) catchv in
792 r := Some (IdMap.union_disj catchv res,e)
793 | [] -> () | _ -> assert false in
794 Array.iter aux pl;
795 let r = match !r with None -> assert false | Some x -> x in
796 r
797 )
798 (fun x -> x)
799
800
801 let rec dispatch_prod ?(kind=`Normal) disp =
802 let pl =
803 match kind with
804 | `Normal -> Array.map (fun p -> p.Normal.nprod) disp.pl
805 | `XML -> Array.map (fun p -> p.Normal.nxml) disp.pl
806 in
807 let t = Types.Product.get ~kind disp.t in
808 dispatch_prod0 disp t pl
809 and dispatch_prod0 disp t pl =
810 get_tests pl
811 (fun (res,(p,q)) -> [p, (res,q)], [])
812 (Types.Product.pi1 t)
813 (dispatch_prod1 disp t)
814 (fun x -> detect_left_tail_call (combine x))
815 and dispatch_prod1 disp t t1 pl _ =
816 get_tests pl
817 (fun (ret1, ncatchv, (res,q)) -> [q, (ret1,res)], [] )
818 (Types.Product.pi2_restricted t1 t)
819 (dispatch_prod2 disp)
820 (fun x -> detect_right_tail_call (combine x))
821 and dispatch_prod2 disp t2 pl _ =
822 let aux_final (ret2, ncatchv, (ret1, res)) =
823 IdMap.mapi_to_list (conv_source_prod ret1 ret2) res in
824 return disp pl aux_final
825
826
827 let rec dispatch_record disp : record option =
828 let t = disp.t in
829 if not (Types.Record.has_record t) then None
830 else
831 match disp.label with
832 | None ->
833 let (some,none) = Types.Record.empty_cases t in
834 let some =
835 if some then
836 let pl = Array.map (fun p -> match p.Normal.nrecord with
837 | Normal.RecNolabel (Some x,_) -> [x]
838 | Normal.RecNolabel (None,_) -> []
839 | _ -> assert false) disp.pl in
840 Some (return disp pl (IdMap.map_to_list conv_source_basic))
841 else None
842 in
843 let none =
844 if none then
845 let pl = Array.map (fun p -> match p.Normal.nrecord with
846 | Normal.RecNolabel (_,Some x) -> [x]
847 | Normal.RecNolabel (_,None) -> []
848 | _ -> assert false) disp.pl in
849 Some (return disp pl (IdMap.map_to_list conv_source_basic))
850 else None
851 in
852 Some (RecNolabel (some,none))
853 | Some lab ->
854 let t = Types.Record.split t lab in
855 let pl = Array.map (fun p -> match p.Normal.nrecord with
856 | Normal.RecLabel (_,l) -> l
857 | _ -> assert false) disp.pl in
858 Some (RecLabel (lab,dispatch_prod0 disp t pl))
859 (* soucis avec les ncatchv ?? *)
860
861
862 let actions disp =
863 match disp.actions with
864 | Some a -> a
865 | None ->
866 let a = combine_kind
867 (dispatch_basic disp)
868 (dispatch_prod disp)
869 (dispatch_prod ~kind:`XML disp)
870 (dispatch_record disp)
871 in
872 disp.actions <- Some a;
873 a
874
875 let to_print = ref []
876
877 module DSET = Set.Make (struct type t = int let compare (x:t) (y:t) = x - y end)
878 let printed = ref DSET.empty
879
880 let queue d =
881 if not d.printed then (
882 d.printed <- true;
883 to_print := d :: !to_print
884 )
885
886 let rec print_source ppf = function
887 | Catch -> Format.fprintf ppf "v"
888 | Const c -> Types.Print.print_const ppf c
889 | Left (-1) -> Format.fprintf ppf "v1"
890 | Right (-1) -> Format.fprintf ppf "v2"
891 | Left i -> Format.fprintf ppf "l%i" i
892 | Right j -> Format.fprintf ppf "r%i" j
893 | Recompose (i,j) ->
894 Format.fprintf ppf "(%a,%a)"
895 print_source (Left i)
896 print_source (Right j)
897
898 let print_result ppf =
899 Array.iteri
900 (fun i s ->
901 if i > 0 then Format.fprintf ppf ",";
902 print_source ppf s;
903 )
904
905 let print_ret ppf (code,ret) =
906 Format.fprintf ppf "$%i" code;
907 if Array.length ret <> 0 then
908 Format.fprintf ppf "(%a)" print_result ret
909
910 let print_ret_opt ppf = function
911 | None -> Format.fprintf ppf "*"
912 | Some r -> print_ret ppf r
913
914 let print_kind ppf actions =
915 let print_lhs ppf (code,prefix,d) =
916 let arity = match d.codes.(code) with (_,a,_) -> a in
917 Format.fprintf ppf "$%i(" code;
918 for i = 0 to arity - 1 do
919 if i > 0 then Format.fprintf ppf ",";
920 Format.fprintf ppf "%s%i" prefix i;
921 done;
922 Format.fprintf ppf ")" in
923 let print_basic (t,ret) =
924 Format.fprintf ppf " | %a -> %a@\n"
925 Types.Print.print_descr t
926 print_ret ret
927 in
928 let print_prod2 = function
929 | Impossible -> assert false
930 | Ignore r ->
931 Format.fprintf ppf " %a\n"
932 print_ret r
933 | TailCall d ->
934 queue d;
935 Format.fprintf ppf " disp_%i v2@\n" d.id
936 | Dispatch (d, branches) ->
937 queue d;
938 Format.fprintf ppf " match v2 with disp_%i@\n" d.id;
939 Array.iteri
940 (fun code r ->
941 Format.fprintf ppf " | %a -> %a\n"
942 print_lhs (code, "r", d)
943 print_ret r;
944 )
945 branches
946 in
947 let print_prod prefix ppf = function
948 | Impossible -> ()
949 | Ignore d2 ->
950 Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix;
951 print_prod2 d2
952 | TailCall d ->
953 queue d;
954 Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix;
955 Format.fprintf ppf " disp_%i v1@\n" d.id
956 | Dispatch (d,branches) ->
957 queue d;
958 Format.fprintf ppf " | %s(v1,v2) -> @\n" prefix;
959 Format.fprintf ppf " match v1 with disp_%i@\n" d.id;
960 Array.iteri
961 (fun code d2 ->
962 Format.fprintf ppf " | %a -> @\n"
963 print_lhs (code, "l", d);
964 print_prod2 d2;
965 )
966 branches
967 in
968 let rec print_record_opt ppf = function
969 | None -> ()
970 | Some r ->
971 Format.fprintf ppf " | Record -> @\n";
972 Format.fprintf ppf " @[%a@]@\n" print_record r
973 and print_record ppf = function
974 | RecNolabel (r1,r2) ->
975 Format.fprintf ppf "SomeField:%a;NoField:%a"
976 print_ret_opt r1 print_ret_opt r2
977 | RecLabel (l, d) ->
978 let l = LabelPool.value l in
979 Format.fprintf ppf "check label %s:@\n" l;
980 Format.fprintf ppf "Present => @[%a@]@\n" (print_prod "record") d
981 in
982
983 List.iter print_basic actions.basic;
984 print_prod "" ppf actions.prod;
985 print_prod "XML" ppf actions.xml;
986 print_record_opt ppf actions.record
987
988 let print_actions ppf = function
989 | AKind k -> print_kind ppf k
990 | AIgnore r -> Format.fprintf ppf "v -> %a@\n" print_ret r
991
992 let print_dispatcher ppf d =
993 (* Format.fprintf ppf "Dispatcher %i accepts [%a]@\n"
994 d.id Types.Print.print_descr (Types.normalize d.t);
995 let print_code code (t, arity, m) =
996 Format.fprintf ppf " Returns $%i(arity=%i) for [%a]"
997 code arity
998 Types.Print.print_descr (Types.normalize t);
999 (*
1000 List.iter
1001 (fun (i,b) ->
1002 Format.fprintf ppf "[%i:" i;
1003 List.iter
1004 (fun (v,i) -> Format.fprintf ppf "%s=>%i;" v i)
1005 b;
1006 Format.fprintf ppf "]"
1007 ) m; *)
1008
1009 Format.fprintf ppf "@\n";
1010 in
1011 Array.iteri print_code d.codes; *)
1012 Format.fprintf ppf "let disp_%i = function@\n" d.id;
1013 print_actions ppf (actions d);
1014 Format.fprintf ppf "====================================@\n"
1015
1016
1017 let rec print_dispatchers ppf =
1018 match !to_print with
1019 | [] -> ()
1020 | d :: rem ->
1021 to_print := rem;
1022 print_dispatcher ppf d;
1023 print_dispatchers ppf
1024
1025
1026 let show ppf t pl lab =
1027 let disp = dispatcher t pl lab in
1028 queue disp;
1029 print_dispatchers ppf
1030
1031 let debug_compile ppf t pl =
1032 let t = Types.descr t in
1033 let lab =
1034 List.fold_left
1035 (fun l p -> min l (Normal.first_label (descr p)))
1036 (Types.Record.first_label t) pl in
1037 let lab = if lab= LabelPool.dummy_max then None else Some lab in
1038
1039 let pl = Array.of_list
1040 (List.map (fun p -> Normal.normal lab Types.Record.any_or_absent [p]) pl) in
1041
1042 show ppf t pl lab;
1043 Format.fprintf ppf "# compiled dispatchers: %i@\n" !cur_id
1044 end
1045
1046

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