-
-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy patherrmsg.py
More file actions
354 lines (246 loc) · 11.6 KB
/
errmsg.py
File metadata and controls
354 lines (246 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# --------------------------------------------------------------------
# SPDX-License-Identifier: AGPL-3.0-or-later
# © Copyright 2008-2024 José Manuel Rodríguez de la Rosa and contributors.
# See the file CONTRIBUTORS.md for copyright details.
# See https://www.gnu.org/licenses/agpl-3.0.html for details.
# --------------------------------------------------------------------
import sys
from collections.abc import Callable
from functools import wraps
from src.api import config, global_
from src.api.constants import CLASS
# Exports only these functions. Others
__all__ = (
"error",
"is_valid_warning_code",
"register_warning",
"warning",
"warning_not_used",
)
WARNING_PREFIX: str = "" # will be prepended to warning messages
ERROR_PREFIX: str = "" # will be prepended to error messages
def msg_output(msg: str) -> None:
if msg in global_.error_msg_cache:
return
config.OPTIONS.stderr.write("%s\n" % msg)
global_.error_msg_cache.add(msg)
def info(msg: str) -> None:
if config.OPTIONS.debug_level < 1:
return
config.OPTIONS.stderr.write("info: %s\n" % msg)
def error(lineno: int, msg: str, fname: str | None = None) -> None:
"""Generic syntax error routine"""
if fname is None:
fname = global_.FILENAME
if global_.has_errors > config.OPTIONS.max_syntax_errors:
msg = "Too many errors. Giving up!"
msg = "%s:%i: error:%s %s" % (fname, lineno, ERROR_PREFIX, msg)
msg_output(msg)
if global_.has_errors > config.OPTIONS.max_syntax_errors:
sys.exit(1)
global_.has_errors += 1
def warning(lineno: int, msg: str, fname: str | None = None) -> None:
"""Generic warning error routine"""
global_.has_warnings += 1
if global_.has_warnings <= config.OPTIONS.expected_warnings:
return
if fname is None:
fname = global_.FILENAME
msg = "%s:%i: %s %s" % (fname, lineno, WARNING_PREFIX or "warning:", msg)
msg_output(msg)
def is_valid_warning_code(code: str) -> bool:
return code in global_.ENABLED_WARNINGS
def assert_is_valid_warning_code(code: str):
assert is_valid_warning_code(code), f"Invalid warning code '{code}'"
def enable_warning(code: str):
assert_is_valid_warning_code(code)
global_.ENABLED_WARNINGS[code] = True
def disable_warning(code: str):
assert_is_valid_warning_code(code)
global_.ENABLED_WARNINGS[code] = False
def register_warning(code: str) -> Callable:
assert code not in global_.ENABLED_WARNINGS, f"Duplicated warning code '{code}'"
global_.ENABLED_WARNINGS[code] = True
def decorator(func: Callable) -> Callable:
def wrapper(*args, **kwargs):
global WARNING_PREFIX
if global_.ENABLED_WARNINGS.get(code, True):
if not config.OPTIONS.hide_warning_codes:
WARNING_PREFIX = f"warning: [W{code}]"
func(*args, **kwargs)
WARNING_PREFIX = ""
return wraps(func)(wrapper)
return decorator
def warning_command_line_flag_deprecation(flag: str) -> None:
"""Warning signaling command line flag is deprecated.
This is a special warning that can't be silenced, and needs no line number nor filename.
"""
msg_output(f"WARNING: deprecated flag {flag}") # TODO: To be enabled upon 1.18+
# region [Warnings]
@register_warning("100")
def warning_implicit_type(lineno: int, id_: str, type_: str = None):
"""Warning: Using default implicit type 'x'"""
if config.OPTIONS.strict:
syntax_error_undeclared_type(lineno, id_)
return
if type_ is None:
type_ = global_.DEFAULT_TYPE.name
warning(lineno, "Using default implicit type '%s' for '%s'" % (type_, id_))
@register_warning("110")
def warning_condition_is_always(lineno: int, cond: bool = False):
"""Warning: Condition is always false/true"""
warning(lineno, "Condition is always %s" % cond)
@register_warning("120")
def warning_conversion_lose_digits(lineno: int):
"""Warning: Conversion may lose significant digits"""
warning(lineno, "Conversion may lose significant digits")
@register_warning("130")
def warning_empty_loop(lineno: int):
"""Warning: Empty loop"""
warning(lineno, "Empty loop")
@register_warning("140")
def warning_empty_if(lineno: int):
"""Warning: Useless empty IF ignored"""
warning(lineno, "Useless empty IF ignored")
@register_warning("150")
def warning_not_used(lineno: int, id_: str, kind: str = "Variable", fname: str | None = None):
"""Emits an optimization warning"""
if config.OPTIONS.optimization_level > 0:
warning(lineno, "%s '%s' is never used" % (kind, id_), fname=fname)
@register_warning("160")
def warning_fastcall_with_N_parameters(lineno: int, kind: str, id_: str, num_params: int):
"""Warning: SUB/FUNCTION declared as FASTCALL with N parameters"""
warning(lineno, f"{kind} '{id_}' declared as FASTCALL with {num_params} parameters")
@register_warning("170")
def warning_func_is_never_called(lineno: int, func_name: str, fname: str | None = None):
warning(lineno, f"Function '{func_name}' is never called and has been ignored", fname=fname)
@register_warning("180")
def warning_unreachable_code(lineno: int, fname: str | None = None):
warning(lineno, "Unreachable code", fname=fname)
@register_warning("190")
def warning_function_should_return_a_value(lineno: int, func_name: str, fname: str | None = None):
warning(lineno, f"Function '{func_name}' should return a value", fname=fname)
@register_warning("200")
def warning_value_will_be_truncated(lineno: int, fname: str | None = None):
warning(lineno, "Value will be truncated", fname=fname)
@register_warning("300")
def warning_ignoring_unknown_pragma(lineno: int, pragma_name: str):
warning(lineno, f"Ignoring unknown pragma '{pragma_name}'")
# endregion
# region [Syntax Errors]
# ----------------------------------------
# Syntax error: Expected string instead of
# numeric expression.
# ----------------------------------------
def syntax_error_expected_string(lineno: int, _type: str):
error(lineno, "Expected a 'string' type expression, got '%s' instead" % _type)
# ----------------------------------------
# Syntax error: FOR variable should be X
# instead of Y
# ----------------------------------------
def syntax_error_wrong_for_var(lineno: int, x: str, y: str):
error(lineno, "FOR variable should be '%s' instead of '%s'" % (x, y))
# ----------------------------------------
# Syntax error: Initializer expression is
# not constant
# ----------------------------------------
def syntax_error_not_constant(lineno: int):
error(lineno, "Initializer expression is not constant.")
# ----------------------------------------
# Syntax error: Id is neither an array nor
# a function
# ----------------------------------------
def syntax_error_not_array_nor_func(lineno: int, varname: str):
error(lineno, "'%s' is neither an array nor a function." % varname)
# ----------------------------------------
# Syntax error: Id is neither an array nor
# a function
# ----------------------------------------
def syntax_error_not_an_array(lineno: int, varname: str):
error(lineno, "'%s' is not an array (or has not been declared yet)" % varname)
# ----------------------------------------
# Syntax error: function redefinition type
# mismatch
# ----------------------------------------
def syntax_error_func_type_mismatch(lineno: int, entry):
error(lineno, "Function '%s' (previously declared at %i) type mismatch" % (entry.name, entry.lineno))
# ----------------------------------------
# Syntax error: function redefinition parm.
# mismatch
# ----------------------------------------
def syntax_error_parameter_mismatch(lineno: int, entry):
error(lineno, "Function '%s' (previously declared at %i) parameter mismatch" % (entry.name, entry.lineno))
# ----------------------------------------
# Syntax error: can't convert value to the
# given type.
# ----------------------------------------
def syntax_error_cant_convert_to_type(lineno: int, expr_str: str, type_: str):
error(lineno, "Cant convert '%s' to type %s" % (expr_str, type_))
# ----------------------------------------
# Syntax error: is a SUB not a FUNCTION
# ----------------------------------------
def syntax_error_is_a_sub_not_a_func(lineno: int, name: str):
error(lineno, "'%s' is a SUB not a FUNCTION" % name)
# ----------------------------------------
# Syntax error: strict mode: missing type declaration
# ----------------------------------------
def syntax_error_undeclared_type(lineno: int, id_: str):
error(lineno, "strict mode: missing type declaration for '%s'" % id_)
# ----------------------------------------
# Cannot assign a value to 'var'. It's not a variable
# ----------------------------------------
def syntax_error_cannot_assign_not_a_var(lineno: int, id_: str):
error(lineno, "Cannot assign a value to '%s'. It's not a variable" % id_)
# ----------------------------------------
# Cannot assign a value to 'var'. It's not a variable
# ----------------------------------------
def syntax_error_address_must_be_constant(lineno: int):
error(lineno, "Address must be a numeric constant expression")
# ----------------------------------------
# Cannot pass an array by value
# ----------------------------------------
def syntax_error_cannot_pass_array_by_value(lineno: int, id_: str):
error(lineno, "Array parameter '%s' must be passed ByRef" % id_)
# ----------------------------------------
# Cannot pass an array by value
# ----------------------------------------
def syntax_error_no_data_defined(lineno: int):
error(lineno, "No DATA defined")
# ----------------------------------------
# Cannot pass an array by value
# ----------------------------------------
def syntax_error_cannot_initialize_array_of_type(lineno: int, type_name: str):
error(lineno, f"Cannot initialize array of type {type_name}")
# ----------------------------------------
# Cannot define a default array argument
# ----------------------------------------
def syntax_error_cannot_define_default_array_argument(lineno: int):
error(lineno, "Cannot define default array argument")
# ----------------------------------------
# Error, ID is a ... not a ...
# ----------------------------------------
def syntax_error_unexpected_class(lineno: int, id_name: str, wrong_class: CLASS, good_class: CLASS):
n1 = "n" if wrong_class[0] in "aeiou" else ""
n2 = "n" if good_class[0] in "aeiou" else ""
error(lineno, f"'{id_name}' is a{n1} {wrong_class.upper()}, not a{n2} {good_class.upper()}")
# ----------------------------------------
# ID already declared as <class> at <line>
# ----------------------------------------
def syntax_error_already_declared(lineno: int, id_name: str, as_class: CLASS, at_lineno: int):
error(lineno, f"'{id_name}' already declared as {as_class} at {at_lineno}")
# ----------------------------------------
# Can't declare a mandatory parameter after an optional one
# ----------------------------------------
def syntax_error_mandatory_param_after_optional(lineno: int, param1: str, param2: str):
error(lineno, f"Can't declare mandatory param '{param2}' after optional param '{param1}'")
# ----------------------------------------
# FOR without NEXT
# ----------------------------------------
def syntax_error_for_without_next(lineno: int):
error(lineno, "FOR without NEXT")
# ----------------------------------------
# FOR without NEXT
# ----------------------------------------
def syntax_error_loop_not_closed(lineno: int, loop_type: str):
error(lineno, f"{loop_type} loop not closed")
# endregion