1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-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-module(ic).
22
23
24-export([sgen/1, gen/1, gen/2, help/0, compile/3]).
25
26
27%%------------------------------------------------------------
28%%
29%% Internal stuff
30%%
31%%------------------------------------------------------------
32
33-export([filter_params/2, handle_preproc/4, do_gen/4]).
34
35-import(lists, [foldr/3]).
36
37
38-include("icforms.hrl").
39-include("ic.hrl").
40
41-include_lib("stdlib/include/erl_compile.hrl").
42
43-export([make_erl_options/1]).			% For erlc
44
45-export([main/3, do_scan/1, do_parse/2, do_type/2]).
46
47
48%%------------------------------------------------------------
49%%
50%% Entry point
51%%
52%%------------------------------------------------------------
53
54%% compile(AbsFileName, Outfile, Options)
55%%   Compile entry point for erl_compile.
56
57compile(File, _OutFile, Options) ->
58    case gen(File, make_erl_options(Options)) of
59	ok -> ok;
60	Other -> Other
61    end.
62
63
64%% Entry for the -s switch
65sgen(ArgList) ->
66%%%    io:format("sgen called w ~p~n", [ArgList]),
67    apply(?MODULE, gen, ArgList).
68
69
70gen(File) ->
71    gen(File, []).
72
73gen(File, Opts) ->
74    G = ic_genobj:new(Opts),
75    IdlFile = ic_file:add_dot_idl(File),
76    case ic_options:get_opt(G, show_opts) of
77	true ->
78	    io:format("Opts: ~p~n", [ic_options:which_opts(G)]);
79	_ -> ok
80    end,
81    ic_genobj:set_idlfile(G, IdlFile),
82    case catch gen2(G, File, Opts) of
83	{_, {'EXIT', R}} ->
84	    ic_genobj:free_table_space(G), %% Free space for all ETS tables
85	    io:format("Fatal error : ~p~n",[R]),
86	    error;
87	{_, {'EXIT', _, R}} ->
88	    ic_genobj:free_table_space(G), %% Free space for all ETS tables
89	    io:format("Fatal error : ~p~n",[R]),
90	    error;
91	{'EXIT', R} ->
92	    ic_genobj:free_table_space(G), %% Free space for all ETS tables
93	    io:format("Fatal error : ~p~n",[R]),
94	    error;
95	{'EXIT', _, R} ->
96	    ic_genobj:free_table_space(G), %% Free space for all ETS tables
97	    io:format("Fatal error : ~p~n",[R]),
98	    error;
99	%% In this case, the pragma registration
100        %% found errors so this should return error.
101	error ->
102	    ic_genobj:free_table_space(G), %% Free space for all ETS tables
103	    error;
104	_ ->
105	    X = ic_error:return(G),
106	    ic_genobj:free_table_space(G), %% Free space for all ETS tables
107	    X
108    end.
109
110
111gen2(G, File, Opts) ->
112    case ic_options:get_opt(G, time) of
113	true ->
114	    time("TOTAL                ", ic, main, [G, File, Opts]);
115	_ ->
116	    case main(G, File, Opts) of
117		error ->
118		    error;
119		_ ->
120		    ok
121	    end
122    end.
123
124
125
126do_gen(erl_corba, G, File, T) ->
127    ic_erlbe:do_gen(G, File, T);
128do_gen(erl_template, G, File, T) ->
129    ic_erl_template:do_gen(G, File, T);
130do_gen(erl_genserv, G, File, T) ->
131    ic_erlbe:do_gen(G, File, T);
132do_gen(c_genserv, G, File, T) ->
133    ic_cclient:do_gen(G, File, T);
134do_gen(noc, G, File, T) ->
135    ic_noc:do_gen(G, File, T);
136do_gen(erl_plain, G, File, T) ->
137    ic_plainbe:do_gen(G, File, T);
138do_gen(c_server, G, File, T) ->
139    ic_cserver:do_gen(G, File, T);
140do_gen(c_client, G, File, T) ->
141    ic_cclient:do_gen(G, File, T);
142%% Java backend
143do_gen(java, G, File, T) ->
144    ic_jbe:do_gen(G, File, T);
145%% No language choice
146do_gen(_,_,_,_) ->
147    ok.
148
149do_scan(G) ->
150    icscan:scan(G, ic_genobj:idlfile(G)).
151
152
153do_parse(G, Tokens) ->
154    case icparse:parse(Tokens) of
155	{ok, L} -> L;
156	X when element(1, X) == error ->
157	    Err = element(2, X),
158	    ic_error:fatal_error(G, {parse_error, element(1, Err),
159				  element(3, Err)});
160	X -> exit(X)
161    end.
162
163
164do_type(G, Form) ->
165    ictype:type_check(G, Form).
166
167time(STR,M,F,A) ->
168    case timer:tc(M, F, A) of
169	{_, {'EXIT', R}} -> exit(R);
170	{_, {'EXIT', _, R}} -> exit(R);
171	{_, _X} when element(1, _X)==error -> throw(_X);
172	{_T, _R} ->
173	    io:format("Time for ~s:  ~10.2f~n", [STR, _T/1000000]),
174	    _R
175    end.
176
177
178
179%% Filters parameters so that only those with certain attributes are
180%% seen. The filter parameter is a list of attributes that will be
181%% seen, ex. [in] or [inout, out]
182filter_params(Filter, Params) ->
183    lists:filter(fun(P) ->
184		    lists:member(get_param_attr(P#param.inout), Filter) end,
185		 Params).
186
187
188%% Access primitive to get the attribute name (and discard the line
189%% number).
190get_param_attr({A, _N}) -> A.
191
192
193%%
194%% Fixing the preproc directives
195%%
196handle_preproc(G, _N, line_nr, X) ->
197    Id = ic_forms:get_id2(X),
198    Flags = X#preproc.aux,
199    case Flags of
200	[] -> ic_genobj:push_file(G, Id);
201	_ ->
202	    foldr(fun({_, _, "1"}, Gprim) -> ic_genobj:push_file(Gprim, Id);
203		     ({_, _, "2"}, Gprim) -> ic_genobj:pop_file(Gprim, Id);
204		     ({_, _, "3"}, Gprim) -> ic_genobj:sys_file(Gprim, Id) end,
205		  G, Flags)
206    end;
207handle_preproc(G, _N, _Other, _X) ->
208    G.
209
210
211
212%%------------------------------------------------------------
213%%
214%% The help department
215%%
216%%
217%%
218%%------------------------------------------------------------
219
220help() ->
221    io:format("No help available at the moment~n", []),
222    ok.
223
224print_version_str(G) ->
225    case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of
226	{true, _} -> ok;
227	{_, true} -> ok;
228	_ ->
229	    io:format("Erlang IDL compiler version ~s~n", [?COMPILERVSN])
230    end.
231
232
233
234%%
235%% Converts generic compiler options to specific options.
236%%
237%% Used by erlc
238%%
239
240make_erl_options(Opts) ->
241
242    %% This way of extracting will work even if the record passed
243    %% has more fields than known during compilation.
244
245    Includes1 = Opts#options.includes,
246    Defines = Opts#options.defines,
247    Outdir = Opts#options.outdir,
248    Warning = Opts#options.warning,
249    Verbose = Opts#options.verbose,
250    Specific = Opts#options.specific,
251    Optimize = Opts#options.optimize,
252    PreProc =
253	lists:flatten(
254	  lists:map(fun(D) -> io_lib:format("-I\"~ts\" ", [ic_util:to_list(D)]) end,
255		    Includes1)++
256	  lists:map(
257	    fun ({Name, Value}) ->
258		    io_lib:format("-D~s=~s ", [ic_util:to_list(Name), ic_util:to_list(Value)]);
259		(Name) ->
260		    io_lib:format("-D~s ", [ic_util:to_list(Name)])
261	    end,
262	    Defines)),
263    Options =
264	case Verbose of
265	    true ->  [];
266	    false -> []
267	end ++
268	case Warning of
269	    0 -> [nowarn];
270	    _ -> ['Wall']
271	end ++
272	case Optimize of
273	    0 -> [];
274	    _ -> []
275	end,
276
277    Options++[{outdir, Outdir}, {preproc_flags, PreProc}]++Specific.
278
279
280%%%
281%%% NEW main, avoids memory fragmentation
282%%%
283main(G, File, _Opts) ->
284    print_version_str(G),
285    ?ifopt(G, time, io:format("File ~p compilation started  :   ~p/~p/~p ~p:~2.2.0p~n",
286			      [ic_genobj:idlfile(G),
287			       element(1,date()),
288			       element(2, date()),
289			       element(3, date()),
290			       element(1, time()),
291			       element(2, time())])),
292
293    case ic_options:get_opt(G, help) of
294	true -> help();
295
296	_ ->
297	    scanning(G, File)
298    end.
299
300
301
302scanning(G, File) ->
303    S = ?ifopt2(G, time,
304	       time("input file scanning  ", ic, do_scan, [G]),
305	       ic:do_scan(G)),
306    ?ifopt2(G, tokens, io:format("TOKENS: ~p~n", [S]),
307				 parsing(G, File, S)).
308
309parsing(G, File, S) ->
310    T = ?ifopt2(G,
311		time,
312		time("input file parsing   ", ic, do_parse, [G,S]),
313		ic:do_parse(G,S)),
314    ?ifopt2(G, form, io:format("PARSE FORM: ~p~n", [T]),
315	     pragma(G, File, T)).
316
317
318
319pragma(G, File, T) ->
320    case ?ifopt2(G,
321		 time,
322		 time("pragma registration  ", ic_pragma, pragma_reg, [G,T]),
323		 ic_pragma:pragma_reg(G,T)) of
324	%% All pragmas were successfully applied
325	{ok,Clean} ->
326	    typing(G, File, Clean);
327
328	error ->
329	    error
330    end.
331
332
333typing(G, File, Clean) ->
334    case catch ?ifopt2(G,
335		       time,
336		       time("type code appliance  ", ic, do_type, [G,Clean]),
337		       ic:do_type(G,Clean)) of
338	{'EXIT',Reason} ->
339	    io:format("Error under type appliance : ~p~n",[Reason]),
340	    error;
341
342	T2 ->
343	    ?ifopt2(G, tform, io:format("TYPE FORM: ~p~n", [T2]),
344		    generation(G, File, T2))
345    end.
346
347
348
349generation(G, File, T2) ->
350    case ic_options:get_opt(G, multiple_be) of
351	false ->
352	    single_generation(G, File, T2);
353	List ->
354	    OutDir =
355		case ic_options:get_opt(G, outdir) of
356		    false ->
357			[];
358		    Dir ->
359			Dir
360		end,
361
362	    case ic_options:get_opt(G, be) of
363		false ->
364		    ok;
365		Be ->
366		    %% Generate this first
367		    ic_options:add_opt(G,[{outdir,OutDir++atom_to_list(Be)}],true),
368		    single_generation(G, File, T2)
369	    end,
370	    multiple_generation(G, File, T2, OutDir, List)
371    end.
372
373multiple_generation(_G, _File, _T2, _RootDir, []) ->
374    ok;
375multiple_generation(G, File, T2, RootDir, [Be|Bes]) ->
376    ic_options:add_opt(G,[{outdir,RootDir++atom_to_list(Be)}],true),
377    ic_options:add_opt(G,[{be,Be}],true),
378    single_generation(G, File, T2),
379
380    case ic_error:get_error_count(G) of
381	0 ->
382	     multiple_generation(G,File,T2,RootDir,Bes);
383	 _ ->
384	     %% Errors reported, abort
385	     ok
386     end.
387
388
389single_generation(G, File, T2) ->
390    case ic_error:get_error_count(G) of
391	0 ->
392	    %% Check if user has sett backend option
393	    case ic_options:get_opt(G, be) of
394		false ->
395		    %% Use default backend option
396		    DefaultBe = ic_options:defaultBe(),
397		    ic_options:add_opt(G,[{be,DefaultBe}],true),
398
399		    ?ifopt2(G,
400			    time,
401			    time("code generation      ", ic, do_gen, [DefaultBe, G, File, T2]),
402			    ic:do_gen(DefaultBe, G, File, T2));
403		Be ->
404		    %% Use user defined backend
405		    ?ifopt2(G,
406			    time,
407			    time("code generation      ", ic, do_gen, [Be, G, File, T2]),
408			    ic:do_gen(Be, G, File, T2))
409	    end;
410	_ ->
411	    ok	    %% Does not matter
412    end.
413
414
415
416