1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-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_error).
23
24-include_lib("ic/src/ic.hrl").
25-include_lib("ic/src/ic_debug.hrl").
26
27%%-----------------------------------------------------------------
28%% External exports
29%%-----------------------------------------------------------------
30-export([error/2,
31	 fatal_error/2,
32	 init_errors/1,
33	 return/1,
34	 warn/2,
35	 get_error_count/1]).
36
37%%-----------------------------------------------------------------
38%% Internal exports
39%%-----------------------------------------------------------------
40-export([]).
41
42%%-----------------------------------------------------------------
43%% External functions
44%%-----------------------------------------------------------------
45
46%%--------------------------------------------------------------------
47%%
48%% Error and warning utilities.
49%%
50%% Note that errors are somewhat brutal and that warnings are kept in
51%% a list for the user to extract at a later stage. The handling of
52%% warnings is entirely up to the user while handling of errors is
53%% never left to the user.
54%%
55%%--------------------------------------------------------------------
56
57return(G) ->
58    case ic_options:get_opt(G, silent2) of
59	true ->
60	    case get_error_count(G) of
61		0 -> {ok, get_list(G, warn_list)};
62		_X -> {error, get_list(G, warn_list), get_list(G, error_list)}
63	    end;
64	false ->
65	    case get_error_count(G) of
66		0 -> ok;
67		X -> print_error(G, {error, g, ic_genobj:idlfile(G), {error_count, X}}),
68		     error
69	    end
70    end.
71
72
73get_list(G, ListName) ->
74    ?lookup(G#genobj.options, ListName).
75
76
77%% Public function for reporting an error
78error(G, Err) ->
79    Error = {error, g, ic_genobj:idlfile(G), Err},
80    case insert_in_list(G, Error, error_list) of
81	new ->
82	    print_error(G, Error),
83	    MaxErrs = ic_options:get_opt(G, maxerrs),
84	    case incr_counter(G, error_count) of
85		X when X >= MaxErrs ->
86		    fatal_error(G, {error_count_exceeded, X});
87		_ -> Error
88	    end;
89	old ->
90	    Error
91    end.
92
93%% Public function for reporting an error. NOTE: also stops execution
94fatal_error(G, Err) ->
95    Error = {error, g, ic_genobj:idlfile(G), Err},
96    insert_in_list(G, Error, error_list),
97    incr_counter(G, error_count),
98    print_error(G, Error),
99    throw(Error).
100
101
102%% Public function for reporting a warning
103warn(G, Warn) ->
104    Warning = {warn, g, ic_genobj:idlfile(G), Warn},
105    case insert_in_list(G, Warning, warn_list) of
106	new ->
107	    print_warn(G, Warning),
108	    MaxErrs = ic_options:get_opt(G, maxwarns),
109	    case incr_counter(G, warn_count) of
110		X when X >= MaxErrs ->
111		    fatal_error(G, {warn_count_exceeded, X});
112		_ -> ok
113	    end;
114	old -> ok
115end.
116
117
118%% Initialisation of all counters and lists associated with errors and
119%% warnings.
120init_errors(G) ->
121    reset_counter(G, error_count),
122    reset_counter(G, warn_count),
123    reset_list(G, error_list),
124    reset_list(G, warn_list),
125    ok.
126
127
128
129%%--------------------------------------------------------------------
130%% Counter and list (warn and error) handling
131%%
132
133incr_counter(G, Counter) ->
134    Num = ?lookup(G#genobj.options, Counter) + 1,
135    ?insert(G#genobj.options, Counter, Num),
136    Num.
137
138reset_counter(G, Counter) ->
139    ?insert(G#genobj.options, Counter, 0).
140
141get_error_count(G) ->
142    ?lookup(G#genobj.options, error_count).
143
144reset_list(G, ListName) ->
145    ?insert(G#genobj.options, ListName, []).
146
147insert_in_list(G, Item, ListName) ->
148    List = ?lookup(G#genobj.options, ListName),
149    case lists:member(Item, List) of
150	true -> old;
151	false ->
152	    ?insert(G#genobj.options, ListName, [Item| List]),
153	    new
154    end.
155
156
157%%--------------------------------------------------------------------
158%%
159%% Nice printouts of errors and warnings
160%%
161
162
163%% Errors
164
165print_error(G, Error) ->
166    case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of
167	{true, _} -> ok;
168	{_, true} -> ok;
169	_ -> format_error(Error)
170    end,
171    error.
172
173format_error({error, _, File, {parse_error, Line, Args}}) ->
174    Fmt = lists:foldl(fun(_, Acc) -> [$~, $s | Acc] end, [], Args),
175    display(File, Line, Fmt, Args);
176format_error({error, _, File, {error_count, X}}) ->
177    display(File, "~p errors found", [X]);
178format_error({error, _, File, {error_count_exceeded, X}}) ->
179    display(File, "too many errors found (~p)", [X]);
180format_error({error, _, File, {warn_count_exceeded, X}}) ->
181    display(File, "too many warnings found (~p)", [X]);
182format_error({error, _, File, {inherit_name_collision,
183			       {Orig, Item}, {Base, NewItem}}}) ->
184    display(File, ic_forms:get_line(Item), "~s collides with ~s",
185	    [pp([ic_forms:get_id2(Item) | Orig]), pp([ic_forms:get_id2(NewItem) | Base])]);
186format_error({error, _, File, {unsupported_op, {'~', Line}}}) ->
187    display(File, Line, "unsupported unary operation ~~", []);
188format_error({error, _, File, {multiply_defined, X}}) ->
189    display(File, ic_forms:get_line(X), "multiple defined identifier ~p", [ic_forms:get_id2(X)]);
190format_error({error, _, File, {illegal_spelling, X}}) ->
191    display(File, ic_forms:get_line(X),
192%	    "illegal spelling of identifier ~s (capitalisation?)",
193	    "identifier ~p multiply declared - differs in case only",
194	    [ic_forms:get_id2(X)]);
195format_error({error, _, File, {illegal_enumerant_value, X}}) ->
196    display(File, ic_forms:get_line(X),
197	    "Enumerant ~s's value collide by name with other type",
198	    [ic_forms:get_id2(X)]);
199format_error({error, _, File, {illegal_forward, X}}) ->
200    display(File, ic_forms:get_line(X),
201	    "cannot inherit from forwarded interface ~s", [ic_forms:get_id2(X)]);
202format_error({error, _, File, {illegal_const_t, X, Type}}) ->
203    display(File, ic_forms:get_line(X),
204	    "Illegal constant type ~s of ~s", [pp(Type), ic_forms:get_id2(X)]);
205format_error({error, _, File, {multiple_cases, X}}) ->
206    display(File, ic_forms:get_line(X), "multiple case values ~s", [pp(X)]);
207format_error({error, _, File, {symtab_not_found, X}}) ->
208    display(File, ic_forms:get_line(X), "undeclared identifier ~s", [ic_forms:get_id2(X)]);
209format_error({error, _, File, {preproc, Lines}}) ->
210    display(File, "preprocessor error: ~s", [hd(Lines)]);
211format_error({error, _, File, {ic_pp_error, Lines}}) ->
212    display(File, "preprocessor error: ~s", [Lines]);
213format_error({error, _, File, {illegal_float, Line}}) ->
214    display(File, Line, "illegal floating point number", []);
215format_error({error, _, File, {bad_type_combination, E, V1, V2}}) ->
216    display(File, ic_forms:get_line(E), "incompatible types, ~p and ~p", [V1, V2]);
217format_error({error, _, File, {bad_oneway_type, X, _TK}}) ->
218    display(File, ic_forms:get_line(X), "oneway operations must be declared void", []);
219format_error({error, _, File, {inout_spec_for_c, X, Arg}}) ->
220    display(File, ic_forms:get_line(X), "inout parameter ~s specified in native c mode",
221	    [Arg]);
222format_error({error, _, File, {sequence_not_defined, X, Arg}}) ->
223    display(File, ic_forms:get_line(X), "sequence ~s not defined", [Arg]);
224format_error({error, _, File, {illegal_typecode_for_c, Arg}}) ->
225    display(File, not_specified, "illegal typecode ~s used in native c mode",
226	    [Arg]);
227format_error({error, _, File, {name_not_found, N}}) ->
228    display(File, not_specified, "name ~s not found", [N]);
229format_error({error, _, File, {illegal_typecode_for_c, Arg, N}}) ->
230    display(File, not_specified, "illegal typecode ~p used for ~p in native c mode", [Arg, N]);
231format_error({error, _, File, {oneway_outparams, X}}) ->
232    display(File, ic_forms:get_line(X),
233	    "oneway operations may not have out or inout parameters", []);
234format_error({error, _, File, {oneway_raises, X}}) ->
235    display(File, ic_forms:get_line(X), "oneway operations may not raise exceptions",
236	    []);
237format_error({error, _, File, {bad_tk_match, T, TK, V}}) ->
238    display(File, ic_forms:get_line(T),
239	    "value ~p does not match declared type ~s", [V, pp(TK)]);
240format_error({error, _, File, {bad_scope_enum_case, ScopedId}}) ->
241    display(File, ic_forms:get_line(ScopedId),
242	    "scoped enum identifiers not allowed as case (~s)",
243	    [pp(ScopedId)]);
244format_error({error, _, File, {bad_type, Expr, Op, _TypeList, V}}) ->
245    display(File, ic_forms:get_line(Expr),
246	    "parameter value ~p to ~s is of illegal type", [V, pp(Op)]);
247format_error({error, _, File, {bad_case_type, TK, X, Val}}) ->
248    display(File, ic_forms:get_line(X),
249	    "case value ~s does not match discriminator type ~s",
250	    [case_pp(X, Val), pp(TK)]);
251format_error({error, _, File, {tk_not_found, X}}) ->
252    display(File, ic_forms:get_line(X), "undeclared identifier ~s", [pp(X)]);
253%%% New format_errors
254format_error({error, _, File, {bad_fixed, Format, Args, Line}}) ->
255    display(File, Line, Format, Args);
256format_error({error, _, File, {illegal_switch_t, Arg, _N}}) ->
257    display(File, ic_forms:get_line(Arg), "illegal switch", []);
258format_error({error, _, File, {inherit_resolve, Arg, N}}) ->
259    display(File, ic_forms:get_line(Arg), "cannot resolve ~s", [N]);
260format_error({error, _, File, {bad_escape_character, Line, Char}}) ->
261    display(File, Line, "bad escape character \"~c\"", [Char]);
262format_error({error, _, File, {pragma_code_opt_bad_option_list, Line}}) ->
263    display(File, Line, "bad option list on pragma \"CODEOPT\"", []);
264format_error({error, _, File, {bad_string, Line}}) ->
265    display(File, Line, "bad string", []);
266format_error({error, _, File, {create_dir, Path, Reason}}) ->
267    display(File, not_specified, "couldn't create directory ~p due to ~p", [Path, Reason]);
268format_error({error, _, File, {open_file, Path, Reason}}) ->
269    display(File, not_specified, "couldn't open ~p due to ~p", [Path, Reason]);
270format_error({error, _, File, {plain_error_string, ErrString}}) ->
271    display(File, not_specified, "~s", [ErrString]);
272format_error({error, _, File, {plain_error_string, T, ErrString}}) ->
273    display(File, ic_forms:get_line(T), "~s", [ErrString]);
274format_error({error, _, File, {ErrString, Line}}) ->
275    display(File, Line, ErrString, []).
276
277
278%% Warnings
279print_warn(G, Warn) ->
280    case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of
281	{true, _} -> ok;
282	{_, true} -> ok;
283	_ -> format_warn(Warn)
284    end.
285
286format_warn({warn, _, File, {ic_pp_warning, Lines}}) ->
287    display(File, "preprocessor warning: ~s", [Lines]);
288format_warn({warn, _, _File, {cfg_open, _Reason, File}}) ->
289    display(File, "warning: could not open file: ~p", [File]);
290format_warn({warn, _, _File, {cfg_read, File}}) ->
291    display(File, "warning: syntax error in configuration file", []);
292format_warn({warn, _, File, {multi_modules, Id}}) ->
293    display(File, ic_forms:get_line(Id), "warning: multiple modules in file", []);
294format_warn({warn, _, File, {illegal_opt, Opt}}) ->
295    display(File, "warning: unrecognised option: ~p", [Opt]);
296format_warn({warn, _, File, {nested_mod, Id}}) ->
297    display(File, ic_forms:get_line(Id), "warning: nested module: ~s", [ic_forms:get_id(Id)]);
298format_warn({warn, _, File, {inherit_name_shadow, {Orig, Item},
299			     {Base, NewItem}}}) ->
300    display(File, ic_forms:get_line(Item),
301	    "warning: ~s shadows ~s", [pp([ic_forms:get_id2(Item) | Orig]),
302				       pp([ic_forms:get_id2(NewItem) | Base])]);
303format_warn({warn, _, File, {internal_307, X, Y}}) ->
304    %% If global Scope variable is not [] at top level constant
305    display(File, ic_forms:get_line(X), "warning: internal 307: ~p ~p", [X, Y]);
306format_warn({warn, _, File, {WarnString, Line}}) ->
307    display(File, Line, WarnString, []).
308
309%% Display an error or warning
310display(File, not_specified, F, A) ->
311    io:format("~p : ~s~n", [File, io_lib:format(F, A)]);
312display(File, Line, F, A) ->
313    io:format("~p on line ~p: ~s~n", [File, Line, io_lib:format(F, A)]).
314display(File, F, A) ->
315    io:format("~p: ~s~n", [File, io_lib:format(F, A)]).
316
317
318
319%%format_warn2(G, WarnStr) ->
320%%    case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2),
321%%          ic_options:get_opt(G, nowarn)} of
322%%	{false, false, false} ->
323%%	    io:format("~p: warning: ~s~n", [ic_genobj:idlfile(G), WarnStr]);
324%%	_ -> ok
325%%    end.
326
327%%format_warn2(G, Line, WarnStr) ->
328%%    case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2),
329%%          ic_options:get_opt(G, nowarn)} of
330%%	{false, false, false} ->
331%%	    io:format("~p on line ~p: warning: ~s~n",
332%%		      [ic_genobj:idlfile(G), Line, WarnStr]);
333%%	_ -> ok
334%%    end.
335
336
337
338
339%% pretty print various stuff
340
341pp({tk_string, _}) -> "string";
342pp({tk_wstring, _}) -> "wstring";
343pp(tk_long) -> "long";
344pp(tk_short) -> "short";
345pp(tk_ushort) -> "unsigned short";
346pp(tk_ulong) -> "unsigned long";
347pp(tk_float) -> "float";
348pp(tk_double) -> "double";
349pp(tk_boolean) -> "boolean";
350pp(tk_char) -> "char";
351pp(tk_wchar) -> "wchar";
352pp(tk_octet) -> "octet";
353pp(tk_null) -> "null";
354pp(tk_void) -> "void";
355pp(tk_any) -> "any";
356pp({tk_fixed, _, _}) -> "fixed";
357pp({tk_objref, _, _}) -> "object reference";
358pp(rshift) -> ">>";
359pp(lshift) -> "<<";
360pp(X) when element(1, X) == tk_enum -> "enum";
361pp(X) when is_record(X, scoped_id) -> ic_util:to_colon(X);
362pp(X) when element(1, X) == '<identifier>' -> ic_forms:get_id(X);
363pp(X) when is_list(X) andalso is_list(hd(X)) -> ic_util:to_colon(X);
364pp({_, Num, Beef}) when is_integer(Num) -> Beef;
365pp({Beef, Num}) when is_integer(Num) -> ic_util:to_list(Beef);
366pp(X) -> ic_util:to_list(X).
367
368%% special treatment of case label names
369case_pp(X, _Val) when is_record(X, scoped_id) -> pp(X);
370case_pp(_X, Val) -> pp(Val).
371
372
373
374%%-----------------------------------------------------------------
375%% Internal functions
376%%-----------------------------------------------------------------
377