1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21
22-module(ic_enum_java).
23
24-include("icforms.hrl").
25-include("ic.hrl").
26-include("ic_debug.hrl").
27%%-----------------------------------------------------------------
28%% External exports
29%%-----------------------------------------------------------------
30-export([gen/3]).
31
32%%-----------------------------------------------------------------
33%% Internal exports
34%%-----------------------------------------------------------------
35-export([]).
36
37%%-----------------------------------------------------------------
38%% External functions
39%%-----------------------------------------------------------------
40
41%%-----------------------------------------------------------------
42%% Func: gen/3
43%%-----------------------------------------------------------------
44gen(G, N, X) when is_record(X, enum) ->
45    %%?PRINTDEBUG2("enum: ~p", [X]),
46    EnumName = ic_forms:get_java_id(X),
47    N2 = ["_" ++ EnumName |N],
48    ic_jbe:gen(G, N2, ic_forms:get_body(X)),
49
50    emit_enum_class(G, N, X, EnumName),
51    emit_holder_class(G, N, X, EnumName),
52    emit_helper_class(G, N, X, EnumName);
53gen(_G, _N, _X) ->
54    ok.
55
56
57%%-----------------------------------------------------------------
58%% Internal functions
59%%-----------------------------------------------------------------
60
61%%-----------------------------------------------------------------
62%% Func: emit_enum_class/4
63%%-----------------------------------------------------------------
64emit_enum_class(G, N, X, EnumName) ->
65    {Fd, _} = ic_file:open_java_file(G, N, EnumName),
66
67    EList = enum_member_name_list(G, N, X),
68    %%?PRINTDEBUG2("EList: ~p", [EList]),
69    ic_codegen:emit(Fd, ["final public class ",EnumName," {\n\n"
70
71			 "   // instance variables\n"]),
72
73    emit_enum_member_int_values_initialization(G, N, X, Fd, EList),
74    emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList),
75
76    ic_codegen:emit(Fd, ["   private int _value;\n\n"
77
78			 "   // constructors\n"
79			 "   private ",EnumName,"(int __value) {\n"
80			 "      _value = __value;\n"
81			 "   }\n\n"
82
83			 "   // methods\n"
84			 "   public int value() {\n"
85			 "      return _value;\n"
86			 "   }\n"]),
87
88    emit_enum_from_int_function(G, N, X, Fd, EnumName, EList),
89
90    ic_codegen:emit(Fd, "\n}\n"),
91    file:close(Fd).
92
93%%-----------------------------------------------------------------
94%% Func:  emit_holder_class/4
95%%-----------------------------------------------------------------
96emit_holder_class(G, N, _X, EnumName) ->
97    EName = string:concat(EnumName, "Holder"),
98    {Fd, _} = ic_file:open_java_file(G, N, EName),
99
100    ic_codegen:emit(Fd, ["final public class ",EnumName,"Holder {\n\n"
101
102			 "   // instance variables\n"
103			 "   public ",EnumName," value;\n\n"
104
105			 "   // constructors\n"
106			 "   public ",EnumName,"Holder() {}\n\n"
107
108			 "   public ",EnumName,"Holder(",EnumName," initial) {\n"
109			 "      value = initial;\n"
110			 "   }\n\n"
111
112			 "   // methods\n"
113			 "   public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception {\n"
114			 "      ",EnumName,"Helper.marshal(out, value);\n"
115			 "   }\n\n"
116
117			 "   public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n"
118			 "      value = ",EnumName,"Helper.unmarshal(in);\n"
119			 "   }\n\n"
120			 "}\n"]),
121    file:close(Fd).
122
123
124%%-----------------------------------------------------------------
125%% Func:  emit_helper_class/4
126%%-----------------------------------------------------------------
127emit_helper_class(G, N, X, EnumName) ->
128    EName = string:concat(EnumName, "Helper"),
129    WEList = enum_member_atom_list(G, N, X),
130    {Fd, _} = ic_file:open_java_file(G, N, EName),
131
132    ic_codegen:emit(Fd, ["public class ",EnumName,"Helper {\n\n"
133
134			 "   // constructors\n"
135			 "   private ",EnumName,"Helper() {}\n\n"
136
137			 "   // methods\n"
138
139			 "   public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",EnumName," _value)\n"
140			 "     throws java.lang.Exception {\n\n"]),
141
142    emit_enum_write_function(G, N, X, Fd, EnumName),
143
144    ic_codegen:emit(Fd, ["   }\n\n"
145
146			 "   public static ",EnumName," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in)\n"
147			 "     throws java.lang.Exception {\n\n"]),
148
149    emit_enum_read_function(G, N, X, Fd, EnumName),
150
151    ic_codegen:emit(Fd, "\n   }\n\n"),
152
153    emit_enum_private_member_variables(Fd, WEList),
154
155    ic_codegen:emit(Fd, ["\n   // Get integer value of enum from string\n"
156			 "   private static int _getIntFromName(String name) throws java.lang.Exception {\n"
157			 "      for(int i = 0; i < _memberCount; i++) {\n"
158			 "         if (name.equals(_members[i]))\n"
159			 "            return i;\n"
160			 "      }\n"
161			 "      throw new java.lang.Exception(\"\");\n"
162			 "   }\n\n"
163
164			 "   public static String id() {\n"
165			 "      return \"",ictk:get_IR_ID(G, N, X),"\";\n"
166			 "   }\n\n"
167
168			 "   public static String name() {\n"
169			 "      return \"",EnumName,"\";\n"
170			 "   }\n\n"]),
171
172    ic_jbe:emit_type_function(G, N, X, Fd),
173
174    ic_codegen:emit(Fd, ["   public static void insert(",?ICPACKAGE,"Any _any, ",EnumName," _this)\n"
175			 "     throws java.lang.Exception {\n\n"
176
177			 "     ",?ERLANGPACKAGE,"OtpOutputStream _os = \n"
178			 "       new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n"
179
180			 "     _any.type(type());\n"
181			 "     marshal(_os, _this);\n"
182			 "     _any.insert_Streamable(_os);\n"
183			 "   }\n\n"
184
185			 "   public static ",EnumName," extract(",?ICPACKAGE,"Any _any)\n"
186			 "     throws java.lang.Exception {\n\n"
187
188			 "     return unmarshal(_any.extract_Streamable());\n"
189			 "   }\n\n"
190
191			 "}\n"]),
192    file:close(Fd).
193
194%%-----------------------------------------------------------------
195%% Func:  emit_enum_public_instance_variables/6
196%%-----------------------------------------------------------------
197emit_enum_public_instance_variables(_G, _N, _X, _Fd, _EnumName, []) ->
198    ok;
199emit_enum_public_instance_variables(G, N, X, Fd, EnumName, [Enumerator |EList]) ->
200    ic_codegen:emit(Fd, ["   public static final ",EnumName," ",Enumerator," = new ",EnumName,"(_",Enumerator,");\n"]),
201    emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList).
202
203%%-----------------------------------------------------------------
204%% Func:  emit_enum_member_int_values_initialization/5
205%%-----------------------------------------------------------------
206emit_enum_member_int_values_initialization(G, N, X, Fd, EList) ->
207    InitString = emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, 0),
208    ic_codegen:emit(Fd, ["   public static final int ",InitString,";\n"]).
209
210
211%%-----------------------------------------------------------------
212%% Func:  emit_enum_member_int_values_initialization_1/6
213%%-----------------------------------------------------------------
214emit_enum_member_int_values_initialization_1(_G, _N, _X, _Fd, [Enumerator], Num) ->
215    "                           _" ++ Enumerator ++ " = " ++ ic_util:to_list(Num);
216emit_enum_member_int_values_initialization_1(G, N, X, Fd, [Enumerator |EList], Num) ->
217    Spaces = if
218	Num == 0 ->
219	    "";
220	true ->
221	    "                           "
222    end,
223    Spaces ++ "_" ++ Enumerator ++ " = " ++ ic_util:to_list(Num) ++ ",\n" ++
224	emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, Num + 1).
225
226%%-----------------------------------------------------------------
227%% Func:  emit_enum_from_int_function/6
228%%-----------------------------------------------------------------
229emit_enum_from_int_function(_G, _N, _X, Fd, EnumName, EList) ->
230    ic_codegen:emit(Fd,
231		    ["   public static final ",EnumName," from_int(int __value)  throws java.lang.Exception {\n"
232		     "      switch (__value) {\n"]),
233    emit_enum_from_int_function_switchbody(Fd, EList),
234    ic_codegen:emit(Fd, ["      }\n"
235			 "   }\n"]).
236
237%%-----------------------------------------------------------------
238%% Func:  emit_enum_from_int_function_switchbody/2
239%%-----------------------------------------------------------------
240emit_enum_from_int_function_switchbody(Fd, []) ->
241    ic_codegen:emit(Fd, ["         default:\n"
242			 "            throw new java.lang.Exception(\"\");\n"]);
243emit_enum_from_int_function_switchbody(Fd, [Enumerator |EList]) ->
244    ic_codegen:emit(Fd, ["         case _",Enumerator,":\n"
245			 "            return ",Enumerator,";\n"]),
246    emit_enum_from_int_function_switchbody(Fd, EList).
247
248%%-----------------------------------------------------------------
249%% Func:  emit_enum_private_member_variables/2
250%%-----------------------------------------------------------------
251emit_enum_private_member_variables(Fd, EList) ->
252    ic_codegen:emit(Fd, ["   private static final int _memberCount = ",integer_to_list(length(EList)),";\n"
253			 "   private static String[] _members  = {\n"]),
254    emit_enum_private_member_variables_1(Fd, EList),
255    ic_codegen:emit(Fd, "   };\n").
256
257%%-----------------------------------------------------------------
258%% Func:  emit_enum_private_member_variables_1/2
259%%-----------------------------------------------------------------
260emit_enum_private_member_variables_1(Fd, [Enumerator]) ->
261    ic_codegen:emit(Fd, ["      \"",Enumerator,"\"\n"]);
262emit_enum_private_member_variables_1(Fd, [Enumerator |EList]) ->
263    ic_codegen:emit(Fd, ["      \"",Enumerator,"\",\n"]),
264    emit_enum_private_member_variables_1(Fd, EList).
265
266%%-----------------------------------------------------------------
267%% Func:  emit_enum_read_function/5
268%%-----------------------------------------------------------------
269emit_enum_read_function(_G, _N, _X, Fd, EnumName) ->
270    ic_codegen:emit(Fd, ["     return ",EnumName,".from_int(_getIntFromName(_in.read_atom()));"]).
271
272%%-----------------------------------------------------------------
273%% Func:  emit_enum_write_function/5
274%%-----------------------------------------------------------------
275emit_enum_write_function(_G, _N, _X, Fd, _EnumName) ->
276    ic_codegen:emit(Fd, "     _out.write_atom(_members[_value.value()]);\n").
277
278
279%%-----------------------------------------------------------------
280%% Func:  enum_member_name_list/3
281%%
282%% Note: The names generated are checked for name coalition
283%%       with java keywords. If so the name is always prefixed
284%%       by "_"
285%%-----------------------------------------------------------------
286enum_member_name_list(_G, _N, X) ->
287    lists:map(
288      fun(Enumerator) ->
289	      ic_forms:get_java_id(Enumerator)
290      end,
291      ic_forms:get_body(X)).
292
293%%-----------------------------------------------------------------
294%% Func:  enum_member_atom_list/3
295%%
296%% Note : Similar to the emit_member_list/3 but does not
297%%        solves name coalitions with java keywords.
298%%        Used for wire encoding only
299%%-----------------------------------------------------------------
300enum_member_atom_list(_G, _N, X) ->
301    lists:map(
302      fun(Enumerator) ->
303	      ic_forms:get_id2(Enumerator)
304      end,
305      ic_forms:get_body(X)).
306
307
308
309
310
311
312
313
314