heptagon/compiler/obc/java/obc2java.ml

312 lines
14 KiB
OCaml
Raw Normal View History

2011-01-20 23:05:18 +01:00
(**************************************************************************)
(* *)
(* Heptagon *)
(* *)
(* Author : Marc Pouzet *)
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
(* *)
(**************************************************************************)
(** An Obc.program is a Java.package,
Obc.type_dec, Obc.class_def are Java.classs
Obc.const_dec is defined in the special class CONSTANTES
Obc.Lvar are Pvar
Obc.Lmem are this.Pvar (Pfield)
Obc.Oobj and Oarray are simply Pvar and Parray_elem
Obc.Types_alias are dereferenced since no simple type alias is possible in Java *)
open Format
open Misc
open Names
open Modules
open Signature
open Obc
open Java
2011-01-24 16:07:26 +01:00
let fresh_it () =
let id = Idents.gen_var "obc2java" "i" in
id, mk_var_dec id Tint
(** fresh Afor from 0 to [size] with [body] a function from [var_ident] (the iterator) to [act] list *)
let fresh_for size body =
let i, id = fresh_it () in
Afor (id, Sint 0, size, mk_block (body i))
2011-01-20 23:05:18 +01:00
(** a [Module] becomes a [package] *)
let translate_qualname q = match q with
| { qual = "Pervasives" } -> q
| { qual = m } when m = g_env.current_mod -> q (* current module is not translated to keep track,
there is no issue since printed without the qualifier *)
| { qual = m } when m = local_qualname -> q
| _ -> { q with qual = String.lowercase q.qual }
(** a [Module.const] becomes a [module.CONSTANTES.CONST] *)
2011-01-24 16:07:26 +01:00
let translate_const_name q = match q with
| { qual = m } when m = local_qualname -> { q with name = String.uppercase q.name }
| _ -> { q with qual = (String.lowercase q.qual)^ ".CONSTANTES"; name = String.uppercase q.name }
2011-01-20 23:05:18 +01:00
(** a [Module.name] becomes a [module.Name]
used for type_names, class_names, fun_names *)
let qualname_to_class_name q =
let q = translate_qualname q in
{ q with name = String.capitalize q.name }
(** a [Module.Constr] of an [Module.enum] type becomes a [module.Enum.CONSTR] of the [module.Enum] class *)
2011-01-24 16:07:26 +01:00
let _translate_constructor_name q q_ty = (* TODO java recursive qualname ! *)
2011-01-20 23:05:18 +01:00
let classe = qualname_to_class_name q_ty in
2011-01-24 16:07:26 +01:00
let q = qualname_to_class_name q in
{ q with name = classe.name ^ "." ^ q.name }
2011-01-20 23:05:18 +01:00
let translate_constructor_name q =
2011-01-24 16:07:26 +01:00
match Modules.find_constrs q with
| Types.Tid q_ty when q_ty = Initial.pbool -> q |> shortname |> local_qn
| Types.Tid q_ty -> _translate_constructor_name q q_ty
2011-01-20 23:05:18 +01:00
| _ -> assert false
2011-01-24 16:07:26 +01:00
let translate_field_name f = f |> Names.shortname |> String.lowercase
2011-01-20 23:05:18 +01:00
(** a [name] becomes a [package.Name] *)
let name_to_classe_name n = n |> Modules.current_qual |> qualname_to_class_name
(** translate an ostatic_exp into an jexp *)
let rec static_exp param_env se = match se.Types.se_desc with
| Types.Svar c ->
if shortname c = local_qualname
then let n = NamesEnv.find (shortname c) param_env in Svar (n |> Idents.name |> local_qn)
else Svar (translate_const_name c)
| Types.Sint i -> Sint i
| Types.Sfloat f -> Sfloat f
| Types.Sbool b -> Sbool b
| Types.Sconstructor c -> let c = translate_constructor_name c in Sconstructor c
2011-01-24 16:07:26 +01:00
| Types.Sfield f -> eprintf "ojSfield @."; assert false;
| Types.Stuple t -> eprintf "ojStuple@."; assert false;
(* TODO java ?? not too difficult if needed, return Tuplen<..>() *)
| Types.Sarray_power _ -> eprintf "ojSarray_power@."; assert false; (* TODO java array *)
| Types.Sarray se_l -> Enew_array (ty param_env se.Types.se_ty, List.map (static_exp param_env) se_l)
| Types.Srecord _ -> eprintf "ojSrecord@."; assert false; (* TODO java *)
2011-01-20 23:05:18 +01:00
| Types.Sop (f, se_l) -> Efun (qualname_to_class_name f, List.map (static_exp param_env) se_l)
and boxed_ty param_env t = match t with
| Types.Tprod ty_l ->
2011-01-24 16:07:26 +01:00
let ln = ty_l |> List.length |> Pervasives.string_of_int in
2011-01-20 23:05:18 +01:00
Tgeneric ({ qual = "heptagon"; name = "Tuple"^ln }, List.map (boxed_ty param_env) ty_l)
| Types.Tid t when t = Initial.pbool -> Tclass (Names.local_qn "Boolean")
| Types.Tid t when t = Initial.pint -> Tclass (Names.local_qn "Integer")
| Types.Tid t when t = Initial.pfloat -> Tclass (Names.local_qn "Float")
| Types.Tid t -> Tclass (qualname_to_class_name t)
| Types.Tarray (t,size) -> Tarray (boxed_ty param_env t, static_exp param_env size)
| Types.Tasync _ -> assert false; (* TODO async *)
| Types.Tunit -> Tunit
and ty param_env t :Java.ty = match t with
| Types.Tprod ty_l ->
2011-01-24 16:07:26 +01:00
let ln = ty_l |> List.length |> Pervasives.string_of_int in
2011-01-20 23:05:18 +01:00
Tgeneric ({ qual = "heptagon"; name = "Tuple"^ln }, List.map (boxed_ty param_env) ty_l)
| Types.Tid t when t = Initial.pbool -> Tbool
| Types.Tid t when t = Initial.pint -> Tint
| Types.Tid t when t = Initial.pfloat -> Tfloat
| Types.Tid t -> Tclass (qualname_to_class_name t)
| Types.Tarray (t,size) -> Tarray (ty param_env t, static_exp param_env size)
| Types.Tasync _ -> assert false; (* TODO async *)
| Types.Tunit -> Tunit
2011-01-24 16:07:26 +01:00
let var_dec param_env vd = { vd_type = ty param_env vd.v_type; vd_ident = vd.v_ident }
let var_dec_list param_env vd_l = List.map (var_dec param_env) vd_l
let rec exp param_env e = match e.e_desc with
| Obc.Epattern p -> Eval (pattern param_env p)
| Obc.Econst se -> static_exp param_env se
| Obc.Eop (op,e_l) -> Efun (op, exp_list param_env e_l)
| Obc.Estruct _ -> eprintf "ojEstruct@."; assert false (* TODO java *)
| Obc.Earray e_l -> Enew_array (ty param_env e.e_ty, exp_list param_env e_l)
| Obc.Ebang _ -> eprintf "ojEbang@."; assert false (* TODO java async *)
2011-01-20 23:05:18 +01:00
2011-01-24 16:07:26 +01:00
and exp_list param_env e_l = List.map (exp param_env) e_l
2011-01-20 23:05:18 +01:00
2011-01-24 16:07:26 +01:00
and pattern param_env p = match p.pat_desc with
| Obc.Lvar v -> Pvar v
| Obc.Lmem v -> Pthis v
| Obc.Lfield (p,f) -> Pfield (pattern param_env p, translate_field_name f)
| Obc.Larray (p,e) -> Parray_elem (pattern param_env p, exp param_env e)
let obj_ref param_env o = match o with
| Oobj id -> Pvar id
| Oarray (id,p) -> Parray_elem (Pvar id, Eval (pattern param_env p))
let rec act_list param_env act_l acts =
let _act act acts = match act with
2011-01-20 23:05:18 +01:00
| Obc.Aassgn (p,e) -> (Aassgn (pattern param_env p, exp param_env e))::acts
| Obc.Acall ([], obj, Mstep, e_l) ->
let acall = Amethod_call (obj_ref param_env obj, "step", exp_list param_env e_l) in
acall::acts
| Obc.Acall ([p], obj, Mstep, e_l) ->
let ecall = Emethod_call (obj_ref param_env obj, "step", exp_list param_env e_l) in
2011-01-24 16:07:26 +01:00
let assgn = Aassgn (pattern param_env p, ecall) in
2011-01-20 23:05:18 +01:00
assgn::acts
2011-01-24 16:07:26 +01:00
| Obc.Acall (p_l, obj, Mstep, e_l) ->
2011-01-20 23:05:18 +01:00
let return_ty = p_l |> pattern_list_to_type |> (ty param_env) in
let return_id = Idents.gen_var "obc2java" "out" in
let return_vd = { vd_type = return_ty; vd_ident = return_id } in
let ecall = Emethod_call (obj_ref param_env obj, "step", exp_list param_env e_l) in
let assgn = Anewvar (return_vd, ecall) in
2011-01-24 16:07:26 +01:00
let copy_return_to_var i p =
Aassgn (pattern param_env p, Eval (Pfield (Pvar return_id, "c"^(string_of_int i))))
in
let copies = Misc.mapi copy_return_to_var p_l in
2011-01-20 23:05:18 +01:00
assgn::(copies@acts)
| Obc.Acall (_, obj, Mreset, _) ->
2011-01-24 16:07:26 +01:00
let acall = Amethod_call (obj_ref param_env obj, "reset", []) in
2011-01-20 23:05:18 +01:00
acall::acts
2011-01-24 16:07:26 +01:00
| Obc.Aasync_call _ -> assert false (* TODO java async *)
| Obc.Acase (e, c_b_l) when e.e_ty = Types.Tid Initial.pbool ->
(match c_b_l with
| [] -> acts
| [(c,b)] when c = Initial.ptrue ->
(Aif (exp param_env e, block param_env b)):: acts
| [(c,b)] when c = Initial.pfalse ->
(Aifelse (exp param_env e, {b_locals = []; b_body = []}, block param_env b)) :: acts
| _ ->
let _, _then = List.find (fun (c,b) -> c = Initial.ptrue) c_b_l in
let _, _else = List.find (fun (c,b) -> c = Initial.pfalse) c_b_l in
(Aifelse (exp param_env e, block param_env _then, block param_env _else)) :: acts)
2011-01-20 23:05:18 +01:00
| Obc.Acase (e, c_b_l) ->
2011-01-24 16:07:26 +01:00
let _c_b (c,b) = translate_constructor_name c, block param_env b in
let acase = Aswitch (exp param_env e, List.map _c_b c_b_l) in
acase::acts
| Obc.Afor (v, se, se', b) ->
let afor = Afor (var_dec param_env v, static_exp param_env se, static_exp param_env se', block param_env b) in
afor::acts
in
List.fold_right _act act_l acts
2011-01-20 23:05:18 +01:00
2011-01-24 16:07:26 +01:00
and block param_env ?(locals=[]) ?(end_acts=[]) ob =
2011-01-20 23:05:18 +01:00
let blocals = var_dec_list param_env ob.Obc.b_locals in
let locals = locals @ blocals in
2011-01-24 16:07:26 +01:00
let acts = act_list param_env ob.Obc.b_body end_acts in
2011-01-20 23:05:18 +01:00
{ b_locals = locals; b_body = acts }
let class_def_list classes cd_l =
let class_def classes cd =
Idents.enter_node cd.cd_name;
let class_name = qualname_to_class_name cd.cd_name in
(* [param_env] is an env mapping local param name to ident *)
let constructeur, param_env =
let param_to_arg param_env p =
2011-01-24 16:07:26 +01:00
let p_ident = Idents.gen_var "obc2java" (String.uppercase p.Signature.p_name) in
2011-01-20 23:05:18 +01:00
let p_vd = { vd_ident = p_ident; vd_type = ty param_env p.Signature.p_type } in
let param_env = NamesEnv.add p.Signature.p_name p_ident param_env in
p_vd, param_env
in
let args, param_env = Misc.mapfold param_to_arg NamesEnv.empty cd.cd_params in
let body =
(* TODO java array : also initialize arrays with [ new int[3] ] *)
let final_field_init_act arg = Aassgn (Pthis arg.vd_ident, Eval (Pvar arg.vd_ident)) in
let obj_init_act acts od =
let params = List.map (static_exp param_env) od.o_params in
let act = match od.o_size with
2011-01-24 16:07:26 +01:00
| None -> [ Aassgn (Pthis od.o_ident, Enew (Tclass od.o_class, params)) ]
| Some size ->
let size = static_exp param_env size in
let assgn_elem i =
[ Aassgn (Parray_elem (Pthis od.o_ident, mk_var i), Enew (Tclass od.o_class, params)) ]
in
[ Aassgn (Pthis od.o_ident, Enew (Tarray (Tclass od.o_class,size), []));
fresh_for size assgn_elem ]
2011-01-20 23:05:18 +01:00
in
2011-01-24 16:07:26 +01:00
act@acts
2011-01-20 23:05:18 +01:00
in
let acts = List.map final_field_init_act args in
let acts = List.fold_left obj_init_act acts cd.cd_objs in
{ b_locals = []; b_body = acts }
in
mk_methode ~args:args body (shortname class_name), param_env
in
let fields =
let mem_to_field fields vd = (mk_field ~protection:Pprotected (ty param_env vd.v_type) vd.v_ident) :: fields in
2011-01-24 16:07:26 +01:00
let obj_to_field fields od =
2011-01-20 23:05:18 +01:00
let jty = match od.o_size with
| None -> Tclass (qualname_to_class_name od.o_class)
| Some size -> Tarray (Tclass (qualname_to_class_name od.o_class), static_exp param_env size)
in
(mk_field ~protection:Pprotected jty od.o_ident) :: fields
in
let params_to_field fields p =
let p_ident = NamesEnv.find p.p_name param_env in
(mk_field ~protection:Pprotected ~final:true (ty param_env p.p_type) p_ident) :: fields
in
let fields = List.fold_left mem_to_field [] cd.cd_mems in
let fields = List.fold_left obj_to_field fields cd.cd_objs in
List.fold_left params_to_field fields cd.cd_params
in
let step =
let ostep = find_step_method cd in
let vd_output = var_dec_list param_env ostep.m_outputs in
let return_ty = ostep.m_outputs |> vd_list_to_type |> (ty param_env) in
let return_act = Areturn (match vd_output with
| [] -> Evoid
| [vd] -> Eval (Pvar vd.vd_ident)
| vd_l -> Enew (return_ty, List.map (fun vd -> Eval (Pvar vd.vd_ident)) vd_l))
in
2011-01-24 16:07:26 +01:00
let body = block param_env ~locals:vd_output ~end_acts:[return_act] ostep.Obc.m_body in
mk_methode ~args:(var_dec_list param_env ostep.Obc.m_inputs) ~returns:return_ty body "step"
2011-01-20 23:05:18 +01:00
in
let reset =
let oreset = find_reset_method cd in
2011-01-24 16:07:26 +01:00
let body = block param_env oreset.Obc.m_body in
2011-01-20 23:05:18 +01:00
mk_methode body "reset"
in
2011-01-24 16:07:26 +01:00
let classe = mk_classe ~fields:fields ~constrs:[constructeur] ~methodes:[step;reset] class_name in
2011-01-20 23:05:18 +01:00
classe::classes
in
2011-01-24 16:07:26 +01:00
List.fold_left class_def classes cd_l
2011-01-20 23:05:18 +01:00
let type_dec_list classes td_l =
let param_env = NamesEnv.empty in
let _td classes td =
2011-01-24 16:07:26 +01:00
let classe_name = qualname_to_class_name td.t_name in
match td.t_desc with
| Type_abs -> Misc.unsupported "obc2java" 1 (* TODO java *)
| Type_alias ot -> classes (* TODO java alias ?? *)
2011-01-20 23:05:18 +01:00
| Type_enum c_l ->
2011-01-24 16:07:26 +01:00
let mk_constr_enum c = _translate_constructor_name c td.t_name in
(mk_enum (List.map mk_constr_enum c_l) classe_name) :: classes
2011-01-20 23:05:18 +01:00
| Type_struct f_l ->
2011-01-24 16:07:26 +01:00
let mk_field_jfield { Signature.f_name = oname; Signature.f_type = oty } =
2011-01-20 23:05:18 +01:00
let jty = ty param_env oty in
2011-01-24 16:07:26 +01:00
let field = Idents.ident_of_name (translate_field_name oname) in (* TODO java pretty ugly *)
mk_field jty field
2011-01-20 23:05:18 +01:00
in
(mk_classe ~fields:(List.map mk_field_jfield f_l) classe_name) :: classes
in
2011-01-24 16:07:26 +01:00
List.fold_left _td classes td_l
2011-01-20 23:05:18 +01:00
let const_dec_list cd_l =
let param_env = NamesEnv.empty in
let mk_const_field { Obc.c_name = oname ; Obc.c_value = ovalue; Obc.c_type = otype } =
2011-01-24 16:07:26 +01:00
let name = oname |> translate_const_name |> shortname |> Idents.ident_of_name in (* TODO java pretty ugly*)
let value = Some (static_exp param_env ovalue) in
2011-01-20 23:05:18 +01:00
let t = ty param_env otype in
mk_field ~static:true ~final:true ~value:value t name
in
match cd_l with
| [] -> []
| _ ->
2011-01-24 16:07:26 +01:00
let classe_name = "CONSTANTES" |> name_to_classe_name in
2011-01-20 23:05:18 +01:00
let fields = List.map mk_const_field cd_l in
[mk_classe ~fields:fields classe_name]
let program p =
let classes = const_dec_list p.p_consts in
let classes = type_dec_list classes p.p_types in
let p = class_def_list classes p.p_defs in
p