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

Contents of /types/patterns.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 119 - (show annotations)
Tue Jul 10 17:07:48 2007 UTC (5 years, 11 months ago) by abate
File size: 30760 byte(s)
[r2002-11-11 23:10:17 by cvscast] Empty log message

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

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