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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (show annotations)
Tue Jul 10 16:58:37 2007 UTC (5 years, 10 months ago) by abate
File size: 15490 byte(s)
[r2002-10-20 19:07:35 by cvscast] Empty log message

Original author: cvscast
Date: 2002-10-20 19:08:05+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 exception ShouldHave of Types.descr * string
11
12 let raise_loc loc exn = raise (Location (loc,exn))
13
14 (* Internal representation as a graph (desugar recursive types and regexp),
15 to compute freevars, etc... *)
16
17 type ti = {
18 id : int;
19 mutable loc' : loc;
20 mutable fv : string SortedList.t option;
21 mutable descr': descr;
22 mutable type_node: Types.node option;
23 mutable pat_node: Patterns.node option
24 }
25 and descr =
26 [ `Alias of string * ti
27 | `Type of Types.descr
28 | `Or of ti * ti
29 | `And of ti * ti
30 | `Diff of ti * ti
31 | `Times of ti * ti
32 | `Arrow of ti * ti
33 | `Record of Types.label * bool * ti
34 | `Capture of Patterns.capture
35 | `Constant of Patterns.capture * Types.const
36 ]
37
38
39
40 module S = struct type t = string let compare = compare end
41 module StringMap = Map.Make(S)
42 module StringSet = Set.Make(S)
43
44 let mk' =
45 let counter = ref 0 in
46 fun loc ->
47 incr counter;
48 let rec x = {
49 id = !counter;
50 loc' = loc;
51 fv = None;
52 descr' = `Alias ("__dummy__", x);
53 type_node = None;
54 pat_node = None
55 } in
56 x
57
58 let cons loc d =
59 let x = mk' loc in
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) -> compile (compile_many env b) t
162 | Regexp (r,q) -> compile env (Regexp.compile r q)
163 | Internal t -> cons loc (`Type t)
164 | Or (t1,t2) -> cons loc (`Or (compile env t1, compile env t2))
165 | And (t1,t2) -> cons loc (`And (compile env t1, compile env t2))
166 | Diff (t1,t2) -> cons loc (`Diff (compile env t1, compile env t2))
167 | Prod (t1,t2) -> cons loc (`Times (compile env t1, compile env t2))
168 | Arrow (t1,t2) -> cons loc (`Arrow (compile env t1, compile env t2))
169 | Record (l,o,t) -> cons loc (`Record (l,o,compile env t))
170 | Constant (x,v) -> cons loc (`Constant (x,v))
171 | Capture x -> cons loc (`Capture x)
172
173 and compile_many env b =
174 let b = List.map (fun (v,t) -> (v,t,mk' t.loc)) b in
175 let env =
176 List.fold_left (fun env (v,t,x) -> StringMap.add v x env) env b in
177 List.iter (fun (v,t,x) -> x.descr' <- `Alias (v, compile env t)) b;
178 env
179
180
181 let rec comp_fv seen s =
182 match s.fv with
183 | Some l -> l
184 | None ->
185 let l =
186 match s.descr' with
187 | `Alias (_,x) -> if List.memq s seen then [] else comp_fv (s :: seen) x
188 | `Or (s1,s2)
189 | `And (s1,s2)
190 | `Diff (s1,s2)
191 | `Times (s1,s2)
192 | `Arrow (s1,s2) -> SortedList.cup (comp_fv seen s1) (comp_fv seen s2)
193 | `Record (l,opt,s) -> comp_fv seen s
194 | `Type _ -> []
195 | `Capture x
196 | `Constant (x,_) -> [x]
197 in
198 if seen = [] then s.fv <- Some l;
199 l
200
201
202 let fv = comp_fv []
203
204 let rec typ seen s : Types.descr =
205 match s.descr' with
206 | `Alias (v,x) ->
207 if List.memq s seen then
208 raise_loc s.loc'
209 (Pattern
210 ("Unguarded recursion on variable " ^ v ^ " in this type"))
211 else typ (s :: seen) x
212 | `Type t -> t
213 | `Or (s1,s2) -> Types.cup (typ seen s1) (typ seen s2)
214 | `And (s1,s2) -> Types.cap (typ seen s1) (typ seen s2)
215 | `Diff (s1,s2) -> Types.diff (typ seen s1) (typ seen s2)
216 | `Times (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
217 | `Arrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
218 | `Record (l,o,s) -> Types.record l o (typ_node s)
219 | `Capture _ | `Constant _ -> assert false
220
221 and typ_node s : Types.node =
222 match s.type_node with
223 | Some x -> x
224 | None ->
225 let x = Types.make () in
226 s.type_node <- Some x;
227 let t = typ [] s in
228 Types.define x t;
229 x
230
231 let type_node s = Types.internalize (typ_node s)
232
233 let rec pat seen s : Patterns.descr =
234 if fv s = [] then Patterns.constr (type_node s) else
235 match s.descr' with
236 | `Alias (v,x) ->
237 if List.memq s seen then
238 raise_loc s.loc'
239 (Pattern
240 ("Unguarded recursion on variable " ^ v ^ " in this pattern"))
241 else pat (s :: seen) x
242 | `Or (s1,s2) -> Patterns.cup (pat seen s1) (pat seen s2)
243 | `And (s1,s2) -> Patterns.cap (pat seen s1) (pat seen s2)
244 | `Diff (s1,s2) when fv s2 = [] ->
245 let s2 = Types.cons (Types.neg (Types.descr (type_node s2)))in
246 Patterns.cap (pat seen s1) (Patterns.constr s2)
247 | `Diff _ ->
248 raise_loc s.loc' (Pattern "Difference not allowed in patterns")
249 | `Times (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
250 | `Record (l,false,s) -> Patterns.record l (pat_node s)
251 | `Record _ ->
252 raise_loc s.loc'
253 (Pattern "Optional field not allowed in record patterns")
254 | `Capture x -> Patterns.capture x
255 | `Constant (x,c) -> Patterns.constant x c
256 | `Arrow _ ->
257 raise_loc s.loc' (Pattern "Arrow not allowed in patterns")
258 | `Type _ -> assert false
259
260 and pat_node s : Patterns.node =
261 match s.pat_node with
262 | Some x -> x
263 | None ->
264 let x = Patterns.make (fv s) in
265 s.pat_node <- Some x;
266 let t = pat [] s in
267 Patterns.define x t;
268 x
269
270 let global_types = ref StringMap.empty
271
272 let mk_typ e =
273 if fv e = [] then type_node e
274 else raise_loc e.loc' (Pattern "Capture variables are not allowed in types")
275
276
277 let typ e =
278 mk_typ (compile !global_types e)
279
280 let pat e =
281 let e = compile !global_types e in
282 pat_node e
283
284 let register_global_types b =
285 let env = compile_many !global_types b in
286 List.iter (fun (v,_) ->
287 let d = Types.descr (mk_typ (StringMap.find v env)) in
288 Types.Print.register_global v d
289 ) b;
290 global_types := env
291
292
293 (* II. Build skeleton *)
294
295 module Fv = StringSet
296
297 let rec expr { loc = loc; descr = d } =
298 let (fv,td) =
299 match d with
300 | DebugTyper t -> (Fv.empty, Typed.DebugTyper (typ t))
301 | Var s -> (Fv.singleton s, Typed.Var s)
302 | Apply (e1,e2) ->
303 let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
304 (Fv.union fv1 fv2, Typed.Apply (e1,e2))
305 | Abstraction a ->
306 let iface = List.map (fun (t1,t2) -> (typ t1, typ t2)) a.fun_iface in
307 let t = List.fold_left
308 (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
309 Types.any iface in
310 let iface = List.map
311 (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
312 iface in
313 let (fv0,body) = branches a.fun_body in
314 let fv = match a.fun_name with
315 | None -> fv0
316 | Some f -> Fv.remove f fv0 in
317 (fv,
318 Typed.Abstraction
319 { Typed.fun_name = a.fun_name;
320 Typed.fun_iface = iface;
321 Typed.fun_body = body;
322 Typed.fun_typ = t;
323 Typed.fun_fv = Fv.elements fv0
324 }
325 )
326 | Cst c -> (Fv.empty, Typed.Cst c)
327 | Pair (e1,e2) ->
328 let (fv1,e1) = expr e1 and (fv2,e2) = expr e2 in
329 (Fv.union fv1 fv2, Typed.Pair (e1,e2))
330 | RecordLitt r ->
331 (* XXX TODO: check that no label appears twice *)
332 let fv = ref Fv.empty in
333 let r = List.map
334 (fun (l,e) ->
335 let (fv2,e) = expr e in
336 fv := Fv.union !fv fv2;
337 (l,e)
338 ) r in
339 (!fv, Typed.RecordLitt r)
340 | Op (op,le) ->
341 let (fvs,ltes) = List.split (List.map expr le) in
342 let fv = List.fold_left Fv.union Fv.empty fvs in
343 (fv, Typed.Op (op,ltes))
344 | Match (e,b) ->
345 let (fv1,e) = expr e
346 and (fv2,b) = branches b in
347 (Fv.union fv1 fv2, Typed.Match (e, b))
348 | Map (e,b) ->
349 let (fv1,e) = expr e
350 and (fv2,b) = branches b in
351 (Fv.union fv1 fv2, Typed.Map (e, b))
352 in
353 fv,
354 { Typed.exp_loc = loc;
355 Typed.exp_typ = Types.empty;
356 Typed.exp_descr = td;
357 }
358
359 and branches b =
360 let fv = ref Fv.empty in
361 let accept = ref Types.empty in
362 let b = List.map
363 (fun (p,e) ->
364 let (fv2,e) = expr e in
365 fv := Fv.union !fv fv2;
366 let p = pat p in
367 accept := Types.cup !accept (Types.descr (Patterns.accept p));
368 { Typed.br_used = false;
369 Typed.br_pat = p;
370 Typed.br_body = e }
371 ) b in
372 (!fv,
373 {
374 Typed.br_typ = Types.empty;
375 Typed.br_branches = b;
376 Typed.br_accept = !accept
377 }
378 )
379
380 module Env = StringMap
381
382 open Typed
383
384
385 let check loc t s msg =
386 if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg))
387
388 let rec type_check env e constr precise =
389 (* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n"
390 Types.Print.print_descr constr precise; *)
391 let d = type_check' e.exp_loc env e.exp_descr constr precise in
392 e.exp_typ <- Types.cup e.exp_typ d;
393 d
394
395 and type_check' loc env e constr precise = match e with
396 | Abstraction a ->
397 let t =
398 try Types.Arrow.check_strenghten a.fun_typ constr
399 with Not_found ->
400 raise_loc loc
401 (ShouldHave
402 (constr, "but the interface of the abstraction is not compatible"))
403 in
404 let env = match a.fun_name with
405 | None -> env
406 | Some f -> Env.add f a.fun_typ env in
407 List.iter
408 (fun (t1,t2) ->
409 ignore (type_check_branches loc env t1 a.fun_body t2 false)
410 ) a.fun_iface;
411 t
412 | Match (e,b) ->
413 let t = type_check env e b.br_accept true in
414 type_check_branches loc env t b constr precise
415 | Pair (e1,e2) ->
416 let rects = Types.Product.get constr in
417 if Types.Product.is_empty rects then
418 raise_loc loc (ShouldHave (constr,"but it is a pair."));
419 let pi1 = Types.Product.pi1 rects in
420
421 let t1 = type_check env e1 (Types.Product.pi1 rects)
422 (precise || (Types.Product.need_second rects))in
423 let rects = Types.Product.restrict_1 rects t1 in
424 let t2 = type_check env e2 (Types.Product.pi2 rects) precise in
425 if precise then
426 Types.times (Types.cons t1) (Types.cons t2)
427 else
428 constr
429 | _ ->
430 let t : Types.descr = compute_type' loc env e in
431 check loc t constr "";
432 t
433
434 and compute_type env e =
435 type_check env e Types.any true
436
437 and compute_type' loc env = function
438 | DebugTyper t -> Types.descr t
439 | Var s -> Env.find s env
440 | Apply (e1,e2) ->
441 let t1 = type_check env e1 Types.Arrow.any true in
442 let t1 = Types.Arrow.get t1 in
443 let dom = Types.Arrow.domain t1 in
444 if Types.Arrow.need_arg t1 then
445 let t2 = type_check env e2 dom true in
446 Types.Arrow.apply t1 t2
447 else
448 (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
449 | Cst c -> Types.constant c
450 | RecordLitt r ->
451 List.fold_left
452 (fun accu (l,e) ->
453 let t = compute_type env e in
454 let t = Types.record l false (Types.cons t) in
455 Types.cap accu t
456 ) Types.Record.any r
457 | Op (op, el) ->
458 let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in
459 type_op loc op args
460 | Map (e,b) ->
461 let t = compute_type env e in
462 Sequence.map (fun t -> type_check_branches loc env t b Types.any true) t
463 | _ -> assert false
464
465 and type_check_branches loc env targ brs constr precise =
466 if Types.is_empty targ then Types.empty
467 else (
468 brs.br_typ <- Types.cup brs.br_typ targ;
469 branches_aux loc env targ
470 (if precise then Types.empty else constr)
471 constr precise brs.br_branches
472 )
473
474 and branches_aux loc env targ tres constr precise = function
475 | [] -> raise_loc loc (NonExhaustive targ)
476 | b :: rem ->
477 let p = b.br_pat in
478 let acc = Types.descr (Patterns.accept p) in
479
480 let targ' = Types.cap targ acc in
481 if Types.is_empty targ'
482 then branches_aux loc env targ tres constr precise rem
483 else
484 ( b.br_used <- true;
485 let res = Patterns.filter targ' p in
486 let env' = List.fold_left
487 (fun env (x,t) -> Env.add x (Types.descr t) env)
488 env res in
489 let t = type_check env' b.br_body constr precise in
490 let tres = if precise then Types.cup t tres else tres in
491 let targ'' = Types.diff targ acc in
492 if (Types.non_empty targ'') then
493 branches_aux loc env targ'' tres constr precise rem
494 else
495 tres
496 )
497
498 and type_op loc op args =
499 match (op,args) with
500 | ("+", [loc1,t1; loc2,t2]) ->
501 type_int_binop Intervals.add loc1 t1 loc2 t2
502 | ("*", [loc1,t1; loc2,t2]) ->
503 type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2
504 | ("@", [loc1,t1; loc2,t2]) ->
505 check loc1 t1 Sequence.any
506 "The first argument of @ must be a sequence";
507 Sequence.concat t1 t2
508 | ("flatten", [loc1,t1]) ->
509 check loc1 t1 Sequence.seqseq
510 "The argument of flatten must be a sequence of sequences";
511 Sequence.flatten t1
512 | _ -> assert false
513
514 and type_int_binop f loc1 t1 loc2 t2 =
515 if not (Types.Int.is_int t1) then
516 raise_loc loc1
517 (Constraint
518 (t1,Types.Int.any,
519 "The first argument must be an integer"));
520 if not (Types.Int.is_int t2) then
521 raise_loc loc2
522 (Constraint
523 (t1,Types.Int.any,
524 "The second argument must be an integer"));
525 Types.Int.put
526 (f (Types.Int.get t1) (Types.Int.get t2));
527
528

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