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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations)
Tue Jul 10 16:57:19 2007 UTC (5 years, 10 months ago) by abate
File size: 12320 byte(s)
[r2002-10-14 22:05:40 by cvscast] Empty log message

Original author: cvscast
Date: 2002-10-14 22:05:40+00:00
1 (* I. Transform the abstract syntax of types and patterns into
2 the internal form *)
3
4 open Location
5 open Ast
6
7 exception Pattern of string
8 exception NonExhaustive of Types.descr
9 exception Constraint of Types.descr * Types.descr * string
10
11 let raise_loc loc exn = raise (Location (loc,exn))
12
13 (* Internal representation as a graph (desugar recursive types and regexp),
14 to compute freevars, etc... *)
15
16 type ti = {
17 id : int;
18 mutable loc' : loc;
19 mutable fv : string SortedList.t option;
20 mutable descr': descr;
21 mutable type_node: Types.node option;
22 mutable pat_node: Patterns.node option
23 }
24 and descr =
25 [ `Alias of string * ti
26 | `Type of Types.descr
27 | `Or of ti * ti
28 | `And of ti * ti
29 | `Diff of ti * ti
30 | `Times of ti * ti
31 | `Arrow of ti * ti
32 | `Record of Types.label * bool * ti
33 | `Capture of Patterns.capture
34 | `Constant of Patterns.capture * Types.const
35 ]
36
37
38
39 module S = struct type t = string let compare = compare end
40 module StringMap = Map.Make(S)
41 module StringSet = Set.Make(S)
42
43 let mk' =
44 let counter = ref 0 in
45 fun () ->
46 incr counter;
47 let rec x = {
48 id = !counter;
49 loc' = noloc;
50 fv = None;
51 descr' = `Alias ("__dummy__", x);
52 type_node = None;
53 pat_node = None
54 } in
55 x
56
57 let cons loc d =
58 let x = mk' () in
59 x.loc' <- loc;
60 x.descr' <- d;
61 x
62
63 (* Note:
64 Compilation of Regexp is implemented as a ``rewriting'' of
65 the parsed syntax, in order to be able to print its result
66 (for debugging for instance)
67
68 It would be possible (and a little more efficient) to produce
69 directly ti nodes.
70 *)
71
72 module Regexp = struct
73 let memo = Hashtbl.create 51
74 let defs = ref []
75 let name =
76 let c = ref 0 in
77 fun () ->
78 incr c;
79 "#" ^ (string_of_int !c)
80
81 let rec seq_vars accu = function
82 | Epsilon | Elem _ -> accu
83 | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
84 | Star r | WeakStar r -> seq_vars accu r
85 | SeqCapture (v,r) -> seq_vars (StringSet.add v accu) r
86
87 let rec propagate vars = function
88 | Epsilon -> `Epsilon
89 | Elem x -> `Elem (vars,x)
90 | Seq (r1,r2) -> `Seq (propagate vars r1,propagate vars r2)
91 | Alt (r1,r2) -> `Alt (propagate vars r1, propagate vars r2)
92 | Star r -> `Star (propagate vars r)
93 | WeakStar r -> `WeakStar (propagate vars r)
94 | SeqCapture (v,x) -> propagate (StringSet.add v vars) x
95
96 let cup r1 r2 =
97 match (r1,r2) with
98 | (_, `Empty) -> r1
99 | (`Empty, _) -> r2
100 | (`Res t1, `Res t2) -> `Res (mk noloc (Or (t1,t2)))
101
102 let rec compile fin e seq : [`Res of Ast.ppat | `Empty] =
103 if List.mem seq e then `Empty
104 else
105 let e = seq :: e in
106 match seq with
107 | [] ->
108 `Res fin
109 | `Epsilon :: rest ->
110 compile fin e rest
111 | `Elem (vars,x) :: rest ->
112 let capt = StringSet.fold
113 (fun v t -> mk noloc (And (t, (mk noloc (Capture v)))))
114 vars x in
115 `Res (mk noloc (Prod (capt, guard_compile fin rest)))
116 | `Seq (r1,r2) :: rest ->
117 compile fin e (r1 :: r2 :: rest)
118 | `Alt (r1,r2) :: rest ->
119 cup (compile fin e (r1::rest)) (compile fin e (r2::rest))
120 | `Star r :: rest -> cup (compile fin e (r::seq)) (compile fin e rest)
121 | `WeakStar r :: rest -> cup (compile fin e rest) (compile fin e (r::seq))
122
123 and guard_compile fin seq =
124 try Hashtbl.find memo seq
125 with
126 Not_found ->
127 let n = name () in
128 let v = mk noloc (PatVar n) in
129 Hashtbl.add memo seq v;
130 let d = compile fin [] seq in
131 (match d with
132 | `Empty -> assert false
133 | `Res d -> defs := (n,d) :: !defs);
134 v
135
136
137 let atom_nil = Types.mk_atom "nil"
138 let constant_nil v t =
139 mk noloc (And (t, (mk noloc (Constant (v, Types.Atom atom_nil)))))
140
141 let compile regexp queue : ppat =
142 let vars = seq_vars StringSet.empty regexp in
143 let fin = StringSet.fold constant_nil vars queue in
144 let n = guard_compile fin [propagate StringSet.empty regexp] in
145 Hashtbl.clear memo;
146 let d = !defs in
147 defs := [];
148 mk noloc (Recurs (n,d))
149 end
150
151 let compile_regexp = Regexp.compile
152
153
154 let rec compile env { loc = loc; descr = d } : ti =
155 match (d : Ast.ppat') with
156 | PatVar s ->
157 (try StringMap.find s env
158 with Not_found ->
159 raise_loc loc (Pattern ("Undefined type variable " ^ s))
160 )
161 | Recurs (t, b) ->
162 let b = List.map (fun (v,t) -> (v,t,mk' ())) b in
163 let env =
164 List.fold_left (fun env (v,t,x) -> StringMap.add v x env) env b in
165 List.iter
166 (fun (v,t,x) -> x.loc' <- t.loc; x.descr' <- `Alias (v, compile env t))
167 b;
168 compile env t
169 | Regexp (r,q) -> compile env (Regexp.compile r q)
170 | Internal t -> cons loc (`Type t)
171 | Or (t1,t2) -> cons loc (`Or (compile env t1, compile env t2))
172 | And (t1,t2) -> cons loc (`And (compile env t1, compile env t2))
173 | Diff (t1,t2) -> cons loc (`Diff (compile env t1, compile env t2))
174 | Prod (t1,t2) -> cons loc (`Times (compile env t1, compile env t2))
175 | Arrow (t1,t2) -> cons loc (`Arrow (compile env t1, compile env t2))
176 | Record (l,o,t) -> cons loc (`Record (l,o,compile env t))
177 | Constant (x,v) -> cons loc (`Constant (x,v))
178 | Capture x -> cons loc (`Capture x)
179
180 let rec comp_fv seen s =
181 match s.fv with
182 | Some l -> l
183 | None ->
184 let l =
185 match s.descr' with
186 | `Alias (_,x) -> if List.memq s seen then [] else comp_fv (s :: seen) x
187 | `Or (s1,s2)
188 | `And (s1,s2)
189 | `Diff (s1,s2)
190 | `Times (s1,s2)
191 | `Arrow (s1,s2) -> SortedList.cup (comp_fv seen s1) (comp_fv seen s2)
192 | `Record (l,opt,s) -> comp_fv seen s
193 | `Type _ -> []
194 | `Capture x
195 | `Constant (x,_) -> [x]
196 in
197 if seen = [] then s.fv <- Some l;
198 l
199
200
201 let fv = comp_fv []
202
203 let rec typ seen s : Types.descr =
204 match s.descr' with
205 | `Alias (v,x) ->
206 if List.memq s seen then
207 raise_loc s.loc'
208 (Pattern
209 ("Unguarded recursion on variable " ^ v ^ " in this type"))
210 else typ (s :: seen) x
211 | `Type t -> t
212 | `Or (s1,s2) -> Types.cup (typ seen s1) (typ seen s2)
213 | `And (s1,s2) -> Types.cap (typ seen s1) (typ seen s2)
214 | `Diff (s1,s2) -> Types.diff (typ seen s1) (typ seen s2)
215 | `Times (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
216 | `Arrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
217 | `Record (l,o,s) -> Types.record l o (typ_node s)
218 | `Capture _ | `Constant _ -> assert false
219
220 and typ_node s : Types.node =
221 match s.type_node with
222 | Some x -> x
223 | None ->
224 let x = Types.make () in
225 s.type_node <- Some x;
226 let t = typ [] s in
227 Types.define x t;
228 x
229
230 let type_node s = Types.internalize (typ_node s)
231
232 let rec pat seen s : Patterns.descr =
233 if fv s = [] then Patterns.constr (type_node s) else
234 match s.descr' with
235 | `Alias (v,x) ->
236 if List.memq s seen then
237 raise_loc s.loc'
238 (Pattern
239 ("Unguarded recursion on variable " ^ v ^ " in this pattern"))
240 else pat (s :: seen) x
241 | `Or (s1,s2) -> Patterns.cup (pat seen s1) (pat seen s2)
242 | `And (s1,s2) -> Patterns.cap (pat seen s1) (pat seen s2)
243 | `Diff (s1,s2) when fv s2 = [] ->
244 let s2 = Types.cons (Types.neg (Types.descr (type_node s2)))in
245 Patterns.cap (pat seen s1) (Patterns.constr s2)
246 | `Diff _ ->
247 raise_loc s.loc' (Pattern "Difference not allowed in patterns")
248 | `Times (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
249 | `Record (l,false,s) -> Patterns.record l (pat_node s)
250 | `Record _ ->
251 raise_loc s.loc'
252 (Pattern "Optional field not allowed in record patterns")
253 | `Capture x -> Patterns.capture x
254 | `Constant (x,c) -> Patterns.constant x c
255 | `Arrow _ ->
256 raise_loc s.loc' (Pattern "Arrow not allowed in patterns")
257 | `Type _ -> assert false
258
259 and pat_node s : Patterns.node =
260 match s.pat_node with
261 | Some x -> x
262 | None ->
263 let x = Patterns.make (fv s) in
264 s.pat_node <- Some x;
265 let t = pat [] s in
266 Patterns.define x t;
267 x
268
269 let typ e =
270 let e = compile StringMap.empty e in
271 if fv e = [] then type_node e
272 else (raise_loc e.loc'
273 (Pattern "Capture variables are not allowed in types"))
274
275 let pat e =
276 let e = compile StringMap.empty e in
277 pat_node e
278
279
280
281 (* II. Build skeleton *)
282
283 module Fv = StringSet
284
285 let rec expr { loc = loc; descr = d } =
286 let (fv,td) =
287 match d with
288 | Var s -> (Fv.singleton s, Typed.Var s)
289 | Apply (e1,e2) ->
290 let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
291 (Fv.union fv1 fv2, Typed.Apply (e1,e2))
292 | Abstraction a ->
293 let iface = List.map (fun (t1,t2) -> (typ t1, typ t2)) a.fun_iface in
294 let t = List.fold_left
295 (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
296 Types.any iface in
297 let iface = List.map
298 (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
299 iface in
300 let (fv0,body) = branches a.fun_body in
301 let fv = match a.fun_name with
302 | None -> fv0
303 | Some f -> Fv.remove f fv0 in
304 (fv,
305 Typed.Abstraction
306 { Typed.fun_name = a.fun_name;
307 Typed.fun_iface = iface;
308 Typed.fun_body = body;
309 Typed.fun_typ = t;
310 Typed.fun_fv = Fv.elements fv0
311 }
312 )
313 | Cst c -> (Fv.empty, Typed.Cst c)
314 | Pair (e1,e2) ->
315 let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
316 (Fv.union fv1 fv2, Typed.Pair (e1,e2))
317 | RecordLitt r ->
318 (* XXX TODO: check that no label appears twice *)
319 let fv = ref Fv.empty in
320 let r = List.map
321 (fun (l,e) ->
322 let (fv2,e) = expr e in
323 fv := Fv.union !fv fv2;
324 (l,e)
325 ) r in
326 (!fv, Typed.RecordLitt r)
327 | Op (o,e) ->
328 let (fv,e) = expr e in (fv, Typed.Op (o,e))
329 | Match (e,b) ->
330 let (fv1,e) = expr e
331 and (fv2,b) = branches b in
332 (Fv.union fv1 fv2, Typed.Match (e, b))
333 | Map (e,b) ->
334 let (fv1,e) = expr e
335 and (fv2,b) = branches b in
336 (Fv.union fv1 fv2, Typed.Map (e, b))
337 in
338 fv,
339 { Typed.exp_loc = loc;
340 Typed.exp_typ = Types.empty;
341 Typed.exp_descr = td;
342 }
343
344 and branches b =
345 let fv = ref Fv.empty in
346 let b = List.map
347 (fun (p,e) ->
348 let (fv2,e) = expr e in
349 fv := Fv.union !fv fv2;
350 { Typed.br_used = false;
351 Typed.br_pat = pat p;
352 Typed.br_body = e }
353 ) b in
354 (!fv, { Typed.br_typ = Types.empty; Typed.br_branches = b } )
355
356 module Env = StringMap
357
358 open Typed
359
360 let rec compute_type env e =
361 let d = compute_type' e.exp_loc env e.exp_descr in
362 e.exp_typ <- Types.cup e.exp_typ d;
363 d
364
365 and compute_type' loc env = function
366 | Var s -> Env.find s env
367 | Apply (e1,e2) ->
368 let t1 = compute_type env e1 and t2 = compute_type env e2 in
369 Types.apply t1 t2
370 | Abstraction a ->
371 let env = match a.fun_name with
372 | None -> env
373 | Some f -> Env.add f a.fun_typ env in
374 List.iter (fun (t1,t2) ->
375 let t = type_branches loc env t1 a.fun_body in
376 if not (Types.subtype t t2) then
377 raise_loc loc (Constraint (t,t2,"Constraint not satisfied in interface"))
378 ) a.fun_iface;
379 a.fun_typ
380 | Cst c -> Types.constant c
381 | Pair (e1,e2) ->
382 let t1 = compute_type env e1 and t2 = compute_type env e2 in
383 let t1 = Types.cons t1 and t2 = Types.cons t2 in
384 Types.times t1 t2
385 | RecordLitt r ->
386 List.fold_left
387 (fun accu (l,e) ->
388 let t = compute_type env e in
389 let t = Types.record l false (Types.cons t) in
390 Types.cap accu t
391 ) Types.Record.any r
392 | Op (op,e) -> assert false
393 | Match (e,b) ->
394 let t = compute_type env e in
395 type_branches loc env t b
396 | Map (e,b) -> assert false
397
398 and type_branches loc env targ brs =
399 if Types.is_empty targ then Types.empty
400 else (
401 brs.br_typ <- Types.cup brs.br_typ targ;
402 branches_aux loc env targ Types.empty brs.br_branches
403 )
404
405 and branches_aux loc env targ tres = function
406 | [] -> raise_loc loc (NonExhaustive targ)
407 | b :: rem ->
408 let p = b.br_pat in
409 let acc = Types.descr (Patterns.accept p) in
410
411 let targ' = Types.cap targ acc in
412 if Types.is_empty targ'
413 then branches_aux loc env targ tres rem
414 else
415 ( b.br_used <- true;
416 let res = Patterns.filter targ' p in
417 let env' = List.fold_left
418 (fun env (x,t) -> Env.add x (Types.descr t) env)
419 env res in
420 let t = compute_type env' b.br_body in
421 let tres = Types.cup t tres in
422 let targ'' = Types.diff targ acc in
423 if (Types.non_empty targ'') then
424 branches_aux loc env targ'' (Types.cup t tres) rem
425 else
426 tres
427 )

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