/[svn]/ocamliface/mlstub.ml
ViewVC logotype

Contents of /ocamliface/mlstub.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1148 - (hide annotations)
Tue Jul 10 18:25:54 2007 UTC (5 years, 10 months ago) by abate
File size: 10789 byte(s)
[r2004-06-27 22:12:44 by afrisch] Reference dans un sens

Original author: afrisch
Date: 2004-06-27 22:12:44+00:00
1 abate 1146 #load "q_MLast.cmo";;
2    
3     (* TODO:
4     - optimizations: generate labels and atoms only once.
5     - implement functions OCaml -> CDuce
6     *)
7    
8    
9     open Mltypes
10     open Ident
11    
12     module IntMap =
13     Map.Make(struct type t = int let compare : t -> t -> int = compare end)
14    
15     module IntHash =
16     Hashtbl.Make(struct type t = int let hash i = i let equal i j = i == j end)
17    
18     (* Compute CDuce type *)
19    
20     let memo_typ = IntHash.create 13
21    
22     let atom lab = Types.atom (Atoms.atom (Atoms.V.mk_ascii lab))
23     let label lab = LabelPool.mk (Ns.empty, U.mk lab)
24     let bigcup f l = List.fold_left (fun accu x -> Types.cup accu (f x)) Types.empty l
25    
26     let rec typ t =
27     try IntHash.find memo_typ t.uid
28     with Not_found ->
29     let node = Types.make () in
30     IntHash.add memo_typ t.uid node;
31     Types.define node (typ_descr t.def);
32     node
33    
34     and typ_descr = function
35     | Link t -> typ_descr t.def
36     | Arrow (t,s) -> Types.arrow (typ t) (typ s)
37     | Tuple tl -> Types.tuple (List.map typ tl)
38     | PVariant l -> bigcup pvariant l
39     | Variant (l,_) -> bigcup variant l
40     | Record (l,_) ->
41     let l = List.map (fun (lab,t) -> label lab, typ t) l in
42     Types.record' (false,(LabelMap.from_list_disj l))
43     | Abstract "int" -> Builtin_defs.caml_int
44     | Abstract "char" -> Builtin_defs.char_latin1
45     | Abstract "string" -> Builtin_defs.string_latin1
46     | Builtin ("list", [t]) -> Types.descr (Sequence.star_node (typ t))
47 abate 1148 | Builtin ("Pervasives.ref", [t]) -> Builtin_defs.ref_type (typ t)
48 abate 1146 | _ -> assert false
49    
50     and pvariant = function
51     | (lab, None) -> atom lab
52     | (lab, Some t) -> Types.times (Types.cons (atom lab)) (typ t)
53    
54     and variant = function
55     | (lab, []) -> atom lab
56     | (lab, c) -> Types.tuple (Types.cons (atom lab) :: List.map typ c)
57    
58    
59     (* Syntactic tools *)
60    
61    
62     let mk_vars l =
63     let i = ref 0 in
64     List.map (fun t -> incr i; Printf.sprintf "x%i" !i) l
65    
66     let loc = (-1,-1)
67    
68     let let_in p e body =
69     <:expr< let $list:[ p, e ]$ in $body$ >>
70    
71     let atom_ascii lab =
72     <:expr< Value.atom_ascii $str: String.escaped lab$ >>
73    
74     let label_ascii lab =
75     <:expr< Value.label_ascii $str: String.escaped lab$ >>
76    
77     let pair e1 e2 = <:expr< Value.Pair ($e1$,$e2$) >>
78    
79     let pmatch e l =
80     let l = List.map (fun (p,e) -> p,None,e) l in
81     <:expr< match $e$ with [ $list:l$ ] >>
82    
83     let rec matches ine oute = function
84     | [v1;v2] ->
85     let_in <:patt<($lid:v1$,$lid:v2$)>> <:expr< Value.get_pair $ine$ >> oute
86     | v::vl ->
87     let oute = matches <:expr< r >> oute vl in
88     let_in <:patt<($lid:v$,r)>> <:expr< Value.get_pair $ine$ >> oute
89     | [] -> assert false
90    
91     let list_lit el =
92     List.fold_right (fun a e -> <:expr< [$a$ :: $e$] >>) el <:expr< [] >>
93    
94     (* OCaml -> CDuce conversions *)
95    
96     let to_cd_gen = ref []
97    
98     let to_cd_fun_name t =
99     Printf.sprintf "to_cd_%i" t.uid
100    
101     let to_cd_fun t =
102     to_cd_gen := t :: !to_cd_gen;
103     to_cd_fun_name t
104    
105     let rec tuple = function
106     | [v] -> v
107     | v::l -> <:expr< Value.Pair ($v$, $tuple l$) >>
108     | [] -> assert false
109    
110     let pat_tuple vars =
111     let pl = List.map (fun id -> <:patt< $lid:id$ >>) vars in
112     <:patt< ($list:pl$) >>
113    
114    
115     let rec to_cd e t =
116     (* Format.fprintf Format.std_formatter "to_cd %a [uid=%i; recurs=%i]@."
117     Mltypes.print t t.uid t.recurs; *)
118     if t.recurs > 0 then <:expr< $lid:to_cd_fun t$ $e$ >>
119     else to_cd_descr e t.def
120    
121     and to_cd_descr e = function
122     | Link t -> to_cd e t
123     | Arrow (t,s) -> failwith "to_cd: Arrow. TODO"
124     | Tuple tl ->
125     (* let (x1,...,xn) = ... in Value.Pair (t1(x1), Value.Pair(...,tn(xn))) *)
126     let vars = mk_vars tl in
127     let_in (pat_tuple vars) e (tuple (tuple_to_cd tl vars))
128     | PVariant l ->
129     (* match <...> with
130     | `A -> Value.atom_ascii "A"
131     | `B x -> Value.Pair (Value.atom_ascii "B",t(x))
132     *)
133     let cases =
134     List.map
135     (function
136     | (lab,None) -> <:patt< `$lid:lab$ >>, atom_ascii lab
137     | (lab,Some t) ->
138     <:patt< `$lid:lab$ x >>,
139     pair (atom_ascii lab) (to_cd <:expr< x >> t)
140     ) l in
141     pmatch e cases
142     | Variant (l,_) ->
143     (* match <...> with
144     | A -> Value.atom_ascii "A"
145     | B (x1,x2,..) -> Value.Pair (Value.atom_ascii "B",...,Value.Pair(tn(x)))
146     *)
147     let cases =
148     List.map
149     (function
150     | (lab,[]) -> <:patt< $uid:lab$ >>, atom_ascii lab
151     | (lab,tl) ->
152     let vars = mk_vars tl in
153     <:patt< $uid:lab$ $pat_tuple vars$ >>,
154     tuple (atom_ascii lab :: tuple_to_cd tl vars)
155     ) l in
156     pmatch e cases
157     | Record (l,_) ->
158     (* let x = <...> in Value.record [ l1,t1(x.l1); ...; ln,x.ln ] *)
159     let l =
160     List.map
161     (fun (lab,t) ->
162     let e = to_cd <:expr<x.$lid:lab$>> t in
163     <:expr< ($label_ascii lab$, $e$) >>)
164     l
165     in
166     let_in <:patt< x >> e <:expr< Value.record $list_lit l$ >>
167    
168     | Abstract "int" -> <:expr< ocaml2cduce_int $e$ >>
169     | Abstract "char" -> <:expr< ocaml2cduce_char $e$ >>
170     | Abstract "string" -> <:expr< ocaml2cduce_string $e$ >>
171     | Builtin ("list",[t]) ->
172     (* Value.sequence_rev (List.rev_map fun_t <...>) *)
173     <:expr< Value.sequence_rev (List.rev_map $lid:to_cd_fun t$ $e$) >>
174 abate 1148 | Builtin ("Pervasives.ref",[t]) ->
175     failwith "to_cd: Reference. TODO"
176 abate 1146 | _ -> assert false
177    
178     and tuple_to_cd tl vars = List.map2 (fun t id -> to_cd <:expr< $lid:id$ >> t) tl vars
179    
180     (* CDuce -> OCaml conversions *)
181    
182     let to_ml_gen = ref []
183    
184     let to_ml_fun_name t =
185     Printf.sprintf "to_ml_%i" t.uid
186    
187     let to_ml_fun t =
188     to_ml_gen := t :: !to_ml_gen;
189     to_ml_fun_name t
190    
191     let rec to_ml e t =
192     (* Format.fprintf Format.std_formatter "to_ml %a@."
193     Mltypes.print t; *)
194     if t.recurs > 0 then <:expr< $lid:to_ml_fun t$ $e$ >>
195     else to_ml_descr e t.def
196    
197     and to_ml_descr e = function
198     | Link t -> to_ml e t
199     | Arrow (t,s) ->
200     (* fun x -> s(Eval.eval_apply <...> (t(x))) *)
201     let arg = to_cd <:expr< x >> t in
202     let res = to_ml <:expr< Eval.eval_apply $e$ $arg$ >> s in
203     <:expr< fun x -> $res$ >>
204    
205     | Tuple tl ->
206     (* let (x1,r) = Value.get_pair <...> in
207     let (x2,r) = Value.get_pair r in
208     ...
209     let (xn-1,xn) = Value.get_pair r in
210     (t1(x1),...,tn(xn)) *)
211    
212     let vars = mk_vars tl in
213     let el = tuple_to_ml tl vars in
214     matches e <:expr< ($list:el$) >> vars
215     | PVariant l ->
216     (* match Value.get_variant <...> with
217     | "A",None -> `A
218     | "B",Some x -> `B (t(x))
219     *)
220     let cases =
221     List.map
222     (function
223     | (lab,None) ->
224     <:patt< ($str: String.escaped lab$, None) >>,
225     <:expr< `$lid:lab$ >>
226     | (lab,Some t) ->
227     <:patt< ($str: String.escaped lab$, Some x) >>,
228     <:expr< `$lid:lab$ $to_ml <:expr< x >> t$ >>
229     ) l in
230     pmatch <:expr< Value.get_variant $e$ >> cases
231     | Variant (l,false) ->
232     failwith "Private Sum type"
233     | Variant (l,true) ->
234     (* match Value.get_variant <...> with
235     | "A",None -> A
236     | "B",Some x -> let (x1,r) = x in ...
237     *)
238     let cases =
239     List.map
240     (function
241     | (lab,[]) ->
242     <:patt< ($str: String.escaped lab$, None) >>,
243     (match lab with (* Stupid Camlp4 *)
244     | "true" -> <:expr< True >>
245     | "false" -> <:expr< False >>
246     | lab -> <:expr< $lid:lab$ >>)
247     | (lab,[t]) ->
248     <:patt< ($str: String.escaped lab$, Some x) >>,
249     <:expr< $lid:lab$ $to_ml <:expr< x >> t$ >>
250     | (lab,tl) ->
251     let vars = mk_vars tl in
252     let el = tuple_to_ml tl vars in
253     <:patt< ($str: String.escaped lab$, Some x) >>,
254     matches <:expr< x >> <:expr< $lid:lab$ ($list:el$) >> vars
255     ) l in
256     pmatch <:expr< Value.get_variant $e$ >> cases
257     | Record (l,false) ->
258     failwith "Private Record type"
259     | Record (l,true) ->
260     (* let x = <...> in
261     { l1 = t1(Value.get_field x "l1"); ... } *)
262     let l =
263     List.map
264     (fun (lab,t) ->
265     (<:patt< $uid:lab$>>,
266     to_ml <:expr< Value.get_field x $label_ascii lab$ >> t)) l in
267     let_in <:patt< x >> e <:expr< {$list:l$} >>
268    
269     | Abstract "int" -> <:expr< cduce2ocaml_int $e$ >>
270     | Abstract "char" -> <:expr< cduce2ocaml_char $e$ >>
271     | Abstract "string" -> <:expr< cduce2ocaml_string $e$ >>
272     | Builtin ("list",[t]) ->
273     (* List.rev_map fun_t (Value.get_sequence_rev <...> *)
274     <:expr< List.rev_map $lid:to_ml_fun t$ (Value.get_sequence_rev $e$) >>
275 abate 1148 | Builtin ("Pervasives.ref",[t]) ->
276     (* ref t(Eval.eval_apply (Value.get_field <...> "get") Value.nil) *)
277     let e = <:expr< Value.get_field $e$ $label_ascii "get"$ >> in
278     let e = <:expr< Eval.eval_apply $e$ Value.nil >> in
279     <:expr< Pervasives.ref $to_ml e t$ >>
280 abate 1146 | _ -> assert false
281    
282     and tuple_to_ml tl vars = List.map2 (fun t id -> to_ml <:expr< $lid:id$ >> t) tl vars
283    
284    
285     let to_ml_done = IntHash.create 13
286     let to_cd_done = IntHash.create 13
287    
288     let global_transl () =
289     let defs = ref [] in
290     let rec aux hd tl gen don fun_name to_descr =
291     gen := tl;
292     if not (IntHash.mem don hd.uid) then (
293     IntHash.add don hd.uid ();
294     let p = <:patt< $lid:fun_name hd$ >> in
295     let e = <:expr< fun x -> $to_descr <:expr< x >> hd.def$ >> in
296     defs := (p,e) :: !defs
297     );
298     loop ()
299     and loop () = match !to_cd_gen,!to_ml_gen with
300     | hd::tl,_ -> aux hd tl to_cd_gen to_cd_done to_cd_fun_name to_cd_descr
301     | _,hd::tl -> aux hd tl to_ml_gen to_ml_done to_ml_fun_name to_ml_descr
302     | [],[] -> ()
303     in
304     loop ();
305     !defs
306    
307     (* Check type constraints and generate stub code *)
308    
309 abate 1147 let err_ppf = Format.err_formatter
310    
311     let check_value ty_env c_env (s,caml_t,t) =
312 abate 1146 (* Find the type for the value in the CDuce module *)
313     let id = Id.mk (U.mk s) in
314     let vt =
315     try Typer.find_value id ty_env
316     with Not_found ->
317 abate 1147 Format.fprintf err_ppf
318     "The interface exports a value %s which is not available in the module@." s;
319 abate 1146 exit 1
320     in
321    
322     (* Compute expected CDuce type *)
323     let et = Types.descr (typ t) in
324    
325     (* Check subtyping *)
326     if not (Types.subtype vt et) then
327     (
328     Format.fprintf
329 abate 1147 err_ppf
330     "The type for the value %s is invalid@\n\
331     Expected Caml type:@[%a@]@\n\
332     Expected CDuce type:@[%a@]@\n\
333     Inferred type:@[%a@]@."
334 abate 1146 s
335 abate 1147 print_ocaml caml_t
336 abate 1146 Types.Print.print et
337     Types.Print.print vt;
338     exit 1
339     );
340    
341     (* Generate stub code *)
342     (* let x = t(Eval.get_slot cu slot) *)
343     let slot = Compile.find_slot id c_env in
344     let e = to_ml <:expr< Eval.get_slot cu $int:string_of_int slot$ >> t in
345     <:patt< $uid:s$ >>, e
346    
347     let stub name cu values =
348     let ty_env = !Typer.from_comp_unit cu in
349     let c_env = !Compile.from_comp_unit cu in
350     let items = List.map (check_value ty_env c_env) values in
351     let g = global_transl () in
352    
353     (* open Cdml
354     open CDuce_all
355     let cu = Cdml.initialize <modname>
356     let rec <global translation functions>
357     let <stubs for values>
358     *)
359    
360     [ <:str_item< open Cdml >>;
361     <:str_item< open CDuce_all >>;
362     <:str_item< value cu = Cdml.initialize $str: String.escaped name$ >> ] @
363     (if g = [] then [] else [ <:str_item< value rec $list:g$ >> ]) @
364     [ <:str_item< value $list:items$ >> ]
365    
366    
367    

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