typer.ml 8.34 KB
Newer Older
1
2
(* I. Transform the abstract syntax of types and patterns into
      the internal form *)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

open Location
open Ast
exception ParsingPattern of string

let raise_loc loc msg = raise (Location loc (ParsingPattern msg))

(* Internal representation as a graph (desugar recursive types and regexp),
   to compute freevars, etc... *)

type ti = { 
  id : int; 
  mutable loc' : loc;
  mutable fv : string SortedList.t option; 
  mutable descr': descr;
  mutable type_node: Types.node option;
  mutable pat_node: Patterns.node option
} 
and descr =
   [ `Alias of ti
   | `Type of Types.descr
   | `Or of ti * ti
   | `And of ti * ti
   | `Diff of ti * ti
   | `Times of ti * ti
   | `Arrow of ti * ti
   | `Record of Types.label * bool * ti
   | `Capture of Patterns.capture
   | `Constant of Patterns.capture * Types.const
   ]
    


module S = struct type t = string let compare = compare end
module StringMap = Map.Make(S)
module StringSet = Set.Make(S)

let mk' =
  let counter = ref 0 in
  fun () ->
    incr counter;
    let rec x = { id = !counter; loc' = noloc; fv = None; descr' = `Alias x; 
		  type_node = None; pat_node = None } in
    x

let cons loc d =
  let x = mk' () in
  x.loc' <- loc;
  x.descr' <- d;
  x
    
(* Note:
   Compilation of Regexp is implemented as a ``rewriting'' of
   the parsed syntax, in order to be able to print its result
   (for debugging for instance)
   
   It would be possible (and a little more efficient) to produce
   directly ti nodes.
*)
    
module Regexp = struct
  let memo = Hashtbl.create 51
  let defs = ref []
  let name =
    let c = ref 0 in
    fun () ->
      incr c;
      "#" ^ (string_of_int !c)

  let rec seq_vars accu = function
    | Epsilon | Elem _ -> accu
    | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
    | Star r | WeakStar r -> seq_vars accu r
    | SeqCapture (v,r) -> seq_vars (StringSet.add v accu) r

  let rec propagate vars = function
    | Epsilon -> `Epsilon
    | Elem x -> `Elem (vars,x)
    | Seq (r1,r2) -> `Seq (propagate vars r1,propagate vars r2)
    | Alt (r1,r2) -> `Alt (propagate vars r1, propagate vars r2)
    | Star r -> `Star (propagate vars r)
    | WeakStar r -> `WeakStar (propagate vars r)
    | SeqCapture (v,x) -> propagate (StringSet.add v vars) x

  let cup r1 r2 = 
    match (r1,r2) with
      | (_, `Empty) -> r1
      | (`Empty, _) -> r2
      | (`Res t1, `Res t2) -> `Res (mk noloc (Or (t1,t2)))

  let rec compile fin e seq : [`Res of Ast.ppat | `Empty] = 
    if List.mem seq e then `Empty
    else 
      let e = seq :: e in
      match seq with
	| [] ->
	    `Res fin
	| `Epsilon :: rest -> 
	    compile fin e rest
	| `Elem (vars,x) :: rest -> 
	    let capt = StringSet.fold
			 (fun v t -> mk noloc (And (t, (mk noloc (Capture v)))))
			 vars x in
	    `Res (mk noloc (Prod (capt, guard_compile fin rest)))
	| `Seq (r1,r2) :: rest -> 
	    compile fin e (r1 :: r2 :: rest)
	| `Alt (r1,r2) :: rest -> 
	    cup (compile fin e (r1::rest)) (compile fin e (r2::rest))
	| `Star r :: rest -> cup (compile fin e (r::seq)) (compile fin e rest) 
	| `WeakStar r :: rest -> cup (compile fin e rest) (compile fin e (r::seq))

  and guard_compile fin seq =
    try Hashtbl.find memo seq 
    with
	Not_found ->
          let n = name () in
	  let v = mk noloc (PatVar n) in
          Hashtbl.add memo seq v;
	  let d = compile fin [] seq in
	  (match d with
	     | `Empty -> assert false
	     | `Res d -> defs := (n,d) :: !defs);
	  v


  let atom_nil = Types.mk_atom "nil"
  let constant_nil v t = 
    mk noloc (And (t, (mk noloc (Constant (v, Types.Atom atom_nil)))))

  let compile regexp queue : ppat =
    let vars = seq_vars StringSet.empty regexp in
    let fin = StringSet.fold constant_nil vars queue in
    let n = guard_compile fin [propagate StringSet.empty regexp] in
    Hashtbl.clear memo;
    let d = !defs in
    defs := [];
    mk noloc (Recurs (n,d))
end

let compile_regexp = Regexp.compile


let rec compile env { loc = loc; descr = d } : ti = 
  match (d : Ast.ppat') with
  | PatVar s -> 
      (try StringMap.find s env
       with Not_found -> raise_loc loc "Undefined variable"
      )
  | Recurs (t, b) ->
      let b = List.map (fun (v,t) -> (v,t,mk' ())) b in
      let env = 
	List.fold_left (fun env (v,t,x) -> StringMap.add v x env) env b in
      List.iter (fun (v,t,x) -> x.descr' <- `Alias (compile env t)) b;
      compile env t
  | Regexp (r,q) -> compile env (Regexp.compile r q)
  | Internal t -> cons loc (`Type t)
  | Or (t1,t2) -> cons loc (`Or (compile env t1, compile env t2))
  | And (t1,t2) -> cons loc (`And (compile env t1, compile env t2))
  | Diff (t1,t2) -> cons loc (`Diff (compile env t1, compile env t2))
  | Prod (t1,t2) -> cons loc (`Times (compile env t1, compile env t2))
  | Arrow (t1,t2) -> cons loc (`Arrow (compile env t1, compile env t2))
  | Record (l,o,t) -> cons loc (`Record (l,o,compile env t))
  | Constant (x,v) -> cons loc (`Constant (x,v))
  | Capture x -> cons loc (`Capture x)

let rec comp_fv seen s =
  match s.fv with
    | Some l -> l
    | None ->
	let l = 
	  match s.descr' with
	    | `Alias x -> if List.memq s seen then [] else comp_fv (s :: seen) x
	    | `Or (s1,s2) 
	    | `And (s1,s2)
	    | `Diff (s1,s2)
	    | `Times (s1,s2)
	    | `Arrow (s1,s2) -> SortedList.cup (comp_fv seen s1) (comp_fv seen s2)
	    | `Record (l,opt,s) -> comp_fv seen s
	    | `Type _ -> []
	    | `Capture x
	    | `Constant (x,_) -> [x]
	in
	if seen = [] then s.fv <- Some l;
	l


let fv = comp_fv []

let rec typ seen s : Types.descr =
  match s.descr' with
    | `Alias x ->
	if List.memq s seen then failwith "Unguarded recursion in this type"
	else typ (s :: seen) x
    | `Type t -> t
    | `Or (s1,s2) -> Types.cup (typ seen s1) (typ seen s2)
    | `And (s1,s2) ->  Types.cap (typ seen s1) (typ seen s2)
    | `Diff (s1,s2) -> Types.diff (typ seen s1) (typ seen s2)
    | `Times (s1,s2) ->	Types.times (typ_node s1) (typ_node s2)
    | `Arrow (s1,s2) ->	Types.arrow (typ_node s1) (typ_node s2)
    | `Record (l,o,s) -> Types.record l o (typ_node s)
    | _ -> failwith "This is not a type"

and typ_node s : Types.node =
  match s.type_node with
    | Some x -> x
    | None ->
	let x = Types.make () in
	s.type_node <- Some x;
	let t = typ [] s in
	Types.define x t;
	x

let type_node s = Types.internalize (typ_node s)

let rec pat seen s : Patterns.descr =
  if fv s = [] then Patterns.constr (type_node s) else
  match s.descr' with
    | `Alias x ->
	if List.memq s seen then failwith "Unguarded recursion in this pattern"
	else pat (s :: seen) x
    | `Or (s1,s2) -> Patterns.cup (pat seen s1) (pat seen s2)
    | `And (s1,s2) -> Patterns.cap (pat seen s1) (pat seen s2)
    | `Diff (s1,s2) when fv s2 = [] ->
	let s2 = Types.cons (Types.neg (Types.descr (type_node s2)))in
	Patterns.cap (pat seen s1) (Patterns.constr s2)
    | `Times (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
    | `Record (l,false,s) -> Patterns.record l (pat_node s)
    | `Capture x ->  Patterns.capture x
    | `Constant (x,c) -> Patterns.constant x c
    | _ -> failwith "This is not a pattern"

and pat_node s : Patterns.node =
  match s.pat_node with
    | Some x -> x
    | None ->
	let x = Patterns.make (fv s) in
	s.pat_node <- Some x;
	let t = pat [] s in
	Patterns.define x t;
	x

let typ e =
  let e = compile StringMap.empty e in
  if fv e = [] then type_node e else failwith "This is not a type"

let pat e =
  let e = compile StringMap.empty e in
  pat_node e



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
(* II. Build skeleton *)

let rec expr { loc = loc; descr = d } = 
  let td = 
    match d with
      | Var s -> Typed.Var s
      | Apply (e1,e2) -> Typed.Apply (expr e1, expr e2)
      | Abstraction a ->
	  Typed.Abstraction 
	    { Typed.fun_name = a.fun_name;
	      Typed.fun_iface = 
		List.map (fun (t1,t2) -> (typ t1, typ t2)) a.fun_iface;
	      Typed.fun_body =
		branches a.fun_body
	    }
      | Cst c -> Typed.Cst c
      | Pair (e1,e2) -> Typed.Pair (expr e1, expr e2)
      | RecordLitt r -> Typed.RecordLitt (List.map (fun (l,e) -> (l, expr e)) r)
      | Op (o,e) -> Typed.Op (o, expr e)
      | Match (e,b) -> Typed.Match (expr e, branches b)
      | Map (e,b) -> Typed.Map (expr e, branches b)
  in
  { Typed.loc = loc;
    Typed.exp_typ = Types.empty;
    Typed.exp_descr = td;
    Typed.fv = []  (* XXX TODO *)
  }
	      
  and branches b = List.map branch b
  and branch (p,e) = 
    { Typed.used = false;
      Typed.br_typ = Types.empty;
      Typed.br_pat = pat p;
      Typed.br_body = expr e }

let compute_type t = failwith "Not yet implemented"