Skip to content

Commit 68cc93d

Browse files
committed
Refact module dependency for check
To reduce cyclic imports, let's use genera imports instead of from ... import.
1 parent a4af079 commit 68cc93d

1 file changed

Lines changed: 52 additions & 64 deletions

File tree

src/api/check.py

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
# the GNU General License
1010
# ----------------------------------------------------------------------
1111

12-
import src.api.errmsg
12+
import src.api.errmsg as errmsg
13+
import src.symbols as symbols
1314

14-
from . import config
15-
from . import global_
15+
from src.symbols.type_ import Type
1616

1717
from .constants import CLASS
1818
from .constants import SCOPE
19-
from .errmsg import error
2019

20+
from . import config
21+
from . import global_
2122

2223
__all__ = ['check_type',
2324
'check_is_declared_explicit',
@@ -43,7 +44,6 @@
4344
# These functions trigger syntax errors if checking goal fails.
4445
# ----------------------------------------------------------------------
4546

46-
4747
def check_type(lineno, type_list, arg):
4848
""" Check arg's type is one in type_list, otherwise,
4949
raises an error.
@@ -55,16 +55,16 @@ def check_type(lineno, type_list, arg):
5555
return True
5656

5757
if len(type_list) == 1:
58-
error(lineno, "Wrong expression type '%s'. Expected '%s'" %
59-
(arg.type_, type_list[0]))
58+
errmsg.error(lineno, "Wrong expression type '%s'. Expected '%s'" %
59+
(arg.type_, type_list[0]))
6060
else:
61-
error(lineno, "Wrong expression type '%s'. Expected one of '%s'"
62-
% (arg.type_, tuple(type_list)))
61+
errmsg.error(lineno, "Wrong expression type '%s'. Expected one of '%s'"
62+
% (arg.type_, tuple(type_list)))
6363

6464
return False
6565

6666

67-
def check_is_declared_explicit(lineno, id_, classname='variable'):
67+
def check_is_declared_explicit(lineno: int, id_: str, classname: str = 'variable'):
6868
""" Check if the current ID is already declared.
6969
If not, triggers a "undeclared identifier" error,
7070
if the --explicit command line flag is enabled (or #pragma
@@ -80,14 +80,13 @@ def check_is_declared_explicit(lineno, id_, classname='variable'):
8080

8181

8282
def check_type_is_explicit(lineno: int, id_: str, type_):
83-
from src.symbols.type_ import SymbolTYPE
84-
assert isinstance(type_, SymbolTYPE)
83+
assert isinstance(type_, symbols.TYPE)
8584
if type_.implicit:
8685
if config.OPTIONS.strict:
87-
src.api.errmsg.syntax_error_undeclared_type(lineno, id_)
86+
errmsg.syntax_error_undeclared_type(lineno, id_)
8887

8988

90-
def check_call_arguments(lineno, id_, args):
89+
def check_call_arguments(lineno: int, id_: str, args):
9190
""" Check arguments against function signature.
9291
9392
Checks every argument in a function call against a function.
@@ -103,26 +102,25 @@ def check_call_arguments(lineno, id_, args):
103102

104103
if len(args) != len(entry.params):
105104
c = 's' if len(entry.params) != 1 else ''
106-
error(lineno, "Function '%s' takes %i parameter%s, not %i" %
107-
(id_, len(entry.params), c, len(args)))
105+
errmsg.error(lineno, "Function '%s' takes %i parameter%s, not %i" %
106+
(id_, len(entry.params), c, len(args)))
108107
return False
109108

110109
for arg, param in zip(args, entry.params):
111110
if arg.class_ in (CLASS.var, CLASS.array) and param.class_ != arg.class_:
112-
error(lineno, "Invalid argument '{}'".format(arg.value))
111+
errmsg.error(lineno, "Invalid argument '{}'".format(arg.value))
113112
return None
114113

115114
if not arg.typecast(param.type_):
116115
return False
117116

118117
if param.byref:
119-
from src.symbols.var import SymbolVAR
120-
if not isinstance(arg.value, SymbolVAR):
121-
error(lineno, "Expected a variable name, not an expression (parameter By Reference)")
118+
if not isinstance(arg.value, symbols.VAR):
119+
errmsg.error(lineno, "Expected a variable name, not an expression (parameter By Reference)")
122120
return False
123121

124122
if arg.class_ not in (CLASS.var, CLASS.array):
125-
error(lineno, "Expected a variable or array name (parameter By Reference)")
123+
errmsg.error(lineno, "Expected a variable or array name (parameter By Reference)")
126124
return False
127125

128126
arg.byref = True
@@ -131,7 +129,7 @@ def check_call_arguments(lineno, id_, args):
131129
arg.value.add_required_symbol(param)
132130

133131
if entry.forwarded: # The function / sub was DECLARED but not implemented
134-
error(lineno, "%s '%s' declared but not implemented" % (CLASS.to_string(entry.class_), entry.name))
132+
errmsg.error(lineno, "%s '%s' declared but not implemented" % (CLASS.to_string(entry.class_), entry.name))
135133
return False
136134

137135
return True
@@ -175,8 +173,7 @@ def check_pending_labels(ast):
175173

176174
tmp = global_.SYMBOL_TABLE.get_entry(node.name)
177175
if tmp is None or tmp.class_ is CLASS.unknown:
178-
error(node.lineno, 'Undeclared identifier "%s"'
179-
% node.name)
176+
errmsg.error(node.lineno, f'Undeclared identifier "{node.name}"')
180177
else:
181178
assert tmp.class_ == CLASS.label
182179
node.to_label(node)
@@ -197,7 +194,7 @@ def check_and_make_label(lbl, lineno):
197194
if lbl == int(lbl):
198195
id_ = str(int(lbl))
199196
else:
200-
error(lineno, 'Line numbers must be integers.')
197+
errmsg.error(lineno, 'Line numbers must be integers.')
201198
return None
202199
else:
203200
id_ = lbl
@@ -208,16 +205,14 @@ def check_and_make_label(lbl, lineno):
208205
# ----------------------------------------------------------------------
209206
# Function for checking some arguments
210207
# ----------------------------------------------------------------------
211-
def is_null(*symbols):
208+
def is_null(*symbols_):
212209
""" True if no nodes or all the given nodes are either
213210
None, NOP or empty blocks. For blocks this applies recursively
214211
"""
215-
from src.symbols.symbol_ import Symbol
216-
217-
for sym in symbols:
212+
for sym in symbols_:
218213
if sym is None:
219214
continue
220-
if not isinstance(sym, Symbol):
215+
if not isinstance(sym, symbols.SYMBOL):
221216
return False
222217
if sym.token == 'NOP':
223218
continue
@@ -229,14 +224,12 @@ def is_null(*symbols):
229224
return True
230225

231226

232-
def is_SYMBOL(token, *symbols):
227+
def is_SYMBOL(token, *symbols_):
233228
""" Returns True if ALL of the given argument are AST nodes
234229
of the given token (e.g. 'BINARY')
235230
"""
236-
from src.symbols.symbol_ import Symbol
237-
238-
assert all(isinstance(x, Symbol) for x in symbols)
239-
return all(sym.token == token for sym in symbols)
231+
assert all(isinstance(x, symbols.SYMBOL) for x in symbols_)
232+
return all(sym.token == token for sym in symbols_)
240233

241234

242235
def is_LABEL(*p):
@@ -290,8 +283,6 @@ def is_var(*p):
290283

291284

292285
def is_integer(*p):
293-
from src.symbols.type_ import Type
294-
295286
try:
296287
return all(i.is_basic and Type.is_integral(i.type_) for i in p)
297288
except Exception:
@@ -303,8 +294,6 @@ def is_integer(*p):
303294
def is_unsigned(*p):
304295
""" Returns false unless all types in p are unsigned
305296
"""
306-
from src.symbols.type_ import Type
307-
308297
try:
309298
return all(i.type_.is_basic and Type.is_unsigned(i.type_) for i in p)
310299
except Exception:
@@ -316,8 +305,6 @@ def is_unsigned(*p):
316305
def is_signed(*p):
317306
""" Returns false unless all types in p are signed
318307
"""
319-
from src.symbols.type_ import Type
320-
321308
try:
322309
return all(i.type_.is_basic and Type.is_signed(i.type_) for i in p)
323310
except Exception:
@@ -329,8 +316,6 @@ def is_signed(*p):
329316
def is_numeric(*p):
330317
""" Returns false unless all elements in p are of numerical type
331318
"""
332-
from src.symbols.type_ import Type
333-
334319
try:
335320
return all(i.type_.is_basic and Type.is_numeric(i.type_) for i in p)
336321
except Exception:
@@ -354,8 +339,6 @@ def is_dynamic(*p): # TODO: Explain this better
354339
""" True if all args are dynamic (e.g. Strings, dynamic arrays, etc)
355340
The use a ptr (ref) and it might change during runtime.
356341
"""
357-
from src.symbols.type_ import Type
358-
359342
try:
360343
return not any(i.scope == SCOPE.global_ and i.is_basic and i.type_ != Type.string for i in p)
361344
except Exception:
@@ -367,7 +350,6 @@ def is_dynamic(*p): # TODO: Explain this better
367350
def is_callable(*p):
368351
""" True if all the args are functions and / or subroutines
369352
"""
370-
from src import symbols
371353
return all(isinstance(x, symbols.FUNCTION) for x in p)
372354

373355

@@ -393,29 +375,25 @@ def common_type(a, b):
393375
""" Returns a type which is common for both a and b types.
394376
Returns None if no common types allowed.
395377
"""
396-
from src.symbols.type_ import SymbolBASICTYPE as BASICTYPE
397-
from src.symbols.type_ import Type as TYPE
398-
from src.symbols.type_ import SymbolTYPE
399-
400378
if a is None or b is None:
401379
return None
402380

403-
if not isinstance(a, SymbolTYPE):
381+
if not isinstance(a, symbols.TYPE):
404382
a = a.type_
405383

406-
if not isinstance(b, SymbolTYPE):
384+
if not isinstance(b, symbols.TYPE):
407385
b = b.type_
408386

409387
if a == b: # Both types are the same?
410388
return a # Returns it
411389

412-
if a == TYPE.unknown and b == TYPE.unknown:
413-
return BASICTYPE(global_.DEFAULT_TYPE)
390+
if a == Type.unknown and b == Type.unknown:
391+
return symbols.BASICTYPE(global_.DEFAULT_TYPE)
414392

415-
if a == TYPE.unknown:
393+
if a == Type.unknown:
416394
return b
417395

418-
if b == TYPE.unknown:
396+
if b == Type.unknown:
419397
return a
420398

421399
# TODO: This will removed / expanded in the future
@@ -424,18 +402,28 @@ def common_type(a, b):
424402

425403
types = (a, b)
426404

427-
if TYPE.float_ in types:
428-
return TYPE.float_
405+
if Type.float_ in types:
406+
return Type.float_
429407

430-
if TYPE.fixed in types:
431-
return TYPE.fixed
408+
if Type.fixed in types:
409+
return Type.fixed
432410

433-
if TYPE.string in types: # TODO: Check this ??
434-
return TYPE.unknown
411+
if Type.string in types: # TODO: Check this ??
412+
return Type.unknown
435413

436414
result = a if a.size > b.size else b
437415

438-
if not TYPE.is_unsigned(a) or not TYPE.is_unsigned(b):
439-
result = TYPE.to_signed(result)
416+
if not Type.is_unsigned(a) or not Type.is_unsigned(b):
417+
result = Type.to_signed(result)
440418

441419
return result
420+
421+
422+
def is_ender(node) -> bool:
423+
""" Returns whether this node ends a block, that is, the following instruction won't be
424+
executed after this one
425+
"""
426+
return node.token in {'END', 'ERROR',
427+
'CONTINUE_DO', 'CONTINUE_FOR', 'CONTINUE_WHILE',
428+
'EXIT_DO', 'EXIT_FOR', 'EXIT_WHILE',
429+
'GOTO', 'RETURN', 'STOP'}

0 commit comments

Comments
 (0)