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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Tue Jul 10 16:57:08 2007 UTC (5 years, 11 months ago) by abate
File size: 11385 byte(s)
[r2002-10-10 16:39:45 by cvscast] Empty log message

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

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