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

Contents of /types/patterns.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 271 - (show annotations)
Tue Jul 10 17:21:17 2007 UTC (5 years, 11 months ago) by abate
File size: 34086 byte(s)
[r2003-03-22 21:56:53 by cvscast] Empty log message

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

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