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_array_java).
23
24-export([gen/4]).
25
26-include("ic.hrl").
27-include("icforms.hrl").
28
29
30gen(G, N, X, Array) when is_record(X, member) ->
31    ArrayName =  ic_forms:get_java_id(Array),
32    ArrayElement = ic_forms:get_type(X),
33    emit_holder_class(G, N, X, Array, ArrayName, ArrayElement),
34    emit_helper_class(G, N, X, Array, ArrayName, ArrayElement);
35gen(G, N, X, Array) when is_record(X, case_dcl) ->
36    ArrayName =  ic_forms:get_java_id(Array),
37    ArrayElement = ic_forms:get_type(X),
38    emit_holder_class(G, N, X, Array, ArrayName, ArrayElement),
39    emit_helper_class(G, N, X, Array, ArrayName, ArrayElement);
40gen(G, N, X, Array)  ->
41    ArrayName =  ic_forms:get_java_id(Array),
42    ArrayElement = ic_forms:get_body(X),
43    emit_holder_class(G, N, X, Array, ArrayName, ArrayElement),
44    emit_helper_class(G, N, X, Array, ArrayName, ArrayElement).
45
46
47
48%%-----------------------------------------------------------------
49%% Func:  emit_holder_class/4
50%%-----------------------------------------------------------------
51emit_holder_class(G, N, _X, Array, ArrayName, ArrayElement) ->
52    SName = string:concat(ArrayName, "Holder"),
53    {Fd, _}= ic_file:open_java_file(G, N, SName),
54
55    ArrayElementName = ic_java_type:getType(G, N, ArrayElement),
56    EmptyDim = arrayEmptyDim(Array),
57
58    ic_codegen:emit(Fd, "final public class ~sHolder {\n",[ArrayName]),
59
60    ic_codegen:emit(Fd, "   // instance variables\n", []),
61    ic_codegen:emit(Fd, "   public ~s~s value;\n\n",
62		    [ArrayElementName,EmptyDim]),
63
64    ic_codegen:emit(Fd, "   // constructors\n", []),
65    ic_codegen:emit(Fd, "   public ~sHolder() {}\n", [ArrayName]),
66    ic_codegen:emit(Fd, "   public ~sHolder(~s~s initial) {\n",
67		    [ArrayName,ArrayElementName,EmptyDim]),
68    ic_codegen:emit(Fd, "      value = initial;\n", []),
69    ic_codegen:emit(Fd, "   }\n", []),
70    ic_codegen:nl(Fd),
71
72    ic_codegen:emit(Fd, "   // methods\n", []),
73
74    ic_codegen:emit(Fd, "   public void _marshal(~sOtpOutputStream out)\n", [?ERLANGPACKAGE]),
75    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n"),
76    ic_codegen:emit(Fd, "      ~sHelper.marshal(out, value);\n", [ArrayName]),
77    ic_codegen:emit(Fd, "   }\n"),
78    ic_codegen:nl(Fd),
79    ic_codegen:emit(Fd, "   public void _unmarshal(~sOtpInputStream in)\n", [?ERLANGPACKAGE]),
80    ic_codegen:emit(Fd, "      throws java.lang.Exception {\n"),
81    ic_codegen:emit(Fd, "      value = ~sHelper.unmarshal(in);\n", [ArrayName]),
82    ic_codegen:emit(Fd, "   }\n", []),
83    ic_codegen:nl(Fd),
84
85    ic_codegen:emit(Fd, "}\n", []),
86    file:close(Fd).
87
88
89%%-----------------------------------------------------------------
90%% Func:  emit_helper_class/4
91%%-----------------------------------------------------------------
92emit_helper_class(G, N, X, Array, ArrayName, ArrayElement) ->
93    SName = string:concat(ArrayName, "Helper"),
94    {Fd, _}= ic_file:open_java_file(G, N, SName),
95
96    ArrayElementName = ic_java_type:getType(G, N, ArrayElement),
97    EmptyDim = arrayEmptyDim(Array),
98%    Dim = arrayDim(G,N,Array),
99
100    ic_codegen:emit(Fd, "public class ~sHelper {\n",[ArrayName]),
101
102    ic_codegen:emit(Fd, "   // constructors\n"),
103    ic_codegen:emit(Fd, "   private ~sHelper() {}\n\n", [ArrayName]),
104
105    ic_codegen:emit(Fd, "   // methods\n"),
106
107    ic_codegen:emit(Fd, "   public static void marshal(~sOtpOutputStream _out, ~s~s _value)\n",
108		    [?ERLANGPACKAGE,ArrayElementName,EmptyDim]),
109    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
110    emit_array_marshal_loop(G,N,X,Array,ArrayElement,Fd),
111    ic_codegen:emit(Fd, "   }\n"),
112    ic_codegen:nl(Fd),
113    ic_codegen:emit(Fd, "   public static ~s~s unmarshal(~sOtpInputStream _in)\n",
114		    [ArrayElementName,EmptyDim,?ERLANGPACKAGE]),
115    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
116    ic_codegen:emit(Fd, "     ~s~s _value = new ~s;\n\n",
117		    [ArrayElementName,EmptyDim,ic_java_type:getFullType(G, N, X, Array)]),
118    emit_array_unmarshal_loop(G,N,X,Array,ArrayElement,Fd),
119    ic_codegen:emit(Fd, "     return _value;\n"),
120    ic_codegen:emit(Fd, "   }\n\n"),
121
122    ic_codegen:emit(Fd, "   public static String id() {\n", []),
123    ic_codegen:emit(Fd, "     return ~p;\n",[ictk:get_IR_ID(G, N, Array)]),
124    ic_codegen:emit(Fd, "   }\n\n"),
125
126    ic_codegen:emit(Fd, "   public static String name() {\n", []),
127    ic_codegen:emit(Fd, "     return ~p;\n",[ArrayName]),
128    ic_codegen:emit(Fd, "   }\n\n"),
129
130    ic_jbe:emit_type_function(G, N, X, Fd),
131
132    ic_codegen:emit(Fd, "   public static void insert(~sAny _any, ~s~s _this)\n",
133		    [?ICPACKAGE,ArrayElementName,EmptyDim]),
134    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
135
136    ic_codegen:emit(Fd, "     ~sOtpOutputStream _os = \n",[?ERLANGPACKAGE]),
137    ic_codegen:emit(Fd, "       new ~sOtpOutputStream();\n\n",[?ERLANGPACKAGE]),
138
139    ic_codegen:emit(Fd, "     _any.type(type());\n"),
140    ic_codegen:emit(Fd, "     marshal(_os, _this);\n"),
141    ic_codegen:emit(Fd, "     _any.insert_Streamable(_os);\n"),
142    ic_codegen:emit(Fd, "   }\n\n"),
143
144    ic_codegen:emit(Fd, "   public static ~s~s extract(~sAny _any)\n",
145		    [ArrayElementName,EmptyDim,?ICPACKAGE]),
146    ic_codegen:emit(Fd, "     throws java.lang.Exception {\n\n"),
147
148    ic_codegen:emit(Fd, "     return unmarshal(_any.extract_Streamable());\n"),
149    ic_codegen:emit(Fd, "   }\n\n"),
150
151    ic_codegen:emit(Fd, "}\n"),
152    file:close(Fd).
153
154
155
156
157emit_array_marshal_loop(G,N,X,Array,AEl,Fd) ->
158    DimList = mk_array_dim_list(G,N,Array),
159    emit_array_marshal_loop_1(G,N,X,Array,AEl,DimList,0,Fd).
160
161
162emit_array_marshal_loop_1(G,N,X,Array,AEl,[D],C,Fd) ->
163
164    DimList = mk_array_dim_list(G,N,Array),
165
166    ic_codegen:emit(Fd, "     _out.write_tuple_head(~s);\n\n",[D]),
167
168    ic_codegen:emit(Fd, "     for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++)\n",[C,C,D,C]),
169
170    case ic_java_type:isBasicType(G, N, AEl) of
171	true ->
172	    ic_codegen:emit(Fd, "       _out~s(_value",
173			    [ic_java_type:marshalFun(G, N, X, AEl)]);
174	false ->
175	    ic_codegen:emit(Fd, "       ~s(_out, _value",
176			    [ic_java_type:marshalFun(G, N, X, AEl)])
177    end,
178
179    emit_array_dimensions(DimList,0,Fd),
180
181    ic_codegen:emit(Fd, ");\n\n");
182
183emit_array_marshal_loop_1(G,N,X,Array,AEl,[D|Ds],C,Fd) ->
184%    DimList = mk_array_dim_list(G,N,Array),
185
186    ic_codegen:emit(Fd, "     _out.write_tuple_head(~s);\n\n",[D]),
187
188    ic_codegen:emit(Fd, "     for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++) {\n",[C,C,D,C]),
189
190    emit_array_marshal_loop_1(G,N,X,Array,AEl,Ds,C+1,Fd),
191
192    ic_codegen:emit(Fd, "     }\n\n").
193
194
195
196
197
198emit_array_unmarshal_loop(G,N,X,Array,AEl,Fd) ->
199    DimList = mk_array_dim_list(G,N,Array),
200    case length(DimList) > 0 of
201	true ->
202	    ic_codegen:emit(Fd, "     _in.read_tuple_head();\n\n"),
203
204	    ic_codegen:emit(Fd, "     for(int _tmp0 = 0; _tmp0 < ~s; _tmp0++) {\n\n",[hd(DimList)]),
205	    emit_array_unmarshal_loop_1(G,N,X,Array,AEl,tl(DimList),1,Fd),
206	    ic_codegen:emit(Fd, "     }\n\n");
207	false ->
208	    emit_array_unmarshal_loop_1(G,N,X,Array,AEl,DimList,0,Fd)
209    end.
210
211emit_array_unmarshal_loop_1(G,N,X,_Array,AEl,[],1,Fd) -> %% One dimensional array
212    case ic_java_type:isBasicType(G, N, AEl) of
213	true ->
214	    ic_codegen:emit(Fd, "       _value[_tmp0] = _in~s;\n",
215			    [ic_java_type:unMarshalFun(G, N, X, AEl)]);
216	false ->
217	    ic_codegen:emit(Fd, "       _value[_tmp0] = ~s.unmarshal(_in);\n\n",
218			    [ic_java_type:getUnmarshalType(G, N, X, AEl)])
219    end;
220emit_array_unmarshal_loop_1(G,N,X,Array,AEl,[],_C,Fd) ->
221    DimList = mk_array_dim_list(G,N,Array),
222    ic_codegen:emit(Fd, "       _value"),
223    emit_array_dimensions(DimList,0,Fd),
224    case ic_java_type:isBasicType(G,N,AEl) of
225	true ->
226	    ic_codegen:emit(Fd, " = _in~s;\n",
227			    [ic_java_type:unMarshalFun(G, N, X, AEl)]);
228	false ->
229	    ic_codegen:emit(Fd, " = ~s.unmarshal(_in);\n",
230			    [ic_java_type:getUnmarshalType(G, N, X, AEl)])
231	end;
232emit_array_unmarshal_loop_1(G,N,X,Array,AEl,[D|Ds],C,Fd) ->
233    ic_codegen:emit(Fd, "     _in.read_tuple_head();\n\n"),
234
235    ic_codegen:emit(Fd, "     for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++) {\n\n",[C,C,D,C]),
236    emit_array_unmarshal_loop_1(G,N,X,Array,AEl,Ds,C+1,Fd),
237    ic_codegen:emit(Fd, "     }\n").
238
239
240
241
242
243%%---------------------------------------------------
244%%  Utilities
245%%---------------------------------------------------
246
247mk_array_dim_list(G,N,Array) ->
248    mk_array_dim_list2(G,N,Array#array.size).
249
250
251mk_array_dim_list2(_G,_N,[]) ->
252    [];
253
254mk_array_dim_list2(G,N,[D |Ds]) when is_record(D,scoped_id) ->
255    {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D),
256    [ ic_util:to_dot(G,FSN) | mk_array_dim_list2(G,N,Ds)];
257
258mk_array_dim_list2(G,N,[D |Ds]) ->
259    [ic_util:eval_java(G,N,D) | mk_array_dim_list2(G,N,Ds)].
260
261
262
263%% Array dimension string
264%arrayDim(G,N,X) ->
265%    arrayDim2(G,N,X#array.size).
266
267%arrayDim2(_G,_N,[]) ->
268%    "";
269%arrayDim2(G,N,[D|Ds]) when record(D,scoped_id) ->
270%    {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D),
271%    "[" ++ ic_util:to_dot(G,FSN) ++ "]" ++ arrayDim2(G,N,Ds);
272%arrayDim2(G,N,[D|Ds]) ->
273%    "[" ++ ic_util:eval_java(G,N,D) ++ "]" ++ arrayDim2(G,N,Ds).
274
275
276%% Array Empty dimension string
277arrayEmptyDim(X) ->
278    arrayEmptyDim2(X#array.size).
279
280arrayEmptyDim2([_D]) ->
281    "[]";
282arrayEmptyDim2([_D |Ds]) ->
283    "[]" ++ arrayEmptyDim2(Ds).
284
285
286emit_array_dimensions([_D],C,Fd) ->
287    ic_codegen:emit(Fd, "[_tmp~p]",[C]);
288emit_array_dimensions([_D|Ds],C,Fd) ->
289    ic_codegen:emit(Fd, "[_tmp~p]",[C]),
290    emit_array_dimensions(Ds,C+1,Fd).
291
292
293
294
295
296
297