/[svn]/typing/typer.ml
ViewVC logotype

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (hide annotations)
Tue Jul 10 16:59:25 2007 UTC (5 years, 10 months ago) by abate
File size: 17298 byte(s)
[r2002-10-21 19:11:57 by cvscast] Empty log message

Original author: cvscast
Date: 2002-10-21 19:13:15+00:00
1 abate 5 (* I. Transform the abstract syntax of types and patterns into
2     the internal form *)
3    
4     open Location
5     open Ast
6    
7 abate 9 exception Pattern of string
8     exception NonExhaustive of Types.descr
9 abate 28 exception MultipleLabel of Types.label
10 abate 9 exception Constraint of Types.descr * Types.descr * string
11 abate 19 exception ShouldHave of Types.descr * string
12 abate 26 exception WrongLabel of Types.descr * Types.label
13 abate 5
14 abate 9 let raise_loc loc exn = raise (Location (loc,exn))
15    
16 abate 5 (* Internal representation as a graph (desugar recursive types and regexp),
17     to compute freevars, etc... *)
18    
19 abate 9 type ti = {
20 abate 5 id : int;
21     mutable loc' : loc;
22     mutable fv : string SortedList.t option;
23     mutable descr': descr;
24     mutable type_node: Types.node option;
25     mutable pat_node: Patterns.node option
26     }
27     and descr =
28 abate 9 [ `Alias of string * ti
29 abate 5 | `Type of Types.descr
30     | `Or of ti * ti
31     | `And of ti * ti
32     | `Diff of ti * ti
33     | `Times of ti * ti
34     | `Arrow of ti * ti
35     | `Record of Types.label * bool * ti
36     | `Capture of Patterns.capture
37     | `Constant of Patterns.capture * Types.const
38     ]
39    
40    
41    
42     module S = struct type t = string let compare = compare end
43     module StringMap = Map.Make(S)
44     module StringSet = Set.Make(S)
45    
46     let mk' =
47     let counter = ref 0 in
48 abate 13 fun loc ->
49 abate 5 incr counter;
50 abate 9 let rec x = {
51     id = !counter;
52 abate 13 loc' = loc;
53 abate 9 fv = None;
54     descr' = `Alias ("__dummy__", x);
55     type_node = None;
56     pat_node = None
57     } in
58 abate 5 x
59    
60     let cons loc d =
61 abate 13 let x = mk' loc in
62 abate 5 x.descr' <- d;
63     x
64    
65     (* Note:
66     Compilation of Regexp is implemented as a ``rewriting'' of
67     the parsed syntax, in order to be able to print its result
68     (for debugging for instance)
69    
70     It would be possible (and a little more efficient) to produce
71     directly ti nodes.
72     *)
73    
74     module Regexp = struct
75     let memo = Hashtbl.create 51
76     let defs = ref []
77     let name =
78     let c = ref 0 in
79     fun () ->
80     incr c;
81     "#" ^ (string_of_int !c)
82    
83     let rec seq_vars accu = function
84     | Epsilon | Elem _ -> accu
85     | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
86     | Star r | WeakStar r -> seq_vars accu r
87     | SeqCapture (v,r) -> seq_vars (StringSet.add v accu) r
88    
89     let rec propagate vars = function
90     | Epsilon -> `Epsilon
91     | Elem x -> `Elem (vars,x)
92     | Seq (r1,r2) -> `Seq (propagate vars r1,propagate vars r2)
93     | Alt (r1,r2) -> `Alt (propagate vars r1, propagate vars r2)
94     | Star r -> `Star (propagate vars r)
95     | WeakStar r -> `WeakStar (propagate vars r)
96     | SeqCapture (v,x) -> propagate (StringSet.add v vars) x
97    
98     let cup r1 r2 =
99     match (r1,r2) with
100     | (_, `Empty) -> r1
101     | (`Empty, _) -> r2
102     | (`Res t1, `Res t2) -> `Res (mk noloc (Or (t1,t2)))
103    
104     let rec compile fin e seq : [`Res of Ast.ppat | `Empty] =
105     if List.mem seq e then `Empty
106     else
107     let e = seq :: e in
108     match seq with
109     | [] ->
110     `Res fin
111     | `Epsilon :: rest ->
112     compile fin e rest
113     | `Elem (vars,x) :: rest ->
114     let capt = StringSet.fold
115     (fun v t -> mk noloc (And (t, (mk noloc (Capture v)))))
116     vars x in
117     `Res (mk noloc (Prod (capt, guard_compile fin rest)))
118     | `Seq (r1,r2) :: rest ->
119     compile fin e (r1 :: r2 :: rest)
120     | `Alt (r1,r2) :: rest ->
121     cup (compile fin e (r1::rest)) (compile fin e (r2::rest))
122     | `Star r :: rest -> cup (compile fin e (r::seq)) (compile fin e rest)
123     | `WeakStar r :: rest -> cup (compile fin e rest) (compile fin e (r::seq))
124    
125     and guard_compile fin seq =
126     try Hashtbl.find memo seq
127     with
128     Not_found ->
129     let n = name () in
130     let v = mk noloc (PatVar n) in
131     Hashtbl.add memo seq v;
132     let d = compile fin [] seq in
133     (match d with
134     | `Empty -> assert false
135     | `Res d -> defs := (n,d) :: !defs);
136     v
137    
138    
139     let atom_nil = Types.mk_atom "nil"
140     let constant_nil v t =
141     mk noloc (And (t, (mk noloc (Constant (v, Types.Atom atom_nil)))))
142    
143     let compile regexp queue : ppat =
144     let vars = seq_vars StringSet.empty regexp in
145     let fin = StringSet.fold constant_nil vars queue in
146     let n = guard_compile fin [propagate StringSet.empty regexp] in
147     Hashtbl.clear memo;
148     let d = !defs in
149     defs := [];
150     mk noloc (Recurs (n,d))
151     end
152    
153     let compile_regexp = Regexp.compile
154    
155    
156     let rec compile env { loc = loc; descr = d } : ti =
157     match (d : Ast.ppat') with
158     | PatVar s ->
159     (try StringMap.find s env
160 abate 9 with Not_found ->
161     raise_loc loc (Pattern ("Undefined type variable " ^ s))
162 abate 5 )
163 abate 13 | Recurs (t, b) -> compile (compile_many env b) t
164 abate 5 | Regexp (r,q) -> compile env (Regexp.compile r q)
165     | Internal t -> cons loc (`Type t)
166     | Or (t1,t2) -> cons loc (`Or (compile env t1, compile env t2))
167     | And (t1,t2) -> cons loc (`And (compile env t1, compile env t2))
168     | Diff (t1,t2) -> cons loc (`Diff (compile env t1, compile env t2))
169     | Prod (t1,t2) -> cons loc (`Times (compile env t1, compile env t2))
170     | Arrow (t1,t2) -> cons loc (`Arrow (compile env t1, compile env t2))
171     | Record (l,o,t) -> cons loc (`Record (l,o,compile env t))
172     | Constant (x,v) -> cons loc (`Constant (x,v))
173     | Capture x -> cons loc (`Capture x)
174    
175 abate 13 and compile_many env b =
176     let b = List.map (fun (v,t) -> (v,t,mk' t.loc)) b in
177     let env =
178     List.fold_left (fun env (v,t,x) -> StringMap.add v x env) env b in
179     List.iter (fun (v,t,x) -> x.descr' <- `Alias (v, compile env t)) b;
180     env
181    
182    
183 abate 5 let rec comp_fv seen s =
184     match s.fv with
185     | Some l -> l
186     | None ->
187     let l =
188     match s.descr' with
189 abate 9 | `Alias (_,x) -> if List.memq s seen then [] else comp_fv (s :: seen) x
190 abate 5 | `Or (s1,s2)
191     | `And (s1,s2)
192     | `Diff (s1,s2)
193     | `Times (s1,s2)
194     | `Arrow (s1,s2) -> SortedList.cup (comp_fv seen s1) (comp_fv seen s2)
195     | `Record (l,opt,s) -> comp_fv seen s
196     | `Type _ -> []
197     | `Capture x
198     | `Constant (x,_) -> [x]
199     in
200     if seen = [] then s.fv <- Some l;
201     l
202    
203    
204     let fv = comp_fv []
205    
206     let rec typ seen s : Types.descr =
207     match s.descr' with
208 abate 9 | `Alias (v,x) ->
209     if List.memq s seen then
210     raise_loc s.loc'
211     (Pattern
212     ("Unguarded recursion on variable " ^ v ^ " in this type"))
213 abate 5 else typ (s :: seen) x
214     | `Type t -> t
215     | `Or (s1,s2) -> Types.cup (typ seen s1) (typ seen s2)
216     | `And (s1,s2) -> Types.cap (typ seen s1) (typ seen s2)
217     | `Diff (s1,s2) -> Types.diff (typ seen s1) (typ seen s2)
218     | `Times (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
219     | `Arrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
220     | `Record (l,o,s) -> Types.record l o (typ_node s)
221 abate 9 | `Capture _ | `Constant _ -> assert false
222 abate 5
223     and typ_node s : Types.node =
224     match s.type_node with
225     | Some x -> x
226     | None ->
227     let x = Types.make () in
228     s.type_node <- Some x;
229     let t = typ [] s in
230     Types.define x t;
231     x
232    
233     let type_node s = Types.internalize (typ_node s)
234    
235     let rec pat seen s : Patterns.descr =
236     if fv s = [] then Patterns.constr (type_node s) else
237     match s.descr' with
238 abate 9 | `Alias (v,x) ->
239     if List.memq s seen then
240     raise_loc s.loc'
241     (Pattern
242     ("Unguarded recursion on variable " ^ v ^ " in this pattern"))
243 abate 5 else pat (s :: seen) x
244     | `Or (s1,s2) -> Patterns.cup (pat seen s1) (pat seen s2)
245     | `And (s1,s2) -> Patterns.cap (pat seen s1) (pat seen s2)
246     | `Diff (s1,s2) when fv s2 = [] ->
247     let s2 = Types.cons (Types.neg (Types.descr (type_node s2)))in
248     Patterns.cap (pat seen s1) (Patterns.constr s2)
249 abate 9 | `Diff _ ->
250     raise_loc s.loc' (Pattern "Difference not allowed in patterns")
251 abate 5 | `Times (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
252     | `Record (l,false,s) -> Patterns.record l (pat_node s)
253 abate 9 | `Record _ ->
254     raise_loc s.loc'
255     (Pattern "Optional field not allowed in record patterns")
256 abate 5 | `Capture x -> Patterns.capture x
257     | `Constant (x,c) -> Patterns.constant x c
258 abate 9 | `Arrow _ ->
259     raise_loc s.loc' (Pattern "Arrow not allowed in patterns")
260     | `Type _ -> assert false
261 abate 5
262     and pat_node s : Patterns.node =
263     match s.pat_node with
264     | Some x -> x
265     | None ->
266     let x = Patterns.make (fv s) in
267     s.pat_node <- Some x;
268     let t = pat [] s in
269     Patterns.define x t;
270     x
271    
272 abate 13 let global_types = ref StringMap.empty
273    
274     let mk_typ e =
275 abate 9 if fv e = [] then type_node e
276 abate 13 else raise_loc e.loc' (Pattern "Capture variables are not allowed in types")
277    
278 abate 5
279 abate 13 let typ e =
280     mk_typ (compile !global_types e)
281    
282 abate 5 let pat e =
283 abate 13 let e = compile !global_types e in
284 abate 5 pat_node e
285    
286 abate 13 let register_global_types b =
287     let env = compile_many !global_types b in
288 abate 15 List.iter (fun (v,_) ->
289     let d = Types.descr (mk_typ (StringMap.find v env)) in
290     Types.Print.register_global v d
291     ) b;
292 abate 13 global_types := env
293 abate 5
294    
295     (* II. Build skeleton *)
296    
297 abate 6 module Fv = StringSet
298    
299 abate 5 let rec expr { loc = loc; descr = d } =
300 abate 6 let (fv,td) =
301 abate 5 match d with
302 abate 18 | DebugTyper t -> (Fv.empty, Typed.DebugTyper (typ t))
303 abate 6 | Var s -> (Fv.singleton s, Typed.Var s)
304     | Apply (e1,e2) ->
305     let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
306     (Fv.union fv1 fv2, Typed.Apply (e1,e2))
307 abate 5 | Abstraction a ->
308 abate 6 let iface = List.map (fun (t1,t2) -> (typ t1, typ t2)) a.fun_iface in
309     let t = List.fold_left
310     (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
311     Types.any iface in
312 abate 9 let iface = List.map
313     (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
314     iface in
315 abate 6 let (fv0,body) = branches a.fun_body in
316     let fv = match a.fun_name with
317     | None -> fv0
318     | Some f -> Fv.remove f fv0 in
319     (fv,
320     Typed.Abstraction
321     { Typed.fun_name = a.fun_name;
322     Typed.fun_iface = iface;
323     Typed.fun_body = body;
324     Typed.fun_typ = t;
325     Typed.fun_fv = Fv.elements fv0
326     }
327     )
328     | Cst c -> (Fv.empty, Typed.Cst c)
329     | Pair (e1,e2) ->
330     let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
331     (Fv.union fv1 fv2, Typed.Pair (e1,e2))
332 abate 26 | Dot (e,l) ->
333     let (fv,e) = expr e in
334 abate 27 (fv, Typed.Dot (e,l))
335 abate 6 | RecordLitt r ->
336 abate 29 (* Note: quadratic check for non duplication of labels.
337     Should improve that to O(n log n) for dealing
338     with huge number of attributes ?
339     *)
340 abate 6 let fv = ref Fv.empty in
341 abate 28 let labs = ref [] in
342 abate 6 let r = List.map
343     (fun (l,e) ->
344     let (fv2,e) = expr e in
345 abate 28 if (List.mem l !labs) then
346     raise_loc loc (MultipleLabel l);
347     labs := l :: !labs;
348 abate 6 fv := Fv.union !fv fv2;
349     (l,e)
350     ) r in
351     (!fv, Typed.RecordLitt r)
352 abate 16 | Op (op,le) ->
353     let (fvs,ltes) = List.split (List.map expr le) in
354     let fv = List.fold_left Fv.union Fv.empty fvs in
355     (fv, Typed.Op (op,ltes))
356 abate 6 | Match (e,b) ->
357     let (fv1,e) = expr e
358     and (fv2,b) = branches b in
359     (Fv.union fv1 fv2, Typed.Match (e, b))
360     | Map (e,b) ->
361     let (fv1,e) = expr e
362     and (fv2,b) = branches b in
363     (Fv.union fv1 fv2, Typed.Map (e, b))
364 abate 5 in
365 abate 6 fv,
366     { Typed.exp_loc = loc;
367 abate 5 Typed.exp_typ = Types.empty;
368     Typed.exp_descr = td;
369     }
370    
371 abate 6 and branches b =
372     let fv = ref Fv.empty in
373 abate 19 let accept = ref Types.empty in
374 abate 6 let b = List.map
375     (fun (p,e) ->
376     let (fv2,e) = expr e in
377     fv := Fv.union !fv fv2;
378 abate 19 let p = pat p in
379     accept := Types.cup !accept (Types.descr (Patterns.accept p));
380 abate 6 { Typed.br_used = false;
381 abate 19 Typed.br_pat = p;
382 abate 6 Typed.br_body = e }
383     ) b in
384 abate 19 (!fv,
385     {
386     Typed.br_typ = Types.empty;
387     Typed.br_branches = b;
388     Typed.br_accept = !accept
389     }
390     )
391 abate 5
392 abate 6 module Env = StringMap
393    
394     open Typed
395    
396 abate 17
397     let check loc t s msg =
398     if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
399    
400 abate 19 let rec type_check env e constr precise =
401     (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
402     Types.Print.print_descr constr precise; *)
403     let d = type_check' e.exp_loc env e.exp_descr constr precise in
404 abate 6 e.exp_typ <- Types.cup e.exp_typ d;
405     d
406    
407 abate 19 and type_check' loc env e constr precise = match e with
408     | Abstraction a ->
409     let t =
410     try Types.Arrow.check_strenghten a.fun_typ constr
411     with Not_found ->
412     raise_loc loc
413     (ShouldHave
414     (constr, "but the interface of the abstraction is not compatible"))
415     in
416     let env = match a.fun_name with
417     | None -> env
418     | Some f -> Env.add f a.fun_typ env in
419     List.iter
420     (fun (t1,t2) ->
421     ignore (type_check_branches loc env t1 a.fun_body t2 false)
422     ) a.fun_iface;
423     t
424     | Match (e,b) ->
425     let t = type_check env e b.br_accept true in
426     type_check_branches loc env t b constr precise
427 abate 30
428 abate 19 | Pair (e1,e2) ->
429     let rects = Types.Product.get constr in
430     if Types.Product.is_empty rects then
431     raise_loc loc (ShouldHave (constr,"but it is a pair."));
432     let pi1 = Types.Product.pi1 rects in
433    
434     let t1 = type_check env e1 (Types.Product.pi1 rects)
435     (precise || (Types.Product.need_second rects))in
436     let rects = Types.Product.restrict_1 rects t1 in
437     let t2 = type_check env e2 (Types.Product.pi2 rects) precise in
438     if precise then
439     Types.times (Types.cons t1) (Types.cons t2)
440     else
441     constr
442 abate 30
443 abate 29 | RecordLitt r ->
444     let rconstr = Types.Record.get constr in
445     if Types.Record.is_empty rconstr then
446     raise_loc loc (ShouldHave (constr,"but it is a record."));
447    
448     let (rconstr,res) =
449     List.fold_left
450     (fun (rconstr,res) (l,e) ->
451     let rconstr = Types.Record.restrict_label_present rconstr l in
452     let pi = Types.Record.project_field rconstr l in
453     if Types.Record.is_empty rconstr then
454     raise_loc loc
455     (ShouldHave (constr,(Printf.sprintf
456     "Field %s is not allowed here."
457     (Types.label_name l)
458     )
459     ));
460     let t = type_check env e pi true in
461     let rconstr = Types.Record.restrict_field rconstr l t in
462    
463     let res =
464     if precise
465     then Types.cap res (Types.record l false (Types.cons t))
466     else res in
467     (rconstr,res)
468     ) (rconstr, if precise then Types.Record.any else constr) r
469     in
470     res
471    
472 abate 19 | _ ->
473     let t : Types.descr = compute_type' loc env e in
474     check loc t constr "";
475     t
476    
477     and compute_type env e =
478     type_check env e Types.any true
479    
480 abate 6 and compute_type' loc env = function
481 abate 18 | DebugTyper t -> Types.descr t
482 abate 6 | Var s -> Env.find s env
483     | Apply (e1,e2) ->
484 abate 19 let t1 = type_check env e1 Types.Arrow.any true in
485     let t1 = Types.Arrow.get t1 in
486     let dom = Types.Arrow.domain t1 in
487     if Types.Arrow.need_arg t1 then
488     let t2 = type_check env e2 dom true in
489     Types.Arrow.apply t1 t2
490     else
491     (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
492 abate 6 | Cst c -> Types.constant c
493 abate 26 | Dot (e,l) ->
494     let t = type_check env e Types.Record.any true in
495     (try (Types.Record.project t l)
496     with Not_found -> raise_loc loc (WrongLabel(t,l)))
497 abate 16 | Op (op, el) ->
498     let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in
499     type_op loc op args
500 abate 17 | Map (e,b) ->
501     let t = compute_type env e in
502 abate 19 Sequence.map (fun t -> type_check_branches loc env t b Types.any true) t
503 abate 30
504     (* We keep these cases here to allow comparison and benchmarking ...
505     Just comment the corresponding cases in type_check' to
506     activate these ones.
507     *)
508     | Pair (e1,e2) ->
509     let t1 = compute_type env e1
510     and t2 = compute_type env e2 in
511     Types.times (Types.cons t1) (Types.cons t2)
512     | RecordLitt r ->
513     List.fold_left
514     (fun accu (l,e) ->
515     let t = compute_type env e in
516     let t = Types.record l false (Types.cons t) in
517     Types.cap accu t
518     ) Types.Record.any r
519    
520    
521 abate 19 | _ -> assert false
522 abate 6
523 abate 19 and type_check_branches loc env targ brs constr precise =
524 abate 6 if Types.is_empty targ then Types.empty
525 abate 9 else (
526     brs.br_typ <- Types.cup brs.br_typ targ;
527 abate 19 branches_aux loc env targ
528     (if precise then Types.empty else constr)
529     constr precise brs.br_branches
530 abate 9 )
531 abate 6
532 abate 19 and branches_aux loc env targ tres constr precise = function
533 abate 9 | [] -> raise_loc loc (NonExhaustive targ)
534 abate 6 | b :: rem ->
535     let p = b.br_pat in
536     let acc = Types.descr (Patterns.accept p) in
537    
538     let targ' = Types.cap targ acc in
539     if Types.is_empty targ'
540 abate 19 then branches_aux loc env targ tres constr precise rem
541 abate 6 else
542     ( b.br_used <- true;
543     let res = Patterns.filter targ' p in
544     let env' = List.fold_left
545     (fun env (x,t) -> Env.add x (Types.descr t) env)
546     env res in
547 abate 19 let t = type_check env' b.br_body constr precise in
548     let tres = if precise then Types.cup t tres else tres in
549 abate 9 let targ'' = Types.diff targ acc in
550     if (Types.non_empty targ'') then
551 abate 19 branches_aux loc env targ'' tres constr precise rem
552 abate 9 else
553     tres
554 abate 6 )
555 abate 16
556     and type_op loc op args =
557     match (op,args) with
558     | ("+", [loc1,t1; loc2,t2]) ->
559     type_int_binop Intervals.add loc1 t1 loc2 t2
560     | ("*", [loc1,t1; loc2,t2]) ->
561     type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
562 abate 17 | ("@", [loc1,t1; loc2,t2]) ->
563     check loc1 t1 Sequence.any
564     "The first argument of @ must be a sequence";
565     Sequence.concat t1 t2
566     | ("flatten", [loc1,t1]) ->
567     check loc1 t1 Sequence.seqseq
568     "The argument of flatten must be a sequence of sequences";
569     Sequence.flatten t1
570 abate 16 | _ -> assert false
571    
572     and type_int_binop f loc1 t1 loc2 t2 =
573     if not (Types.Int.is_int t1) then
574     raise_loc loc1
575     (Constraint
576     (t1,Types.Int.any,
577     "The first argument must be an integer"));
578     if not (Types.Int.is_int t2) then
579     raise_loc loc2
580     (Constraint
581     (t1,Types.Int.any,
582     "The second argument must be an integer"));
583     Types.Int.put
584     (f (Types.Int.get t1) (Types.Int.get t2));
585    
586    

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