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

Contents of /ocamliface/mlstub.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1215 - (show annotations)
Tue Jul 10 18:31:55 2007 UTC (5 years, 10 months ago) by abate
File size: 16370 byte(s)
[r2004-07-05 13:19:51 by afrisch] eval

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

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