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

Contents of /ocamliface/mlstub.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1162 - (show annotations)
Tue Jul 10 18:27:18 2007 UTC (5 years, 11 months ago) by abate
File size: 14189 byte(s)
[r2004-06-28 04:51:58 by afrisch] -static

Original author: afrisch
Date: 2004-06-28 04:51:59+00:00
1 #load "q_MLast.cmo";;
2
3 (* TODO:
4 - optimizations: generate labels and atoms only once.
5 - MD5 checksum
6 - embeded CDuce code in OCaml
7 *)
8
9
10 open Mltypes
11 open Ident
12
13 module IntMap =
14 Map.Make(struct type t = int let compare : t -> t -> int = compare end)
15
16 module IntHash =
17 Hashtbl.Make(struct type t = int let hash i = i let equal i j = i == j end)
18
19 (* Compute CDuce type *)
20
21 let memo_typ = IntHash.create 13
22
23 let atom lab = Types.atom (Atoms.atom (Atoms.V.mk_ascii lab))
24 let label lab = LabelPool.mk (Ns.empty, U.mk lab)
25 let bigcup f l = List.fold_left (fun accu x -> Types.cup accu (f x)) Types.empty l
26
27 let rec typ t =
28 try IntHash.find memo_typ t.uid
29 with Not_found ->
30 let node = Types.make () in
31 IntHash.add memo_typ t.uid node;
32 Types.define node (typ_descr t.def);
33 node
34
35 and typ_descr = function
36 | Link t -> typ_descr t.def
37 | Arrow (t,s) -> Types.arrow (typ t) (typ s)
38 | Tuple tl -> Types.tuple (List.map typ tl)
39 | PVariant l -> bigcup pvariant l
40 | Variant (l,_) -> bigcup variant l
41 | Record (l,_) ->
42 let l = List.map (fun (lab,t) -> label lab, typ t) l in
43 Types.record' (false,(LabelMap.from_list_disj l))
44 | Abstract "int" -> Builtin_defs.caml_int
45 | Abstract "char" -> Builtin_defs.char_latin1
46 | Abstract "string" -> Builtin_defs.string_latin1
47 | Abstract s -> Types.abstract (Types.Abstract.atom s)
48 | Builtin ("list", [t]) -> Types.descr (Sequence.star_node (typ t))
49 | Builtin ("Pervasives.ref", [t]) -> Builtin_defs.ref_type (typ t)
50 | Builtin ("CDuce_all.Value.t", []) -> Types.any
51 | Builtin ("unit", []) -> Sequence.nil_type
52 | _ -> assert false
53
54 and pvariant = function
55 | (lab, None) -> atom lab
56 | (lab, Some t) -> Types.times (Types.cons (atom lab)) (typ t)
57
58 and variant = function
59 | (lab, []) -> atom lab
60 | (lab, c) -> Types.tuple (Types.cons (atom lab) :: List.map typ c)
61
62
63 (* Syntactic tools *)
64
65 let var_counter = ref 0
66 let mk_var _ =
67 incr var_counter;
68 Printf.sprintf "x%i" !var_counter
69
70 let mk_vars = List.map mk_var
71
72 let loc = (-1,-1)
73
74 let let_in p e body =
75 <:expr< let $list:[ p, e ]$ in $body$ >>
76
77 let atom_ascii lab =
78 <:expr< Value.atom_ascii $str: String.escaped lab$ >>
79
80 let label_ascii lab =
81 <:expr< Value.label_ascii $str: String.escaped lab$ >>
82
83 let pair e1 e2 = <:expr< Value.Pair ($e1$,$e2$) >>
84
85 let pmatch e l =
86 let l = List.map (fun (p,e) -> p,None,e) l in
87 <:expr< match $e$ with [ $list:l$ ] >>
88
89 let rec matches ine oute = function
90 | [v1;v2] ->
91 let_in <:patt<($lid:v1$,$lid:v2$)>> <:expr< Value.get_pair $ine$ >> oute
92 | v::vl ->
93 let r = mk_var () in
94 let oute = matches <:expr< $lid:r$ >> oute vl in
95 let_in <:patt<($lid:v$,$lid:r$)>> <:expr< Value.get_pair $ine$ >> oute
96 | [] -> assert false
97
98 let list_lit el =
99 List.fold_right (fun a e -> <:expr< [$a$ :: $e$] >>) el <:expr< [] >>
100
101 let protect e f =
102 match e with
103 | <:expr< $lid:x$ >> -> f e
104 | e ->
105 let x = mk_var () in
106 let r = f <:expr< $lid:x$ >> in
107 <:expr< let $lid:x$ = $e$ in $r$ >>
108
109 (* Registered types *)
110
111 module HashTypes = Hashtbl.Make(Types)
112 let registered_types = HashTypes.create 13
113 let nb_registered_types = ref 0
114
115 let register_type t =
116 let n =
117 try HashTypes.find registered_types t
118 with Not_found ->
119 let i = !nb_registered_types in
120 HashTypes.add registered_types t i;
121 incr nb_registered_types;
122 i
123 in
124 <:expr< types.($int:string_of_int n$) >>
125
126 let get_registered_types () =
127 let a = Array.make !nb_registered_types Types.empty in
128 HashTypes.iter (fun t i -> a.(i) <- t) registered_types;
129 a
130
131 (* OCaml -> CDuce conversions *)
132
133
134 let to_cd_gen = ref []
135
136 let to_cd_fun_name t =
137 Printf.sprintf "to_cd_%i" t.uid
138
139 let to_cd_fun t =
140 to_cd_gen := t :: !to_cd_gen;
141 to_cd_fun_name t
142
143 let to_ml_gen = ref []
144
145 let to_ml_fun_name t =
146 Printf.sprintf "to_ml_%i" t.uid
147
148 let to_ml_fun t =
149 to_ml_gen := t :: !to_ml_gen;
150 to_ml_fun_name t
151
152 let rec tuple = function
153 | [v] -> v
154 | v::l -> <:expr< Value.Pair ($v$, $tuple l$) >>
155 | [] -> assert false
156
157 let pat_tuple vars =
158 let pl = List.map (fun id -> <:patt< $lid:id$ >>) vars in
159 <:patt< ($list:pl$) >>
160
161
162 let rec to_cd e t =
163 (* Format.fprintf Format.std_formatter "to_cd %a [uid=%i; recurs=%i]@."
164 Mltypes.print t t.uid t.recurs; *)
165 if t.recurs > 0 then <:expr< $lid:to_cd_fun t$ $e$ >>
166 else to_cd_descr e t.def
167
168 and to_cd_descr e = function
169 | Link t -> to_cd e t
170 | Arrow (t,s) ->
171 (* let y = <...> in Value.Abstraction ([t,s], fun x -> s(y (t(x))) *)
172 protect e
173 (fun y ->
174 let x = mk_var () in
175 let arg = to_ml <:expr< $lid:x$ >> t in
176 let res = to_cd <:expr< $y$ $arg$ >> s in
177 let abs = <:expr< fun $lid:x$ -> $res$ >> in
178 let tt = register_type (Types.descr (typ t)) in
179 let ss = register_type (Types.descr (typ s)) in
180 <:expr< Value.Abstraction ([($tt$,$ss$)],$abs$) >>
181 )
182 | Tuple tl ->
183 (* let (x1,...,xn) = ... in Value.Pair (t1(x1), Value.Pair(...,tn(xn))) *)
184 let vars = mk_vars tl in
185 let_in (pat_tuple vars) e (tuple (tuple_to_cd tl vars))
186 | PVariant l ->
187 (* match <...> with
188 | `A -> Value.atom_ascii "A"
189 | `B x -> Value.Pair (Value.atom_ascii "B",t(x))
190 *)
191 let cases =
192 List.map
193 (function
194 | (lab,None) -> <:patt< `$lid:lab$ >>, atom_ascii lab
195 | (lab,Some t) ->
196 <:patt< `$lid:lab$ x >>,
197 pair (atom_ascii lab) (to_cd <:expr< x >> t)
198 ) l in
199 pmatch e cases
200 | Variant (l,_) ->
201 (* match <...> with
202 | A -> Value.atom_ascii "A"
203 | B (x1,x2,..) -> Value.Pair (Value.atom_ascii "B",...,Value.Pair(tn(x)))
204 *)
205 let cases =
206 List.map
207 (function
208 | (lab,[]) -> <:patt< $uid:lab$ >>, atom_ascii lab
209 | (lab,tl) ->
210 let vars = mk_vars tl in
211 <:patt< $uid:lab$ $pat_tuple vars$ >>,
212 tuple (atom_ascii lab :: tuple_to_cd tl vars)
213 ) l in
214 pmatch e cases
215 | Record (l,_) ->
216 (* let x = <...> in Value.record [ l1,t1(x.l1); ...; ln,x.ln ] *)
217 protect e
218 (fun x ->
219 let l =
220 List.map
221 (fun (lab,t) ->
222 let e = to_cd <:expr<$x$.$lid:lab$>> t in
223 <:expr< ($label_ascii lab$, $e$) >>)
224 l
225 in
226 <:expr< Value.record $list_lit l$ >>)
227
228 | Abstract "int" -> <:expr< ocaml2cduce_int $e$ >>
229 | Abstract "char" -> <:expr< ocaml2cduce_char $e$ >>
230 | Abstract "string" -> <:expr< ocaml2cduce_string $e$ >>
231 | Abstract s -> <:expr< Value.abstract $str:String.escaped s$ $e$ >>
232 | Builtin ("list",[t]) ->
233 (* Value.sequence_rev (List.rev_map fun_t <...>) *)
234 <:expr< Value.sequence_rev (List.rev_map $lid:to_cd_fun t$ $e$) >>
235 | Builtin ("Pervasives.ref",[t]) ->
236 (* let x = <...> in
237 Value.mk_ext_ref t (fun () -> t(!x)) (fun y -> x := t'(y)) *)
238 protect e
239 (fun e ->
240 let y = mk_var () in
241 let tt = register_type (Types.descr (typ t)) in
242 let get_x = <:expr< $e$.val >> in
243 let get = <:expr< fun () -> $to_cd get_x t$ >> in
244 let tr_y = to_ml <:expr< $lid:y$ >> t in
245 let set = <:expr< fun $lid:y$ -> $e$.val := $tr_y$ >> in
246 <:expr< Value.mk_ext_ref $tt$ $get$ $set$ >>
247 )
248
249 | Builtin ("CDuce_all.Value.t", []) -> e
250 | Builtin ("unit", []) -> <:expr< do { $e$; Value.nil } >>
251 | _ -> assert false
252
253 and tuple_to_cd tl vars = List.map2 (fun t id -> to_cd <:expr< $lid:id$ >> t) tl vars
254
255 (* CDuce -> OCaml conversions *)
256
257
258
259 and to_ml e t =
260 (* Format.fprintf Format.std_formatter "to_ml %a@."
261 Mltypes.print t; *)
262 if t.recurs > 0 then <:expr< $lid:to_ml_fun t$ $e$ >>
263 else to_ml_descr e t.def
264
265 and to_ml_descr e = function
266 | Link t -> to_ml e t
267 | Arrow (t,s) ->
268 (* let y = <...> in fun x -> s(Eval.eval_apply y (t(x))) *)
269 protect e
270 (fun y ->
271 let x = mk_var () in
272 let arg = to_cd <:expr< $lid:x$ >> t in
273 let res = to_ml <:expr< Eval.eval_apply $y$ $arg$ >> s in
274 <:expr< fun $lid:x$ -> $res$ >>
275 )
276
277 | Tuple tl ->
278 (* let (x1,r) = Value.get_pair <...> in
279 let (x2,r) = Value.get_pair r in
280 ...
281 let (xn-1,xn) = Value.get_pair r in
282 (t1(x1),...,tn(xn)) *)
283
284 let vars = mk_vars tl in
285 let el = tuple_to_ml tl vars in
286 matches e <:expr< ($list:el$) >> vars
287 | PVariant l ->
288 (* match Value.get_variant <...> with
289 | "A",None -> `A
290 | "B",Some x -> `B (t(x))
291 *)
292 let x = mk_var () in
293 let cases =
294 List.map
295 (function
296 | (lab,None) ->
297 <:patt< ($str: String.escaped lab$, None) >>,
298 <:expr< `$lid:lab$ >>
299 | (lab,Some t) ->
300 let x = mk_var () in
301 let ex = <:expr< $lid:x$ >> in
302 <:patt< ($str: String.escaped lab$, Some $lid:x$) >>,
303 <:expr< `$lid:lab$ $to_ml ex t$ >>
304 ) l in
305 pmatch <:expr< Value.get_variant $e$ >> cases
306 | Variant (l,false) ->
307 failwith "Private Sum type"
308 | Variant (l,true) ->
309 (* match Value.get_variant <...> with
310 | "A",None -> A
311 | "B",Some x -> let (x1,r) = x in ...
312 *)
313 let cases =
314 List.map
315 (function
316 | (lab,[]) ->
317 <:patt< ($str: String.escaped lab$, None) >>,
318 (match lab with (* Stupid Camlp4 *)
319 | "true" -> <:expr< True >>
320 | "false" -> <:expr< False >>
321 | lab -> <:expr< $lid:lab$ >>)
322 | (lab,[t]) ->
323 let x = mk_var () in
324 let ex = <:expr< $lid:x$ >> in
325 <:patt< ($str: String.escaped lab$, Some $lid:x$) >>,
326 <:expr< $lid:lab$ $to_ml ex t$ >>
327 | (lab,tl) ->
328 let vars = mk_vars tl in
329 let el = tuple_to_ml tl vars in
330 let x = mk_var () in
331 <:patt< ($str: String.escaped lab$, Some $lid:x$) >>,
332 matches <:expr< $lid:x$ >>
333 <:expr< $lid:lab$ ($list:el$) >> vars
334 ) l in
335 pmatch <:expr< Value.get_variant $e$ >> cases
336 | Record (l,false) ->
337 failwith "Private Record type"
338 | Record (l,true) ->
339 (* let x = <...> in
340 { l1 = t1(Value.get_field x "l1"); ... } *)
341 protect e
342 (fun x ->
343 let l =
344 List.map
345 (fun (lab,t) ->
346 (<:patt< $uid:lab$>>,
347 to_ml
348 <:expr< Value.get_field $x$ $label_ascii lab$ >> t)) l in
349 <:expr< {$list:l$} >>)
350
351 | Abstract "int" -> <:expr< cduce2ocaml_int $e$ >>
352 | Abstract "char" -> <:expr< cduce2ocaml_char $e$ >>
353 | Abstract "string" -> <:expr< cduce2ocaml_string $e$ >>
354 | Abstract s -> <:expr< Value.get_abstract $e$ >>
355 | Builtin ("list",[t]) ->
356 (* List.rev_map fun_t (Value.get_sequence_rev <...> *)
357 <:expr< List.rev_map $lid:to_ml_fun t$ (Value.get_sequence_rev $e$) >>
358 | Builtin ("Pervasives.ref",[t]) ->
359 (* ref t(Eval.eval_apply (Value.get_field <...> "get") Value.nil) *)
360 let e = <:expr< Value.get_field $e$ $label_ascii "get"$ >> in
361 let e = <:expr< Eval.eval_apply $e$ Value.nil >> in
362 <:expr< Pervasives.ref $to_ml e t$ >>
363 | Builtin ("CDuce_all.Value.t", []) -> e
364 | Builtin ("unit", []) -> <:expr< ignore $e$ >>
365 | _ -> assert false
366
367 and tuple_to_ml tl vars = List.map2 (fun t id -> to_ml <:expr< $lid:id$ >> t) tl vars
368
369
370 let to_ml_done = IntHash.create 13
371 let to_cd_done = IntHash.create 13
372
373 let global_transl () =
374 let defs = ref [] in
375 let rec aux hd tl gen don fun_name to_descr =
376 gen := tl;
377 if not (IntHash.mem don hd.uid) then (
378 IntHash.add don hd.uid ();
379 let p = <:patt< $lid:fun_name hd$ >> in
380 let e = <:expr< fun x -> $to_descr <:expr< x >> hd.def$ >> in
381 defs := (p,e) :: !defs
382 );
383 loop ()
384 and loop () = match !to_cd_gen,!to_ml_gen with
385 | hd::tl,_ -> aux hd tl to_cd_gen to_cd_done to_cd_fun_name to_cd_descr
386 | _,hd::tl -> aux hd tl to_ml_gen to_ml_done to_ml_fun_name to_ml_descr
387 | [],[] -> ()
388 in
389 loop ();
390 !defs
391
392 (* Check type constraints and generate stub code *)
393
394 let err_ppf = Format.err_formatter
395
396 let exts = ref []
397
398 let check_value ty_env c_env (s,caml_t,t) =
399 (* Find the type for the value in the CDuce module *)
400 let id = Id.mk (U.mk s) in
401 let vt =
402 try Typer.find_value id ty_env
403 with Not_found ->
404 Format.fprintf err_ppf
405 "The interface exports a value %s which is not available in the module@." s;
406 exit 1
407 in
408
409 (* Compute expected CDuce type *)
410 let et = Types.descr (typ t) in
411
412 (* Check subtyping *)
413 if not (Types.subtype vt et) then
414 (
415 Format.fprintf
416 err_ppf
417 "The type for the value %s is invalid@\n\
418 Expected Caml type:@[%a@]@\n\
419 Expected CDuce type:@[%a@]@\n\
420 Inferred type:@[%a@]@."
421 s
422 print_ocaml caml_t
423 Types.Print.print et
424 Types.Print.print vt;
425 exit 1
426 );
427
428 (* Generate stub code *)
429 (* let x = t(Eval.get_slot cu slot) *)
430 let slot = Compile.find_slot id c_env in
431 let e = to_ml <:expr< Eval.get_slot cu $int:string_of_int slot$ >> t in
432 <:patt< $uid:s$ >>, e
433
434 let stub name ty_env c_env values =
435 let items = List.map (check_value ty_env c_env) values in
436 let exts =
437 List.map
438 (fun (s,i,t) ->
439 let c = to_cd <:expr< $lid:s$ >> t in
440 <:str_item< Eval.set_slot cu $int:string_of_int i$ $c$ >>
441 ) !exts in
442
443
444 let g = global_transl () in
445
446 (* open Cdml
447 open CDuce_all
448 let cu = Cdml.initialize <modname>
449 let rec <global translation functions>
450 <fills external slots>
451 <run the unit>
452 let <stubs for values>
453 *)
454
455 [ <:str_item< open Cdml >>;
456 <:str_item< open CDuce_all >>;
457 <:str_item< value cu = Cdml.initialize $str: String.escaped name$ >>;
458 <:str_item< value types = Librarian.registered_types cu >>;
459 <:str_item< declare $list:exts$ end >>;
460 <:str_item< Librarian.run cu >>
461 ] @
462 (if g = [] then [] else [ <:str_item< value rec $list:g$ >> ]) @
463 (if items = [] then [] else [ <:str_item< value $list:items$ >> ])
464
465
466
467 let () =
468 Librarian.stub_ml :=
469 (fun cu ty_env c_env ->
470 try
471 let name = String.capitalize cu in
472 let (prolog, values) =
473 try Mltypes.read_cmi name
474 with Not_found ->
475 Printf.eprintf "Warning: no caml interface\n";
476 ("",[]) in
477 let code = stub cu ty_env c_env values in
478 Some (Obj.magic (prolog,code)),
479 get_registered_types ()
480 with Mltypes.Error s -> raise (Location.Generic s)
481 );
482
483 Externals.register_external :=
484 (fun s i ->
485 let t =
486 try Mltypes.find_value s
487 with Not_found ->
488 Printf.eprintf "Cannot resolve the external symbol %s\n" s;
489 exit 1
490 in
491 exts := (s, i, t) :: !exts;
492 fun () -> Types.descr (typ t)
493 )

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