%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(ic_enum_java).
-include("icforms.hrl").
-include("ic.hrl").
-include("ic_debug.hrl").
%%-----------------------------------------------------------------
%% External exports
%%-----------------------------------------------------------------
-export([gen/3]).
%%-----------------------------------------------------------------
%% Internal exports
%%-----------------------------------------------------------------
-export([]).
%%-----------------------------------------------------------------
%% External functions
%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
%% Func: gen/3
%%-----------------------------------------------------------------
gen(G, N, X) when is_record(X, enum) ->
%%?PRINTDEBUG2("enum: ~p", [X]),
EnumName = ic_forms:get_java_id(X),
N2 = ["_" ++ EnumName |N],
ic_jbe:gen(G, N2, ic_forms:get_body(X)),
emit_enum_class(G, N, X, EnumName),
emit_holder_class(G, N, X, EnumName),
emit_helper_class(G, N, X, EnumName);
gen(_G, _N, _X) ->
ok.
%%-----------------------------------------------------------------
%% Internal functions
%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
%% Func: emit_enum_class/4
%%-----------------------------------------------------------------
emit_enum_class(G, N, X, EnumName) ->
{Fd, _} = ic_file:open_java_file(G, N, EnumName),
EList = enum_member_name_list(G, N, X),
%%?PRINTDEBUG2("EList: ~p", [EList]),
ic_codegen:emit(Fd, ["final public class ",EnumName," {\n\n"
" // instance variables\n"]),
emit_enum_member_int_values_initialization(G, N, X, Fd, EList),
emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList),
ic_codegen:emit(Fd, [" private int _value;\n\n"
" // constructors\n"
" private ",EnumName,"(int __value) {\n"
" _value = __value;\n"
" }\n\n"
" // methods\n"
" public int value() {\n"
" return _value;\n"
" }\n"]),
emit_enum_from_int_function(G, N, X, Fd, EnumName, EList),
ic_codegen:emit(Fd, "\n}\n"),
file:close(Fd).
%%-----------------------------------------------------------------
%% Func: emit_holder_class/4
%%-----------------------------------------------------------------
emit_holder_class(G, N, _X, EnumName) ->
EName = string:concat(EnumName, "Holder"),
{Fd, _} = ic_file:open_java_file(G, N, EName),
ic_codegen:emit(Fd, ["final public class ",EnumName,"Holder {\n\n"
" // instance variables\n"
" public ",EnumName," value;\n\n"
" // constructors\n"
" public ",EnumName,"Holder() {}\n\n"
" public ",EnumName,"Holder(",EnumName," initial) {\n"
" value = initial;\n"
" }\n\n"
" // methods\n"
" public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception {\n"
" ",EnumName,"Helper.marshal(out, value);\n"
" }\n\n"
" public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n"
" value = ",EnumName,"Helper.unmarshal(in);\n"
" }\n\n"
"}\n"]),
file:close(Fd).
%%-----------------------------------------------------------------
%% Func: emit_helper_class/4
%%-----------------------------------------------------------------
emit_helper_class(G, N, X, EnumName) ->
EName = string:concat(EnumName, "Helper"),
WEList = enum_member_atom_list(G, N, X),
{Fd, _} = ic_file:open_java_file(G, N, EName),
ic_codegen:emit(Fd, ["public class ",EnumName,"Helper {\n\n"
" // constructors\n"
" private ",EnumName,"Helper() {}\n\n"
" // methods\n"
" public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",EnumName," _value)\n"
" throws java.lang.Exception {\n\n"]),
emit_enum_write_function(G, N, X, Fd, EnumName),
ic_codegen:emit(Fd, [" }\n\n"
" public static ",EnumName," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in)\n"
" throws java.lang.Exception {\n\n"]),
emit_enum_read_function(G, N, X, Fd, EnumName),
ic_codegen:emit(Fd, "\n }\n\n"),
emit_enum_private_member_variables(Fd, WEList),
ic_codegen:emit(Fd, ["\n // Get integer value of enum from string\n"
" private static int _getIntFromName(String name) throws java.lang.Exception {\n"
" for(int i = 0; i < _memberCount; i++) {\n"
" if (name.equals(_members[i]))\n"
" return i;\n"
" }\n"
" throw new java.lang.Exception(\"\");\n"
" }\n\n"
" public static String id() {\n"
" return \"",ictk:get_IR_ID(G, N, X),"\";\n"
" }\n\n"
" public static String name() {\n"
" return \"",EnumName,"\";\n"
" }\n\n"]),
ic_jbe:emit_type_function(G, N, X, Fd),
ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",EnumName," _this)\n"
" throws java.lang.Exception {\n\n"
" ",?ERLANGPACKAGE,"OtpOutputStream _os = \n"
" new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n"
" _any.type(type());\n"
" marshal(_os, _this);\n"
" _any.insert_Streamable(_os);\n"
" }\n\n"
" public static ",EnumName," extract(",?ICPACKAGE,"Any _any)\n"
" throws java.lang.Exception {\n\n"
" return unmarshal(_any.extract_Streamable());\n"
" }\n\n"
"}\n"]),
file:close(Fd).
%%-----------------------------------------------------------------
%% Func: emit_enum_public_instance_variables/6
%%-----------------------------------------------------------------
emit_enum_public_instance_variables(_G, _N, _X, _Fd, _EnumName, []) ->
ok;
emit_enum_public_instance_variables(G, N, X, Fd, EnumName, [Enumerator |EList]) ->
ic_codegen:emit(Fd, [" public static final ",EnumName," ",Enumerator," = new ",EnumName,"(_",Enumerator,");\n"]),
emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList).
%%-----------------------------------------------------------------
%% Func: emit_enum_member_int_values_initialization/5
%%-----------------------------------------------------------------
emit_enum_member_int_values_initialization(G, N, X, Fd, EList) ->
InitString = emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, 0),
ic_codegen:emit(Fd, [" public static final int ",InitString,";\n"]).
%%-----------------------------------------------------------------
%% Func: emit_enum_member_int_values_initialization_1/6
%%-----------------------------------------------------------------
emit_enum_member_int_values_initialization_1(_G, _N, _X, _Fd, [Enumerator], Num) ->
" _" ++ Enumerator ++ " = " ++ ic_util:to_list(Num);
emit_enum_member_int_values_initialization_1(G, N, X, Fd, [Enumerator |EList], Num) ->
Spaces = if
Num == 0 ->
"";
true ->
" "
end,
Spaces ++ "_" ++ Enumerator ++ " = " ++ ic_util:to_list(Num) ++ ",\n" ++
emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, Num + 1).
%%-----------------------------------------------------------------
%% Func: emit_enum_from_int_function/6
%%-----------------------------------------------------------------
emit_enum_from_int_function(_G, _N, _X, Fd, EnumName, EList) ->
ic_codegen:emit(Fd,
[" public static final ",EnumName," from_int(int __value) throws java.lang.Exception {\n"
" switch (__value) {\n"]),
emit_enum_from_int_function_switchbody(Fd, EList),
ic_codegen:emit(Fd, [" }\n"
" }\n"]).
%%-----------------------------------------------------------------
%% Func: emit_enum_from_int_function_switchbody/2
%%-----------------------------------------------------------------
emit_enum_from_int_function_switchbody(Fd, []) ->
ic_codegen:emit(Fd, [" default:\n"
" throw new java.lang.Exception(\"\");\n"]);
emit_enum_from_int_function_switchbody(Fd, [Enumerator |EList]) ->
ic_codegen:emit(Fd, [" case _",Enumerator,":\n"
" return ",Enumerator,";\n"]),
emit_enum_from_int_function_switchbody(Fd, EList).
%%-----------------------------------------------------------------
%% Func: emit_enum_private_member_variables/2
%%-----------------------------------------------------------------
emit_enum_private_member_variables(Fd, EList) ->
ic_codegen:emit(Fd, [" private static final int _memberCount = ",integer_to_list(length(EList)),";\n"
" private static String[] _members = {\n"]),
emit_enum_private_member_variables_1(Fd, EList),
ic_codegen:emit(Fd, " };\n").
%%-----------------------------------------------------------------
%% Func: emit_enum_private_member_variables_1/2
%%-----------------------------------------------------------------
emit_enum_private_member_variables_1(Fd, [Enumerator]) ->
ic_codegen:emit(Fd, [" \"",Enumerator,"\"\n"]);
emit_enum_private_member_variables_1(Fd, [Enumerator |EList]) ->
ic_codegen:emit(Fd, [" \"",Enumerator,"\",\n"]),
emit_enum_private_member_variables_1(Fd, EList).
%%-----------------------------------------------------------------
%% Func: emit_enum_read_function/5
%%-----------------------------------------------------------------
emit_enum_read_function(_G, _N, _X, Fd, EnumName) ->
ic_codegen:emit(Fd, [" return ",EnumName,".from_int(_getIntFromName(_in.read_atom()));"]).
%%-----------------------------------------------------------------
%% Func: emit_enum_write_function/5
%%-----------------------------------------------------------------
emit_enum_write_function(_G, _N, _X, Fd, _EnumName) ->
ic_codegen:emit(Fd, " _out.write_atom(_members[_value.value()]);\n").
%%-----------------------------------------------------------------
%% Func: enum_member_name_list/3
%%
%% Note: The names generated are checked for name coalition
%% with java keywords. If so the name is always prefixed
%% by "_"
%%-----------------------------------------------------------------
enum_member_name_list(_G, _N, X) ->
lists:map(
fun(Enumerator) ->
ic_forms:get_java_id(Enumerator)
end,
ic_forms:get_body(X)).
%%-----------------------------------------------------------------
%% Func: enum_member_atom_list/3
%%
%% Note : Similar to the emit_member_list/3 but does not
%% solves name coalitions with java keywords.
%% Used for wire encoding only
%%-----------------------------------------------------------------
enum_member_atom_list(_G, _N, X) ->
lists:map(
fun(Enumerator) ->
ic_forms:get_id2(Enumerator)
end,
ic_forms:get_body(X)).