Skip to content

Commit 9a6d82a

Browse files
committed
refact: use python Enums for TYPE
Primarty types TYPE now uses Python's Enum. This legacy code cames from Python 2.x and implement its own enum.
1 parent ad4bbc9 commit 9a6d82a

9 files changed

Lines changed: 78 additions & 76 deletions

File tree

src/api/constants.py

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
# the GNU General License
1010
# ----------------------------------------------------------------------
1111

12+
import enum
1213
import os
1314

15+
from typing import Optional
16+
1417
from .decorator import classproperty
1518

1619

@@ -28,7 +31,7 @@
2831
# ----------------------------------------------------------------------
2932

3033

31-
class CLASS(object):
34+
class CLASS:
3235
""" Enums class constants
3336
"""
3437
unknown = 'unknown' # 0
@@ -69,115 +72,114 @@ def to_string(cls, class_):
6972
return cls._CLASS_NAMES[class_]
7073

7174

72-
class ARRAY(object):
75+
class ARRAY:
7376
""" Enums array constants
7477
"""
7578
bound_size = 2 # This might change depending on arch, program, etc..
7679
bound_count = 2 # Size of bounds counter
7780
array_type_size = 1 # Size of array type
7881

7982

80-
class TYPE(object):
81-
""" Enums type constants
83+
@enum.unique
84+
class TYPE(enum.IntEnum):
85+
""" Enums primary type constants
8286
"""
83-
auto = unknown = None
84-
byte_ = 1
87+
unknown = 0
88+
byte = 1
8589
ubyte = 2
8690
integer = 3
8791
uinteger = 4
88-
long_ = 5
92+
long = 5
8993
ulong = 6
9094
fixed = 7
91-
float_ = 8
95+
float = 8
9296
string = 9
9397

94-
TYPE_SIZES = {
95-
byte_: 1, ubyte: 1,
96-
integer: 2, uinteger: 2,
97-
long_: 4, ulong: 4,
98-
fixed: 4, float_: 5,
99-
string: 2, unknown: 0
100-
}
101-
102-
TYPE_NAMES = {
103-
byte_: 'byte', ubyte: 'ubyte',
104-
integer: 'integer', uinteger: 'uinteger',
105-
long_: 'long', ulong: 'ulong',
106-
fixed: 'fixed', float_: 'float',
107-
string: 'string', unknown: 'none'
108-
}
98+
@classmethod
99+
def type_size(cls, type_: 'TYPE'):
100+
type_sizes = {
101+
cls.byte: 1, cls.ubyte: 1,
102+
cls.integer: 2, cls.uinteger: 2,
103+
cls.long: 4, cls.ulong: 4,
104+
cls.fixed: 4, cls.float: 5,
105+
cls.string: 2, cls.unknown: 0
106+
}
107+
return type_sizes[type_]
109108

110109
@classproperty
111110
def types(cls):
112-
return tuple(cls.TYPE_SIZES.keys())
111+
return set(TYPE)
113112

114113
@classmethod
115-
def size(cls, type_):
116-
return cls.TYPE_SIZES.get(type_, None)
114+
def size(cls, type_: 'TYPE'):
115+
return cls.type_size(type_)
117116

118117
@classproperty
119118
def integral(cls):
120-
return (cls.byte_, cls.ubyte, cls.integer, cls.uinteger,
121-
cls.long_, cls.ulong)
119+
return {cls.byte, cls.ubyte, cls.integer, cls.uinteger,
120+
cls.long, cls.ulong}
122121

123122
@classproperty
124123
def signed(cls):
125-
return (cls.byte_, cls.integer, cls.long_, cls.fixed, cls.float_)
124+
return {cls.byte, cls.integer, cls.long, cls.fixed, cls.float}
126125

127126
@classproperty
128127
def unsigned(cls):
129-
return (cls.ubyte, cls.uinteger, cls.ulong)
128+
return {cls.ubyte, cls.uinteger, cls.ulong}
130129

131130
@classproperty
132131
def decimals(cls):
133-
return (cls.fixed, cls.float_)
132+
return {cls.fixed, cls.float}
134133

135134
@classproperty
136135
def numbers(cls):
137-
return tuple(list(cls.integral) + list(cls.decimals))
136+
return set(cls.integral) | set(cls.decimals)
138137

139138
@classmethod
140-
def is_valid(cls, type_):
139+
def is_valid(cls, type_: 'TYPE'):
141140
""" Whether the given type is
142141
valid or not.
143142
"""
144143
return type_ in cls.types
145144

146145
@classmethod
147-
def is_signed(cls, type_):
146+
def is_signed(cls, type_: 'TYPE'):
148147
return type_ in cls.signed
149148

150149
@classmethod
151-
def is_unsigned(cls, type_):
150+
def is_unsigned(cls, type_: 'TYPE'):
152151
return type_ in cls.unsigned
153152

154153
@classmethod
155-
def to_signed(cls, type_):
154+
def to_signed(cls, type_: 'TYPE'):
156155
""" Return signed type or equivalent
157156
"""
158157
if type_ in cls.unsigned:
159-
return {TYPE.ubyte: TYPE.byte_,
158+
return {TYPE.ubyte: TYPE.byte,
160159
TYPE.uinteger: TYPE.integer,
161-
TYPE.ulong: TYPE.long_}[type_]
160+
TYPE.ulong: TYPE.long}[type_]
162161
if type_ in cls.decimals or type_ in cls.signed:
163162
return type_
164163
return cls.unknown
165164

166-
@classmethod
167-
def to_string(cls, type_):
165+
@staticmethod
166+
def to_string(type_: 'TYPE'):
168167
""" Return ID representation (string) of a type
169168
"""
170-
return cls.TYPE_NAMES[type_]
169+
return type_.name
171170

172-
@classmethod
173-
def to_type(cls, typename):
171+
@staticmethod
172+
def to_type(typename: str) -> Optional['TYPE']:
174173
""" Converts a type ID to name. On error returns None
175174
"""
176-
NAME_TYPES = {cls.TYPE_NAMES[x]: x for x in cls.TYPE_NAMES}
177-
return NAME_TYPES.get(typename, None)
175+
for t in TYPE:
176+
if t.name == typename:
177+
return t
178+
179+
return None
178180

179181

180-
class SCOPE(object):
182+
class SCOPE:
181183
""" Enum scopes
182184
"""
183185
unknown = None
@@ -202,7 +204,7 @@ def to_string(cls, scope):
202204
return cls._names[scope]
203205

204206

205-
class KIND(object):
207+
class KIND:
206208
""" Enum kind
207209
"""
208210
unknown = None
@@ -229,7 +231,7 @@ def to_string(cls, kind):
229231
return cls._NAMES.get(kind)
230232

231233

232-
class CONVENTION(object):
234+
class CONVENTION:
233235
unknown = None
234236
fastcall = '__fastcall__'
235237
stdcall = '__stdcall__'
@@ -268,4 +270,4 @@ def to_string(cls, convention):
268270
ID_TYPES = TYPE.types
269271

270272
# Maps deprecated suffixes to types
271-
SUFFIX_TYPE = {'$': TYPE.string, '%': TYPE.integer, '&': TYPE.long_}
273+
SUFFIX_TYPE = {'$': TYPE.string, '%': TYPE.integer, '&': TYPE.long}

src/api/global_.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@
5757
# ----------------------------------------------------------------------
5858
# Default var type when not specified (implicit) an can't be guessed
5959
# ----------------------------------------------------------------------
60-
DEFAULT_TYPE = TYPE.float_
60+
DEFAULT_TYPE = TYPE.float
6161

6262
# ----------------------------------------------------------------------
6363
# Default variable type when not specified in DIM.
6464
# 'auto' => try to guess and if not, fallback to DEFAULT_TYPE
6565
# ----------------------------------------------------------------------
66-
DEFAULT_IMPLICIT_TYPE = TYPE.auto # Use TYPE.auto for smart type guessing
66+
DEFAULT_IMPLICIT_TYPE = TYPE.unknown # Use TYPE.auto for smart type guessing
6767

6868
# ----------------------------------------------------------------------
6969
# Maximum number of errors to report before giving up.

src/api/symboltable.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def access_id(self, id_: str, lineno: int, scope=None, default_type=None, defaul
435435

436436
# The entry was already declared. If it's type is auto and the default type is not None,
437437
# update its type.
438-
if default_type is not None and result.type_ == self.basic_types[TYPE.auto]:
438+
if default_type is not None and result.type_ == self.basic_types[TYPE.unknown]:
439439
result.type_ = default_type
440440
warning_implicit_type(lineno, id_, default_type.name)
441441

@@ -493,8 +493,8 @@ def access_func(self, id_: str, lineno: int, scope=None, default_type=None):
493493
result = self.get_entry(id_, scope)
494494
if result is None:
495495
if default_type is None:
496-
if global_.DEFAULT_IMPLICIT_TYPE == TYPE.auto:
497-
default_type = symbols.TYPEREF(self.basic_types[TYPE.auto], lineno, implicit=True)
496+
if global_.DEFAULT_IMPLICIT_TYPE == TYPE.unknown:
497+
default_type = symbols.TYPEREF(self.basic_types[TYPE.unknown], lineno, implicit=True)
498498
else:
499499
default_type = symbols.TYPEREF(self.basic_types[global_.DEFAULT_TYPE], lineno, implicit=True)
500500

src/arch/zx48k/translator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -844,9 +844,9 @@ def visit_BEEP(self, node):
844844
self.runtime_call(RuntimeLabel.BEEPER, 0) # Procedure call. Discard return
845845
else:
846846
yield node.children[1]
847-
self.ic_param(TYPE.float_, node.children[1].t)
847+
self.ic_param(TYPE.float, node.children[1].t)
848848
yield node.children[0]
849-
self.ic_fparam(TYPE.float_, node.children[0].t)
849+
self.ic_fparam(TYPE.float, node.children[0].t)
850850
self.runtime_call(RuntimeLabel.BEEP, 0)
851851

852852
def visit_PAUSE(self, node):
@@ -985,7 +985,7 @@ def default_value(cls, type_, expr): # TODO: This function must be moved to api
985985
assert check.is_static(expr)
986986

987987
if isinstance(expr, (symbols.CONST, symbols.VAR)): # a constant expression like @label + 1
988-
if type_ in (cls.TYPE(TYPE.float_), cls.TYPE(TYPE.string)):
988+
if type_ in (cls.TYPE(TYPE.float), cls.TYPE(TYPE.string)):
989989
error(expr.lineno, "Can't convert non-numeric value to {0} at compile time".format(type_.name))
990990
return ['<ERROR>']
991991

@@ -1008,7 +1008,7 @@ def default_value(cls, type_, expr): # TODO: This function must be moved to api
10081008
# U/Long
10091009
return ['##({0}) & 0xFFFF'.format(val), '##(({0}) >> 16) & 0xFFFF'.format(val)]
10101010

1011-
if type_ == cls.TYPE(TYPE.float_):
1011+
if type_ == cls.TYPE(TYPE.float):
10121012
C, DE, HL = _float(expr.value)
10131013
C = C[:-1] # Remove 'h' suffix
10141014
if len(C) > 2:
@@ -1242,7 +1242,7 @@ def visit_CHR(self, node):
12421242
self.runtime_call(RuntimeLabel.CHR, node.size)
12431243

12441244
def visit_STR(self, node):
1245-
self.ic_fparam(TYPE.float_, node.children[0].t)
1245+
self.ic_fparam(TYPE.float, node.children[0].t)
12461246
self.runtime_call(RuntimeLabel.STR_FAST, node.type_.size)
12471247

12481248
def visit_LEN(self, node):

src/arch/zx48k/translatorinstvisitor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ def emit(*args):
2121
def TSUFFIX(type_):
2222
assert isinstance(type_, symbols.TYPE) or TYPE.is_valid(type_)
2323

24-
_TSUFFIX = {TYPE.byte_: 'i8', TYPE.ubyte: 'u8',
24+
_TSUFFIX = {TYPE.byte: 'i8', TYPE.ubyte: 'u8',
2525
TYPE.integer: 'i16', TYPE.uinteger: 'u16',
26-
TYPE.long_: 'i32', TYPE.ulong: 'u32',
27-
TYPE.fixed: 'f16', TYPE.float_: 'f',
26+
TYPE.long: 'i32', TYPE.ulong: 'u32',
27+
TYPE.fixed: 'f16', TYPE.float: 'f',
2828
TYPE.string: 'str'
2929
}
3030

src/arch/zx48k/translatorvisitor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ def emit_data_blocks(self):
144144
for d in datas:
145145
if isinstance(d, symbols.FUNCDECL):
146146
type_ = '%02Xh' % (self.DATA_TYPES[self.TSUFFIX(d.type_)] | 0x80)
147-
self.ic_data(TYPE.byte_, [type_])
147+
self.ic_data(TYPE.byte, [type_])
148148
self.ic_data(gl.PTR_TYPE, [d.mangled])
149149
continue
150150

151-
self.ic_data(TYPE.byte_, [self.DATA_TYPES[self.TSUFFIX(d.value.type_)]])
151+
self.ic_data(TYPE.byte, [self.DATA_TYPES[self.TSUFFIX(d.value.type_)]])
152152
if d.value.type_ == self.TYPE(TYPE.string):
153153
lbl = self.add_string_label(d.value.value)
154154
self.ic_data(gl.PTR_TYPE, [lbl])

src/symbols/type_.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,13 @@ class Type(object):
235235
"""
236236
unknown = auto = SymbolBASICTYPE(TYPE.unknown)
237237
ubyte = SymbolBASICTYPE(TYPE.ubyte)
238-
byte_ = SymbolBASICTYPE(TYPE.byte_)
238+
byte_ = SymbolBASICTYPE(TYPE.byte)
239239
uinteger = SymbolBASICTYPE(TYPE.uinteger)
240-
long_ = SymbolBASICTYPE(TYPE.long_)
240+
long_ = SymbolBASICTYPE(TYPE.long)
241241
ulong = SymbolBASICTYPE(TYPE.ulong)
242242
integer = SymbolBASICTYPE(TYPE.integer)
243243
fixed = SymbolBASICTYPE(TYPE.fixed)
244-
float_ = SymbolBASICTYPE(TYPE.float_)
244+
float_ = SymbolBASICTYPE(TYPE.float)
245245
string = SymbolBASICTYPE(TYPE.string)
246246

247247
types = [unknown,

tests/api/test_symbolTable.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def test_declare_variable_dupl_suffix(self):
7575
"(stdin):11: error: Variable 'a%' already declared at (stdin):10\n")
7676

7777
def test_declare_variable_wrong_suffix(self):
78-
self.s.declare_variable('b%', 12, self.btyperef(TYPE.byte_))
78+
self.s.declare_variable('b%', 12, self.btyperef(TYPE.byte))
7979
self.assertEqual(self.OUTPUT,
8080
"(stdin):12: error: 'b%' suffix is for type 'integer' but it was declared as 'byte'\n")
8181

@@ -127,37 +127,37 @@ def test_enter_scope(self):
127127

128128
def test_declare_local_var(self):
129129
self.s.enter_scope('testfunction')
130-
self.s.declare_variable('a', 12, self.btyperef(TYPE.float_))
130+
self.s.declare_variable('a', 12, self.btyperef(TYPE.float))
131131
self.assertTrue(self.s.check_is_declared('a', 11, scope=self.s.current_scope))
132132
self.assertEqual(self.s.get_entry('a').scope, SCOPE.local)
133133

134134
def test_declare_array(self):
135-
self.s.declare_array('test', lineno=1, type_=self.btyperef(TYPE.byte_), bounds=self.bounds)
135+
self.s.declare_array('test', lineno=1, type_=self.btyperef(TYPE.byte), bounds=self.bounds)
136136

137137
def test_declare_array_fail(self):
138138
# type_ must by an instance of symbols.TYPEREF
139-
self.assertRaises(AssertionError, self.s.declare_array, 'test', 1, TYPE.byte_, self.bounds)
139+
self.assertRaises(AssertionError, self.s.declare_array, 'test', 1, TYPE.byte, self.bounds)
140140

141141
def test_declare_array_fail2(self):
142142
# bounds must by an instance of symbols.BOUNDLIST
143-
self.assertRaises(AssertionError, self.s.declare_array, 'test', 1, self.btyperef(TYPE.byte_),
143+
self.assertRaises(AssertionError, self.s.declare_array, 'test', 1, self.btyperef(TYPE.byte),
144144
'bla')
145145

146146
def test_declare_local_array(self):
147147
""" the logic for declaring a local array differs from
148148
local scalar variables
149149
"""
150150
self.s.enter_scope('testfunction')
151-
self.s.declare_array('a', 12, self.btyperef(TYPE.float_),
151+
self.s.declare_array('a', 12, self.btyperef(TYPE.float),
152152
symbols.BOUNDLIST(symbols.BOUND(0, 2)))
153153
self.assertTrue(self.s.check_is_declared('a', 11, scope=self.s.current_scope))
154154
self.assertEqual(self.s.get_entry('a').scope, SCOPE.local)
155155

156156
def test_declare_local_var_dup(self):
157157
self.s.enter_scope('testfunction')
158-
self.s.declare_variable('a', 12, self.btyperef(TYPE.float_))
158+
self.s.declare_variable('a', 12, self.btyperef(TYPE.float))
159159
# Now checks for duplicated name 'a'
160-
self.s.declare_variable('a', 14, self.btyperef(TYPE.float_))
160+
self.s.declare_variable('a', 14, self.btyperef(TYPE.float))
161161
self.assertEqual(self.OUTPUT,
162162
"(stdin):14: error: Variable 'a' already declared at (stdin):12\n")
163163

tests/symbols/test_symbolNUMBER.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def test__init__(self):
1919
self.assertEqual(n.type_, BASICTYPE(TYPE.ubyte))
2020

2121
n = NUMBER(-1, lineno=1)
22-
self.assertEqual(n.type_, BASICTYPE(TYPE.byte_))
22+
self.assertEqual(n.type_, BASICTYPE(TYPE.byte))
2323

2424
n = NUMBER(256, lineno=1)
2525
self.assertEqual(n.type_, BASICTYPE(TYPE.uinteger))

0 commit comments

Comments
 (0)