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
23-module(ic_union_java).
24
25-include("icforms.hrl").
26-include("ic.hrl").
27-include("ic_debug.hrl").
28%%-----------------------------------------------------------------
29%% External exports
30%%-----------------------------------------------------------------
31-export([gen/3]).
32
33%%-----------------------------------------------------------------
34%% Internal exports
35%%-----------------------------------------------------------------
36-export([]).
37
38%%-----------------------------------------------------------------
39%% External functions
40%%-----------------------------------------------------------------
41
42%%-----------------------------------------------------------------
43%% Func: gen/3
44%%-----------------------------------------------------------------
45gen(G, N, X) when is_record(X, union) ->
46
47    %% Create a TK value if not existed
48    %% Should be integrated in fetchTk
49    %% instead
50    NewX = case ic_forms:get_tk(X) of
51	       undefined ->
52		   S = ic_genobj:tktab(G),
53		   Tk = ictype:tk(G, S, N, X),
54		   #union{ id = X#union.id,
55			   type = X#union.type,
56			   body = X#union.body,
57			   tk = Tk };
58	       _Tk ->
59		   X
60	   end,
61
62    UnionName = ic_forms:get_java_id(NewX),
63    WiredUnionName = ic_forms:get_id2(NewX),
64    N2 = [UnionName ++ "Package"|N],
65    %%?PRINTDEBUG2("Recursive call over type ~p",
66    %%		 [[ic_forms:get_type(NewX)]]),
67    ic_jbe:gen(G, N, [ic_forms:get_type(NewX)]),
68    %%?PRINTDEBUG2("Recursive call over body: ~p",
69    %%		 [ic_forms:get_body(NewX)]),
70    ic_jbe:gen(G, N2, ic_forms:get_body(NewX)),
71
72    emit_union_class(G, N, NewX, UnionName),
73    emit_holder_class(G, N, NewX, UnionName),
74    emit_helper_class(G, N, NewX, UnionName, WiredUnionName);
75gen(_G, _N, _X) ->
76    ok.
77
78
79%%-----------------------------------------------------------------
80%% Internal functions
81%%-----------------------------------------------------------------
82
83%%-----------------------------------------------------------------
84%% Func: emit_union_class/4
85%%-----------------------------------------------------------------
86emit_union_class(G, N, X, UnionName) ->
87    {Fd, _} = ic_file:open_java_file(G, N, UnionName),
88
89    DiscrType = ic_java_type:getType(G, [UnionName ++ "Package"|N],
90				  ic_forms:get_type(X)),
91
92    MList = union_member_list(G, N, X, DiscrType),
93
94    ic_codegen:emit(Fd, "final public class ~s {\n",[UnionName]),
95
96    ic_codegen:emit(Fd, "   // instance variables\n", []),
97    ic_codegen:emit(Fd, "   private boolean _initialized;\n", []),
98    ic_codegen:emit(Fd, "   private ~s _discriminator;\n", [DiscrType]),
99    ic_codegen:emit(Fd, "   private java.lang.Object _value;\n", []),
100
101    {tk_union,_, _,DiscrTk, _, _} = ic_forms:get_tk(X),
102
103    DV = get_default_val(G, [UnionName |N], DiscrType, DiscrTk, MList),
104
105    case DV of
106	none -> %% all values in case
107	    ok;
108	_ ->
109	    ic_codegen:emit(Fd, "   private ~s _default =  ~s;\n",
110			    [DiscrType, DV])
111    end,
112
113    ic_codegen:nl(Fd),
114    ic_codegen:emit(Fd, "   // constructors\n", []),
115
116    ic_codegen:emit(Fd, "   public ~s() {\n", [UnionName]),
117    ic_codegen:emit(Fd, "      _initialized = false;\n", []),
118    ic_codegen:emit(Fd, "      _value = null;\n", []),
119    ic_codegen:emit(Fd, "   }\n", []),
120    ic_codegen:nl(Fd),
121
122    ic_codegen:emit(Fd, "   // discriminator access\n", []),
123
124    ic_codegen:emit(Fd, "   public ~s discriminator() "
125		    "throws java.lang.Exception {\n", [DiscrType]),
126    ic_codegen:emit(Fd, "      if (!_initialized) {\n", []),
127    ic_codegen:emit(Fd, "         throw new java.lang.Exception(\"\");\n",[]),
128    ic_codegen:emit(Fd, "      }\n", []),
129    ic_codegen:emit(Fd, "      return _discriminator;\n", []),
130    ic_codegen:emit(Fd, "   }\n", []),
131    ic_codegen:nl(Fd),
132
133    emit_union_members_functions(G, [UnionName ++ "Package"|N], X,
134				 Fd, UnionName, DiscrType, MList, MList),
135    ic_codegen:nl(Fd),
136
137    ic_codegen:emit(Fd, "}\n", []),
138    file:close(Fd).
139
140%%-----------------------------------------------------------------
141%% Func:  emit_holder_class/4
142%%-----------------------------------------------------------------
143emit_holder_class(G, N, _X, UnionName) ->
144    UName = string:concat(UnionName, "Holder"),
145    {Fd, _} = ic_file:open_java_file(G, N, UName),
146
147    ic_codegen:emit(Fd, "final public class ~sHolder {\n",[UnionName]),
148
149    ic_codegen:emit(Fd, "   // instance variables\n"),
150    ic_codegen:emit(Fd, "   public ~s value;\n", [UnionName]),
151    ic_codegen:nl(Fd),
152
153    ic_codegen:emit(Fd, "   // constructors\n"),
154    ic_codegen:emit(Fd, "   public ~sHolder() {}\n", [UnionName]),
155    ic_codegen:emit(Fd, "   public ~sHolder(~s initial) {\n",
156		    [UnionName, UnionName]),
157    ic_codegen:emit(Fd, "      value = initial;\n"),
158    ic_codegen:emit(Fd, "   }\n"),
159    ic_codegen:nl(Fd),
160
161    ic_codegen:emit(Fd, "   // methods\n"),
162
163    ic_codegen:emit(Fd, "   public void _marshal(~sOtpOutputStream out) throws java.lang.Exception {\n",
164		    [?ERLANGPACKAGE]),
165    ic_codegen:emit(Fd, "      ~sHelper.marshal(out, value);\n", [UnionName]),
166    ic_codegen:emit(Fd, "   }\n\n"),
167
168    ic_codegen:emit(Fd, "   public void _unmarshal(~sOtpInputStream in) throws java.lang.Exception {\n",
169		    [?ERLANGPACKAGE]),
170    ic_codegen:emit(Fd, "      value = ~sHelper.unmarshal(in);\n", [UnionName]),
171    ic_codegen:emit(Fd, "   }\n\n"),
172
173    ic_codegen:emit(Fd, "}\n"),
174    file:close(Fd).
175
176
177%%-----------------------------------------------------------------
178%% Func:  emit_helper_class/4
179%%-----------------------------------------------------------------
180emit_helper_class(G, N, X, UnionName, WiredUnionName) ->
181    UName = string:concat(UnionName, "Helper"),
182    {Fd, _} = ic_file:open_java_file(G, N, UName),
183
184    DiscrType = ic_java_type:getType(G, [ UnionName ++ "Package" |N],
185				  ic_forms:get_type(X)),
186
187    ic_codegen:emit(Fd, "public class ~sHelper {\n",[UnionName]),
188
189    ic_codegen:emit(Fd, "   // constructors\n", []),
190    ic_codegen:emit(Fd, "   private ~sHelper() {}\n", [UnionName]),
191    ic_codegen:nl(Fd),
192
193    ic_codegen:emit(Fd, "   // methods\n", []),
194    MList = union_member_list(G, N, X, DiscrType),
195
196    ic_codegen:emit(Fd, "   public static void marshal(~sOtpOutputStream _out, ~s _value)\n",
197		    [?ERLANGPACKAGE, UnionName]),
198    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
199    emit_union_marshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList),
200    ic_codegen:emit(Fd, "   }\n\n"),
201
202    ic_codegen:emit(Fd, "   public static ~s unmarshal(~sOtpInputStream _in)\n",
203		    [UnionName, ?ERLANGPACKAGE]),
204    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
205    emit_union_unmarshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList),
206    ic_codegen:emit(Fd, "   }\n\n"),
207
208    ic_codegen:emit(Fd, "   public static String id() {\n"),
209    ic_codegen:emit(Fd, "      return ~p;\n",[ictk:get_IR_ID(G, N, X)]),
210    ic_codegen:emit(Fd, "   }\n\n"),
211
212    ic_codegen:emit(Fd, "   public static String name() {\n"),
213    ic_codegen:emit(Fd, "      return ~p;\n",[UnionName]),
214    ic_codegen:emit(Fd, "   }\n\n"),
215
216    ic_jbe:emit_type_function(G, N, X, Fd),
217
218
219    ic_codegen:emit(Fd, "   public static void insert(~sAny _any, ~s _this)\n",
220		    [?ICPACKAGE,UnionName]),
221    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
222
223    ic_codegen:emit(Fd, "     ~sOtpOutputStream _os = \n",[?ERLANGPACKAGE]),
224    ic_codegen:emit(Fd, "       new ~sOtpOutputStream();\n\n",[?ERLANGPACKAGE]),
225
226    ic_codegen:emit(Fd, "     _any.type(type());\n"),
227    ic_codegen:emit(Fd, "     marshal(_os, _this);\n"),
228    ic_codegen:emit(Fd, "     _any.insert_Streamable(_os);\n"),
229    ic_codegen:emit(Fd, "   }\n\n"),
230
231    ic_codegen:emit(Fd, "   public static ~s extract(~sAny _any)\n",
232		    [UnionName,?ICPACKAGE]),
233    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
234
235    ic_codegen:emit(Fd, "     return unmarshal(_any.extract_Streamable());\n"),
236    ic_codegen:emit(Fd, "   }\n\n"),
237
238    ic_codegen:emit(Fd, "   public static int discriminatorAsInt(~s _discriminator)\n",
239		    [DiscrType]),
240    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n"),
241    emit_discriminator_as_int(G, N, ic_forms:get_type(X), Fd),
242    ic_codegen:emit(Fd, "   }\n\n"),
243
244    ic_codegen:emit(Fd, "}\n"),
245    file:close(Fd).
246
247%%-----------------------------------------------------------------
248%% Func:  emit_union_members_functions/7
249%%-----------------------------------------------------------------
250emit_union_members_functions(_, _, _, _, _, _, [], _) ->
251    ok;
252emit_union_members_functions(G, N, X, Fd, UnionName, DiscrType,
253			     [{Label, Case, TypeDef, Id, Ls} | MList], MListTot) ->
254
255    CaseId = Case#case_dcl.id, %% Maybe Array
256    CaseType = Case#case_dcl.type, %% Maybe Sequence
257
258    Type = if element(1,CaseId) == array ->
259		   ic_java_type:getType(G, N, TypeDef) ++
260		       ic_java_type:getdim(CaseId#array.size);
261	      true ->
262		   ic_java_type:getType(G, N, TypeDef)
263	   end,
264
265    HolderType =
266	if element(1,CaseId) == array ->
267		ic_java_type:getHolderType(G, N, CaseId);
268	   true ->
269		if element(1,CaseType) == sequence ->
270			ic_util:to_dot(G,[Id|N]) ++"Holder";
271		   true ->
272			ic_java_type:getHolderType(G, N, TypeDef)
273		end
274	end,
275
276    %%
277    %% Set method
278    %%
279    ic_codegen:emit(Fd, "   // ~s access and set functions\n",[Id]),
280    ic_codegen:emit(Fd, "   public void ~s(~s value) "
281		    "throws java.lang.Exception {\n",
282		    [Id, Type]),
283    ic_codegen:emit(Fd, "      _initialized = true;\n", []),
284    case Label of
285	"default" ->
286	    ic_codegen:emit(Fd, "      _discriminator = (~s) _default;\n",
287			    [DiscrType]);
288	_ ->
289	    case ic_java_type:isBasicType(G, N, ic_forms:get_type(X)) of
290		true ->
291		    ic_codegen:emit(Fd, "      _discriminator = (~s) "
292				    "~s;\n",
293				    [DiscrType, Label]);
294		_ ->
295		    ic_codegen:emit(Fd, "      _discriminator = (~s) "
296				    "~s.~s;\n",
297				    [DiscrType, DiscrType, Label])
298	    end
299    end,
300    ic_codegen:emit(Fd, "      _value = new ~s(value);\n",
301		    [HolderType]),
302    ic_codegen:emit(Fd, "   }\n", []),
303
304    %%
305    %% Check this entry has more than one label and the generate an extra set method.
306    %%
307    case Ls of
308	[] ->
309	    ok;
310	_ ->
311	    ic_codegen:emit(Fd, "   public void ~s(~s discriminator, ~s value) "
312			    "throws java.lang.Exception {\n",
313			    [Id, DiscrType, Type]),
314	    ic_codegen:emit(Fd, "      _initialized = true;\n", []),
315	    ic_codegen:emit(Fd, "      _discriminator = (~s) discriminator;\n",
316				    [DiscrType]),
317	    ic_codegen:emit(Fd, "      _value = new ~s(value);\n",
318			    [HolderType]),
319	    ic_codegen:emit(Fd, "   }\n", [])
320    end,
321
322    %%
323    %% Get method
324    %%
325    ic_codegen:emit(Fd, "   public ~s ~s() throws java.lang.Exception {\n",
326		    [Type, Id]),
327    ic_codegen:emit(Fd, "      if (!_initialized) {\n", []),
328    ic_codegen:emit(Fd, "         throw new java.lang.Exception(\"\");\n",[]),
329    ic_codegen:emit(Fd, "      }\n", []),
330    ic_codegen:emit(Fd, "      switch (~sHelper.discriminatorAsInt"
331		    "(discriminator())) {\n",
332		    [UnionName]),
333    if
334	Label == "default" ->
335	    ic_codegen:emit(Fd, "         default:\n", []),
336	    ic_codegen:emit(Fd, "            break;\n", []),
337	    emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType,
338						 MListTot),
339	    ic_codegen:emit(Fd, "            throw new java.lang.Exception(\"\");\n", []);
340	true ->
341	    ic_codegen:emit(Fd, "         case ~s:\n",
342			    [get_case_as_int(G, N, ic_forms:get_type(X),
343					     DiscrType, Label)]),
344	    ic_codegen:emit(Fd, "            break;\n", []),
345	    ic_codegen:emit(Fd, "         default:\n", []),
346	    ic_codegen:emit(Fd, "            throw new java.lang.Exception(\"\");\n", [])
347    end,
348    ic_codegen:emit(Fd, "      }\n", []),
349
350    ic_codegen:emit(Fd, "      return ((~s) _value).value;\n",
351		    [HolderType]),
352    ic_codegen:emit(Fd, "   }\n", []),
353    ic_codegen:nl(Fd),
354    emit_union_members_functions(G, N, X, Fd, UnionName, DiscrType, MList,
355				 MListTot).
356
357
358%%-----------------------------------------------------------------
359%% Func:  emit_default_access_fun_switch_cases/6
360%%-----------------------------------------------------------------
361emit_default_access_fun_switch_cases(_G, _N, _X, _Fd, _DiscrType, []) ->
362    ok;
363emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType,
364				     [{"default", _, _, _, _} |MList]) ->
365    emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, MList);
366emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType,
367				     [{Label, _Case, _TypeDef, _Id, _} | MList]) ->
368    ic_codegen:emit(Fd, "         case ~s:\n",
369		    [get_case_as_int(G, N, ic_forms:get_type(X),
370				     DiscrType, Label)]),
371    emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, MList).
372
373
374
375%%-----------------------------------------------------------------
376%% Func:  emit_union_unmarshal_function/5
377%%-----------------------------------------------------------------
378emit_union_unmarshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList) ->
379    DiscrTypeForm = ic_forms:get_type(X),
380    DiscrType = ic_java_type:getType(G, [UnionName ++ "Package"|N],
381				  DiscrTypeForm),
382
383    ic_codegen:emit(Fd, "     _in.read_tuple_head();\n\n"),
384
385    ic_codegen:emit(Fd, "     if ((_in.read_atom()).compareTo(~p) != 0)\n",
386	 	    [ic_util:to_undersc([WiredUnionName|N])]),
387    ic_codegen:emit(Fd, "       throw new java.lang.Exception(\"\");\n\n",[]),
388
389    ic_codegen:emit(Fd, "     ~s _value = new ~s();\n", [UnionName, UnionName]),
390
391    %% Decode discriminator
392    case ic_java_type:isBasicType(G, N, DiscrTypeForm) of
393	true ->
394	    ic_codegen:emit(Fd, "     ~s _discriminator = _in~s;\n\n",
395			    [DiscrType,
396			     ic_java_type:unMarshalFun(G, N, X, DiscrTypeForm)]);
397	_ ->
398	    ic_codegen:emit(Fd, "     ~s _discriminator = ~s.unmarshal(_in);\n\n",
399			    [DiscrType,ic_java_type:getUnmarshalType(G, N, X, DiscrTypeForm)])
400    end,
401
402    ic_codegen:emit(Fd, "     switch (~sHelper.discriminatorAsInt(_discriminator)) {\n",
403		    [UnionName]),
404
405    emit_union_unmarshal_function_loop(G, [UnionName ++ "Package"|N], X,
406				       Fd, DiscrType, MList),
407
408    ic_codegen:emit(Fd, "     }\n\n"),
409
410    ic_codegen:emit(Fd, "     return _value;\n").
411
412%%-----------------------------------------------------------------
413%% Func:  emit_union_unmarshal_function_loop/6
414%%-----------------------------------------------------------------
415emit_union_unmarshal_function_loop(_, _, _, _, _, []) ->
416    ok;
417emit_union_unmarshal_function_loop(G, N, X, Fd, DiscrType,
418			       [{Label, Case, Type, Id, Ls} |MList]) ->
419    case Label of
420	"default" ->
421	    ic_codegen:emit(Fd, "     default:\n");
422	_ ->
423	    ic_codegen:emit(Fd, "     case ~s:\n",
424			    [get_case_as_int(G, N, ic_forms:get_type(X),
425					     DiscrType, Label)])
426    end,
427
428    gen_multiple_cases(G, N, X, Fd, DiscrType, Ls),
429
430    CaseId = Case#case_dcl.id, %% Maybe Array
431    CaseType = Case#case_dcl.type, %% Maybe Sequence
432
433    case element(1,CaseId) of
434	array ->
435	    ic_codegen:emit(Fd, "       _value.~s(~s.unmarshal(_in));\n",
436			    [Id,
437			     ic_java_type:getUnmarshalType(G, N, Case, CaseId)]);
438
439	_ ->
440	    case element(1, CaseType) of
441		sequence ->
442		    ic_codegen:emit(Fd, "       _value.~s(~s.unmarshal(_in));\n",
443				    [Id,
444				     ic_java_type:getUnmarshalType(G, N, Case, CaseType)]);
445		_ ->
446		    case ic_java_type:isBasicType(G, N, CaseType) of
447			true ->
448			    ic_codegen:emit(Fd, "       _value.~s(_in~s);\n",
449					    [Id,
450					     ic_java_type:unMarshalFun(G, N, X, Type)]);
451			false ->
452			    ic_codegen:emit(Fd, "       _value.~s(~s.unmarshal(_in));\n",
453					    [Id,
454					     ic_java_type:getUnmarshalType(G, N, X, Type)])
455		    end
456	    end
457    end,
458
459    ic_codegen:emit(Fd, "       break;\n", []),
460    emit_union_unmarshal_function_loop(G, N, X, Fd, DiscrType, MList).
461
462
463
464
465
466%%-----------------------------------------------------------------
467%% Func:  emit_union_marshal_function/6
468%%-----------------------------------------------------------------
469emit_union_marshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList) ->
470
471    DiscrTypeForm = ic_forms:get_type(X),
472    DiscrType = ic_java_type:getType(G, [UnionName ++ "Package" |N],
473				  DiscrTypeForm),
474
475    ic_codegen:emit(Fd, "     _out.write_tuple_head(3);\n"),
476    ic_codegen:emit(Fd, "     _out.write_atom(~p);\n",
477		    [ic_util:to_undersc([WiredUnionName|N])]),
478
479    case ic_java_type:isBasicType(G, N, DiscrTypeForm) of
480	true ->
481	    ic_codegen:emit(Fd, "     _out~s(_value.discriminator());\n\n",
482			    [ic_java_type:marshalFun(G, N, X, DiscrTypeForm)]);
483	false ->
484	    ic_codegen:emit(Fd, "     ~s(_out, _value.discriminator());\n\n",
485			    [ic_java_type:marshalFun(G, N, X, DiscrTypeForm)])
486    end,
487
488    ic_codegen:emit(Fd, "     switch(~sHelper.discriminatorAsInt(_value.discriminator())) {\n",
489		    [UnionName]),
490
491    emit_union_marshal_function_loop(G,
492				     [ UnionName ++ "Package"|N],
493				     X,
494				     Fd,
495				     DiscrType,
496				     MList),
497
498    ic_codegen:emit(Fd, "     }\n\n", []).
499
500
501%%-----------------------------------------------------------------
502%% Func:  emit_union_marshal_function_loop/
503%%-----------------------------------------------------------------
504emit_union_marshal_function_loop(_, _, _, _, _, []) ->
505    ok;
506emit_union_marshal_function_loop(G, N, X, Fd, DiscrType,
507			       [{Label, Case, Type, Id, Ls} |MList]) ->
508    case Label of
509	"default" ->
510	    ic_codegen:emit(Fd, "     default:\n",
511			    []);
512	_ ->
513	    ic_codegen:emit(Fd, "     case ~s:\n",
514			    [get_case_as_int(G, N, ic_forms:get_type(X),
515					     DiscrType, Label)])
516    end,
517
518    gen_multiple_cases(G, N, X, Fd, DiscrType, Ls),
519
520
521    CaseId = Case#case_dcl.id, %% Maybe Array
522    CaseType = Case#case_dcl.type, %% Maybe Sequence
523
524    case element(1,CaseId) of
525	array ->
526	    ic_codegen:emit(Fd, "       ~s(_out, _value.~s());\n",
527			    [ic_java_type:marshalFun(G, N, Case, CaseId),
528			     Id]);
529	_ ->
530	    case element(1, CaseType) of
531		sequence ->
532		    ic_codegen:emit(Fd, "       ~s.marshal(_out, _value.~s());\n",
533				    [ic_util:to_dot(G,[Id|N]) ++ "Helper",
534				     Id]);
535		_ ->
536		    case ic_java_type:isBasicType(G, N, CaseType) of
537			true ->
538			    ic_codegen:emit(Fd, "       _out~s(_value.~s());\n",
539					    [ic_java_type:marshalFun(G, N, X, Type),
540					     Id]);
541			false ->
542			    ic_codegen:emit(Fd, "       ~s(_out, _value.~s());\n",
543					    [ic_java_type:marshalFun(G, N, X, Type),
544					     Id])
545		    end
546	    end
547    end,
548
549    ic_codegen:emit(Fd, "       break;\n", []),
550    emit_union_marshal_function_loop(G, N, X, Fd, DiscrType, MList).
551
552
553
554gen_multiple_cases(_G, _N, _X, _Fd, _DiscrType, []) ->
555    ok;
556gen_multiple_cases(G, N, X, Fd, DiscrType, [Label |Ls]) ->
557    ic_codegen:emit(Fd, "        case ~s:\n",
558		    [get_case_as_int(G, N, ic_forms:get_type(X),
559				     DiscrType, getLabel(DiscrType, Label))]),
560    gen_multiple_cases(G, N, X, Fd, DiscrType, Ls).
561
562
563%%-----------------------------------------------------------------
564%% Func:  union_member_list/3
565%%-----------------------------------------------------------------
566union_member_list(G, N, X, DiscrType) ->
567    M = lists:map(
568	  fun(Case) ->
569		  {Label, LabelList} = case  check_default(ic_forms:get_idlist(Case)) of
570					   {{default, C}, List}  ->
571					       {{default, C}, List};
572					   {L, []} ->
573					       {L, []};
574					   {_, [L |Ls]} ->
575					       {L, Ls}
576				       end,
577
578		  CName = ic_forms:get_java_id(Case),
579		  CId = Case#case_dcl.id,
580		  CType = Case#case_dcl.type,
581
582		  if element(1,CId) == array ->
583			  N2 = [ic_forms:get_id2(X) ++ "Package" |N],
584			  ic_array_java:gen(G, N2, Case, CId);
585		     true ->
586			  if element(1,Case#case_dcl.type) == sequence ->
587				  N2 = [ic_forms:get_id2(X) ++ "Package" |N],
588				  ic_sequence_java:gen(G, N2, CType, CName);
589			     true ->
590				  ok
591			  end
592		  end,
593
594		  {getLabel(DiscrType, Label),
595		   Case,
596		   ic_forms:get_type(Case),
597		   CName,
598		   LabelList}
599	  end,
600	  ic_forms:get_body(X)),
601    lists:flatten(M).
602
603check_default([]) ->
604    {false, []};
605check_default([{default, X} |Ls]) ->
606    {{default, X}, Ls};
607check_default([L]) ->
608    {false, [L]};
609check_default([L |Ls]) ->
610    {X, Y} = check_default(Ls),
611    {X, [L | Y]}.
612
613getLabel(_, {'<integer_literal>', _, N}) ->
614    N;
615getLabel(_, {'<character_literal>', _, N}) ->
616    "'" ++ N ++ "'";
617getLabel(_, {'<wcharacter_literal>', _, N}) ->
618    "'" ++ N ++ "'";
619getLabel(_, {'TRUE',_}) ->
620    "true";
621getLabel(_, {'FALSE',_}) ->
622    "true";
623getLabel(_, {default, _}) ->
624    "default";
625getLabel(_DiscrType, X) -> %%DiscrType ++ "." ++
626    ic_util:to_dot(ic_forms:get_id(X)).
627
628get_default_val(G, N, _, tk_short, MList) ->
629    integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
630get_default_val(G, N, _, tk_long, MList) ->
631    integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
632get_default_val(G, N, _, tk_ushort, MList) ->
633    integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
634get_default_val(G, N, _, tk_ulong, MList) ->
635    integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
636get_default_val(G, N, _, tk_char, MList) ->
637    char_default_val(G, N, $a, lists:map(fun({V, _, _, _, _}) -> V end, MList));
638get_default_val(G, N, _, tk_boolean, MList) ->
639    boolean_default_val(G, N, lists:map(fun({V, _, _, _, _}) -> V end, MList));
640get_default_val(G, N, DiscrType, {tk_enum, _, _, Values}, MList) ->
641    enum_default_val(G, N, DiscrType, Values, MList).
642
643integer_default_val(G, N, Num, MList) ->
644    Num2 = integer_to_list(Num),
645    case lists:member(Num2, MList) of
646	true ->
647	    integer_default_val(G, N, Num + 1, MList);
648	false ->
649	    Num2
650    end.
651
652char_default_val(G, N, CharNum, MList) ->
653    Str = "'",
654    CharNum2 = Str ++ [CharNum | Str],
655    case lists:member(CharNum2, MList) of
656	true ->
657	    char_default_val(G, N, CharNum + 1, MList);
658	false ->
659	    CharNum2
660    end.
661
662boolean_default_val(G, N, MList) ->
663    if
664	length(MList) > 2 ->
665	    ic_error:error(G, {plain_error_string,
666			       lists:flatten(
667				 io_lib:format("Default value found while all values have label on ~s",
668					       [ic_util:to_colon(N)]))}),
669	    none;
670	true ->
671	    case MList of
672		["true"] ->
673		    "false";
674		["false"] ->
675		    "true";
676		["default","true"] ->
677		    "false";
678		["true","default"] ->
679		    "false";
680		["default","false"] ->
681		    "true";
682		["false","default"] ->
683		    "true";
684		_ ->
685		    none
686	    end
687    end.
688
689
690
691
692enum_default_val(G, N, DiscrType, Values, Mlist) ->
693
694    VLen = length(Values),
695    MLen = length(Mlist),
696
697    case MLen > VLen of
698	true ->
699	    ic_error:error(G, {plain_error_string,
700			       lists:flatten(
701				 io_lib:format("Default value found while all values have label on ~s",
702					       [ic_util:to_colon(N)]))}),
703	    none;
704	false ->
705	    enum_default_val_loop(G, N, DiscrType, Values, Mlist)
706    end.
707
708enum_default_val_loop(_G, _N, _, [], []) ->
709    none;
710enum_default_val_loop(_G, _N, DiscrType, [Value| _], []) ->
711    DiscrType ++ "." ++ Value;
712enum_default_val_loop(G, N, DiscrType, Values, [Case | MList]) when is_tuple(Case) ->
713    NewValues = lists:delete(element(1,Case), Values),
714    enum_default_val_loop(G, N, DiscrType, NewValues, MList).
715
716
717
718emit_discriminator_as_int(G, N, T, Fd) ->
719    case ictype:isBoolean(G,N,T) of
720	true ->
721	    ic_codegen:emit(Fd, "      if(_discriminator)\n", []),
722	    ic_codegen:emit(Fd, "         return 1;\n", []),
723	    ic_codegen:emit(Fd, "      else\n", []),
724	    ic_codegen:emit(Fd, "         return 0;\n", []);
725	false ->
726	    case ictype:isEnum(G, N, T) of
727		true ->
728		    ic_codegen:emit(Fd, "      return _discriminator.value();\n",
729				    []);
730		false ->
731		    ic_codegen:emit(Fd, "      return _discriminator;\n", [])
732	    end
733    end.
734
735
736get_case_as_int(G, N, T, DiscrJavaTypeName, Label) ->
737  case ictype:isBoolean(G,N,T) of
738      true ->
739	  case Label of
740	      "true" ->
741		  "1";
742	      "false" ->
743		  "0"
744	  end;
745      false ->
746	  case ictype:isEnum(G, N, T) of
747	      true ->
748		  DiscrJavaTypeName ++ "._" ++ Label;
749	      false ->
750		  "(" ++ DiscrJavaTypeName ++ ") " ++ Label
751	  end
752  end.
753
754
755
756