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

Contents of /types/patterns.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 287 - (show annotations)
Tue Jul 10 17:22:43 2007 UTC (5 years, 10 months ago) by abate
File size: 34507 byte(s)
[r2003-04-04 14:09:43 by cvscast] Empty log message

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

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