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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (hide annotations)
Tue Jul 10 16:59:11 2007 UTC (5 years, 10 months ago) by abate
File size: 15789 byte(s)
[r2002-10-21 09:03:48 by cvscast] Empty log message

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

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