(***********************************************************************) (* *) (* Objective Caml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* Automatique. Distributed only by permission. *) (* *) (***********************************************************************) (* $Id$ *) (* Translation from typed abstract syntax to lambda terms, for the module language *) open Misc open Asttypes open Path open Types open Typedtree open Lambda open Translobj open Translcore open Translclass (* Compile a coercion *) let rec apply_coercion restr arg = match restr with Tcoerce_none -> arg | Tcoerce_structure pos_cc_list -> name_lambda arg (fun id -> Lprim(Pmakeblock(0, Immutable), List.map (apply_coercion_field id) pos_cc_list)) | Tcoerce_functor(cc_arg, cc_res) -> let param = Ident.create "funarg" in name_lambda arg (fun id -> Lfunction(Curried, [param], apply_coercion cc_res (Lapply(Lvar id, [apply_coercion cc_arg (Lvar param)])))) | Tcoerce_primitive p -> fatal_error "Translmod.apply_coercion" and apply_coercion_field id (pos, cc) = match cc with Tcoerce_primitive p -> transl_primitive p | _ -> apply_coercion cc (Lprim(Pfield pos, [Lvar id])) (* Compose two coercions apply_coercion c1 (apply_coercion c2 e) behaves like apply_coercion (compose_coercions c1 c2) e. *) let rec compose_coercions c1 c2 = match (c1, c2) with (Tcoerce_none, c2) -> c2 | (c1, Tcoerce_none) -> c1 | (Tcoerce_structure pc1, Tcoerce_structure pc2) -> let v2 = Array.of_list pc2 in Tcoerce_structure (List.map (fun (p1, c1) -> let (p2, c2) = v2.(p1) in (p2, compose_coercions c1 c2)) pc1) | (Tcoerce_functor(arg1, res1), Tcoerce_functor(arg2, res2)) -> Tcoerce_functor(compose_coercions arg2 arg1, compose_coercions res1 res2) | (_, _) -> fatal_error "Translmod.compose_coercions" (* Record the primitive declarations occuring in the module compiled *) let primitive_declarations = ref ([] : string list) (* Keep track of the root path (from the root of the namespace to the currently compiled module expression). Useful for naming exceptions. *) let global_path glob = Some(Pident glob) let functor_path path param = match path with None -> None | Some p -> Some(Papply(p, Pident param)) let field_path path field = match path with None -> None | Some p -> Some(Pdot(p, Ident.name field, Path.nopos)) (* Compile a module expression *) let rec transl_module cc rootpath mexp = match mexp.mod_desc with Tmod_ident path -> apply_coercion cc (transl_path path) | Tmod_structure str -> transl_structure [] cc rootpath str | Tmod_functor(param, mty, body) -> let bodypath = functor_path rootpath param in begin match cc with Tcoerce_none -> Lfunction(Curried, [param], transl_module Tcoerce_none bodypath body) | Tcoerce_functor(ccarg, ccres) -> let param' = Ident.create "funarg" in Lfunction(Curried, [param'], Llet(Alias, param, apply_coercion ccarg (Lvar param'), transl_module ccres bodypath body)) | _ -> fatal_error "Translmod.transl_module" end | Tmod_apply(funct, arg, ccarg) -> apply_coercion cc (Lapply(transl_module Tcoerce_none None funct, [transl_module ccarg None arg])) | Tmod_constraint(arg, mty, ccarg) -> transl_module (compose_coercions cc ccarg) rootpath arg and transl_structure fields cc rootpath = function [] -> begin match cc with Tcoerce_none -> Lprim(Pmakeblock(0, Immutable), List.map (fun id -> Lvar id) (List.rev fields)) | Tcoerce_structure pos_cc_list -> let v = Array.of_list (List.rev fields) in Lprim(Pmakeblock(0, Immutable), List.map (fun (pos, cc) -> match cc with Tcoerce_primitive p -> transl_primitive p | _ -> apply_coercion cc (Lvar v.(pos))) pos_cc_list) | _ -> fatal_error "Translmod.transl_structure" end | Tstr_eval expr :: rem -> Lsequence(transl_exp expr, transl_structure fields cc rootpath rem) | Tstr_value(rec_flag, pat_expr_list) :: rem -> let ext_fields = rev_let_bound_idents pat_expr_list @ fields in transl_let rec_flag pat_expr_list (transl_structure ext_fields cc rootpath rem) | Tstr_primitive(id, descr) :: rem -> begin match descr.val_kind with Val_prim p -> primitive_declarations := p.Primitive.prim_name :: !primitive_declarations | _ -> () end; transl_structure fields cc rootpath rem | Tstr_type(decls) :: rem -> transl_structure fields cc rootpath rem | Tstr_exception(id, decl) :: rem -> Llet(Strict, id, transl_exception id (field_path rootpath id) decl, transl_structure (id :: fields) cc rootpath rem) | Tstr_module(id, modl) :: rem -> Llet(Strict, id, transl_module Tcoerce_none (field_path rootpath id) modl, transl_structure (id :: fields) cc rootpath rem) | Tstr_modtype(id, decl) :: rem -> transl_structure fields cc rootpath rem | Tstr_open path :: rem -> transl_structure fields cc rootpath rem | Tstr_class cl_list :: rem -> Lletrec(List.map (fun (id, arity, meths, cl) -> (id, transl_class id arity meths cl)) cl_list, transl_structure ((List.rev (List.map (fun (i, _, _, _) -> i) cl_list)) @ fields) cc rootpath rem) | Tstr_cltype cl_list :: rem -> transl_structure fields cc rootpath rem (* Update forward declaration in Translcore *) let _ = Translcore.transl_module := transl_module (* Compile an implementation *) let transl_implementation module_name (str, cc) = reset_labels (); primitive_declarations := []; let module_id = Ident.create_persistent module_name in Lprim(Psetglobal module_id, [transl_label_init (transl_structure [] cc (global_path module_id) str)]) (* A variant of transl_structure used to compile toplevel structure definitions for the native-code compiler. Store the defined values in the fields of the global as soon as they are defined, in order to reduce register pressure. "map" is a table from idents to (position in global block, coercion). "prim" is a list of (position in global block, primitive declaration). *) let transl_store_structure glob map prims str = let rec transl_store = function [] -> lambda_unit | Tstr_eval expr :: rem -> Lsequence(transl_exp expr, transl_store rem) | Tstr_value(rec_flag, pat_expr_list) :: rem -> transl_let rec_flag pat_expr_list (store_idents glob map (let_bound_idents pat_expr_list) (transl_store rem)) | Tstr_primitive(id, descr) :: rem -> begin match descr.val_kind with Val_prim p -> primitive_declarations := p.Primitive.prim_name :: !primitive_declarations | _ -> () end; transl_store rem | Tstr_type(decls) :: rem -> transl_store rem | Tstr_exception(id, decl) :: rem -> Llet(Strict, id, transl_exception id (field_path (global_path glob) id) decl, store_ident glob map id (transl_store rem)) | Tstr_module(id, modl) :: rem -> Llet(Strict, id, transl_module Tcoerce_none (field_path (global_path glob) id) modl, store_ident glob map id (transl_store rem)) | Tstr_modtype(id, decl) :: rem -> transl_store rem | Tstr_open path :: rem -> transl_store rem | Tstr_class cl_list :: rem -> Lletrec(List.map (fun (id, arity, meths, cl) -> (id, transl_class id arity meths cl)) cl_list, store_idents glob map (List.map (fun (i, _, _, _) -> i) cl_list) (transl_store rem)) | Tstr_cltype cl_list :: rem -> transl_store rem and store_ident glob map id cont = try let (pos, cc) = Ident.find_same id map in let init_val = apply_coercion cc (Lvar id) in Lsequence (Lprim(Psetfield(pos, false), [Lprim(Pgetglobal glob, []); init_val]), cont) with Not_found -> cont and store_idents glob map idlist cont = List.fold_right (store_ident glob map) idlist cont and store_primitive (pos, prim) cont = Lsequence(Lprim(Psetfield(pos, false), [Lprim(Pgetglobal glob, []); transl_primitive prim]), cont) in List.fold_right store_primitive prims (transl_store str) (* Build the list of value identifiers defined by a toplevel structure *) let rec defined_idents = function [] -> [] | Tstr_eval expr :: rem -> defined_idents rem | Tstr_value(rec_flag, pat_expr_list) :: rem -> let_bound_idents pat_expr_list @ defined_idents rem | Tstr_primitive(id, descr) :: rem -> defined_idents rem | Tstr_type decls :: rem -> defined_idents rem | Tstr_exception(id, decl) :: rem -> id :: defined_idents rem | Tstr_module(id, modl) :: rem -> id :: defined_idents rem | Tstr_modtype(id, decl) :: rem -> defined_idents rem | Tstr_open path :: rem -> defined_idents rem | Tstr_class cl_list :: rem -> List.map (fun (i, _, _, _) -> i) cl_list @ defined_idents rem | Tstr_cltype cl_list :: rem -> defined_idents rem (* Transform a coercion and the list of value identifiers built above into a table id -> (pos, coercion), with [pos] being the position in the global block where the value of [id] must be stored, and [coercion] the coercion to be applied to it. A given identifier may appear several times in the coercion (if it occurs several times in the signature); remember to assign it the position of its last occurrence. Also buid a list of primitives and their positions in the global block, and the total size of the global block. *) let build_ident_map restr idlist = match restr with Tcoerce_none -> let rec build_map pos map = function [] -> (map, [], pos) | id :: rem -> build_map (pos+1) (Ident.add id (pos, Tcoerce_none) map) rem in build_map 0 Ident.empty idlist | Tcoerce_structure pos_cc_list -> let idarray = Array.of_list idlist in let rec build_map pos map prims = function [] -> (map, prims, pos) | (source_pos, Tcoerce_primitive p) :: rem -> build_map (pos+1) map ((pos, p) :: prims) rem | (source_pos, cc) :: rem -> build_map (pos+1) (Ident.add idarray.(source_pos) (pos, cc) map) prims rem in build_map 0 Ident.empty [] pos_cc_list | _ -> fatal_error "Translmod.build_ident_map" (* Compile an implementation using transl_store_structure (for the native-code compiler). *) let transl_store_implementation module_name (str, restr) = reset_labels (); primitive_declarations := []; let module_id = Ident.create_persistent module_name in let (map, prims, size) = build_ident_map restr (defined_idents str) in (size, transl_label_init (transl_store_structure module_id map prims str)) (* Compile a sequence of expressions *) let rec make_sequence fn = function [] -> lambda_unit | [x] -> fn x | x::rem -> let lam = fn x in Lsequence(lam, make_sequence fn rem) (* Compile a toplevel phrase *) let transl_toplevel_item = function Tstr_eval expr -> transl_exp expr | Tstr_value(rec_flag, pat_expr_list) -> let idents = let_bound_idents pat_expr_list in let lam = transl_let rec_flag pat_expr_list (make_sequence (fun id -> Lprim(Psetglobal id, [Lvar id])) idents) in List.iter Ident.make_global idents; lam | Tstr_primitive(id, descr) -> lambda_unit | Tstr_type(decls) -> lambda_unit | Tstr_exception(id, decl) -> Ident.make_global id; Lprim(Psetglobal id, [transl_exception id None decl]) | Tstr_module(id, modl) -> Ident.make_global id; Lprim(Psetglobal id, [transl_module Tcoerce_none None modl]) | Tstr_modtype(id, decl) -> lambda_unit | Tstr_open path -> lambda_unit | Tstr_class cl_list -> let lam = Lletrec(List.map (fun (id, arity, meths, cl) -> (id, transl_class id arity meths cl)) cl_list, make_sequence (fun (id, _, _, _) -> Lprim(Psetglobal id, [Lvar id])) cl_list) in List.iter (fun (id, _, _, _) -> Ident.make_global id) cl_list; lam | Tstr_cltype cl_list -> lambda_unit let transl_toplevel_definition str = reset_labels (); transl_label_init (make_sequence transl_toplevel_item str)