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