Skip to content

Commit bec023f

Browse files
authored
Merge pull request #401 from boriel/feature/improve_config_storage_system
Feature/improve config storage system
2 parents f1d7640 + 4bc1719 commit bec023f

30 files changed

Lines changed: 327 additions & 294 deletions

api/check.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def check_is_declared_explicit(lineno, id_, classname='variable'):
6969
7070
If not in strict mode, passes it silently.
7171
"""
72-
if not config.OPTIONS.explicit.value:
72+
if not config.OPTIONS.explicit:
7373
return True
7474

7575
entry = global_.SYMBOL_TABLE.check_is_declared(id_, lineno, classname)
@@ -80,7 +80,7 @@ def check_type_is_explicit(lineno: int, id_: str, type_):
8080
from symbols.type_ import SymbolTYPE
8181
assert isinstance(type_, SymbolTYPE)
8282
if type_.implicit:
83-
if config.OPTIONS.strict.value:
83+
if config.OPTIONS.strict:
8484
api.errmsg.syntax_error_undeclared_type(lineno, id_)
8585

8686

api/debug.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515

1616

1717
def __DEBUG__(msg, level=1):
18-
if level > OPTIONS.Debug.value:
18+
if level > OPTIONS.Debug:
1919
return
2020

2121
line = inspect.getouterframes(inspect.currentframe())[1][2]
2222
fname = os.path.basename(inspect.getouterframes(inspect.currentframe())[1][1])
23-
OPTIONS.stderr.value.write('debug: %s:%i %s\n' % (fname, line, msg))
23+
OPTIONS.stderr.write('debug: %s:%i %s\n' % (fname, line, msg))
2424

2525

2626
def __LINE__():

api/errmsg.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ def msg_output(msg):
2121
if msg in global_.error_msg_cache:
2222
return
2323

24-
OPTIONS.stderr.value.write("%s\n" % msg)
24+
OPTIONS.stderr.write("%s\n" % msg)
2525
global_.error_msg_cache.add(msg)
2626

2727

2828
def info(msg):
29-
if OPTIONS.Debug.value < 1:
29+
if OPTIONS.Debug < 1:
3030
return
31-
OPTIONS.stderr.value.write("info: %s\n" % msg)
31+
OPTIONS.stderr.write("info: %s\n" % msg)
3232

3333

3434
def error(lineno, msg, fname=None):
@@ -37,13 +37,13 @@ def error(lineno, msg, fname=None):
3737
if fname is None:
3838
fname = global_.FILENAME
3939

40-
if global_.has_errors > OPTIONS.max_syntax_errors.value:
40+
if global_.has_errors > OPTIONS.max_syntax_errors:
4141
msg = 'Too many errors. Giving up!'
4242

4343
msg = "%s:%i: error: %s" % (fname, lineno, msg)
4444
msg_output(msg)
4545

46-
if global_.has_errors > OPTIONS.max_syntax_errors.value:
46+
if global_.has_errors > OPTIONS.max_syntax_errors:
4747
sys.exit(1)
4848

4949
global_.has_errors += 1
@@ -63,7 +63,7 @@ def warning(lineno, msg, fname=None):
6363
def warning_implicit_type(lineno, id_, type_=None):
6464
""" Warning: Using default implicit type 'x'
6565
"""
66-
if OPTIONS.strict.value:
66+
if OPTIONS.strict:
6767
syntax_error_undeclared_type(lineno, id_)
6868
return
6969

@@ -99,7 +99,7 @@ def warning_empty_if(lineno):
9999

100100
# Emmits an optimization warning
101101
def warning_not_used(lineno, id_, kind='Variable'):
102-
if OPTIONS.optimization.value > 0:
102+
if OPTIONS.optimization > 0:
103103
warning(lineno, "%s '%s' is never used" % (kind, id_))
104104

105105

api/identityset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def add(self, elem):
1818
self._elems.add(elem)
1919

2020
def remove(self, elem):
21-
""" Removes an element if it exits. Otherwise does nothing.
21+
""" Removes an element if it exists. Otherwise does nothing.
2222
Returns if the element was removed.
2323
"""
2424
if elem in self._elems:

api/optimize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def visit(self, node):
8585

8686
@property
8787
def O_LEVEL(self):
88-
return OPTIONS.optimization.value
88+
return OPTIONS.optimization
8989

9090
def visit_ADDRESS(self, node):
9191
if node.operand.token != 'ARRAYACCESS':

api/options.py

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

12-
from .errors import Error
12+
import json
1313

14-
TRUE = true = True
15-
FALSE = false = False
14+
from typing import Dict
15+
from typing import List
16+
from typing import Any
1617

18+
from .errors import Error
1719

1820
__all__ = ['Option', 'Options', 'ANYTYPE']
1921

2022

21-
class ANYTYPE(object):
23+
class ANYTYPE:
2224
""" Dummy class to signal any value
2325
"""
2426
pass
@@ -64,31 +66,45 @@ def __str__(self):
6466
% (self.value, self.option, self.type)
6567

6668

69+
class InvalidConfigInitialization(Error):
70+
def __init__(self, invalid_value):
71+
self.invalid_value = invalid_value
72+
73+
def __str__(self):
74+
return "Invalid value for config initialization"
75+
76+
6777
# ----------------------------------------------------------------------
6878
# This class interfaces an Options Container
6979
# ----------------------------------------------------------------------
70-
class Option(object):
71-
""" A simple container
80+
class Option:
81+
""" A simple container for options with optional type checking
82+
on vale assignation.
7283
"""
73-
def __init__(self, name, type_, value=None):
84+
def __init__(self, name: str, type_, value=None):
7485
self.name = name
7586
self.type = type_
7687
self.value = value
77-
self.stack = [] # An option stack
88+
self.stack: List[Any] = [] # An option stack
7889

7990
@property
80-
def value(self):
91+
def value(self) -> Any:
8192
return self.__value
8293

8394
@value.setter
8495
def value(self, value):
85-
if self.type is not None and not isinstance(value, self.type):
96+
if value is not None and self.type is not None and not isinstance(value, self.type):
8697
try:
87-
value = eval(value)
98+
if isinstance(value, str) and self.type == bool:
99+
value = {'false': False, 'true': True}[value.lower()]
100+
else:
101+
value = self.type(value)
88102
except TypeError:
89103
pass
90104
except ValueError:
91105
pass
106+
except KeyError:
107+
pass
92108

93109
if value is not None and not isinstance(value, self.type):
94110
raise InvalidValueError(self.name, self.type, value)
@@ -102,63 +118,81 @@ def push(self, value=None):
102118
self.stack.append(self.value)
103119
self.value = value
104120

105-
def pop(self):
106-
result = self.value
107-
108-
try:
109-
self.value = self.stack.pop()
110-
except IndexError:
121+
def pop(self) -> Any:
122+
if not self.stack:
111123
raise OptionStackUnderflowError(self.name)
112124

125+
result = self.value
126+
self.value = self.stack.pop()
113127
return result
114128

115129

116130
# ----------------------------------------------------------------------
117131
# This class interfaces an Options Container
118132
# ----------------------------------------------------------------------
119-
class Options(object):
120-
def __init__(self):
121-
self.options = None
122-
self.reset()
133+
class Options:
134+
""" Class to store config options.
135+
"""
136+
def __init__(self, init_value=None):
137+
self._options: Dict[str, Option] = {}
123138

124-
def reset(self):
125-
if self.options is None:
126-
self.options = {}
139+
if init_value is not None:
140+
if isinstance(init_value, dict):
141+
self._options = init_value
142+
elif isinstance(init_value, str):
143+
self._options = json.loads(init_value)
144+
else:
145+
raise InvalidConfigInitialization(invalid_value=init_value)
127146

128-
for opt in list(self.options.keys()): # converts to list since dict will change size during iteration
129-
self.remove_option(opt)
147+
def reset(self):
148+
self._options.clear()
130149

131150
def add_option(self, name, type_=None, default_value=None):
132-
if name in self.options.keys():
151+
if name in self._options:
133152
raise DuplicatedOptionError(name)
134153

135154
if type_ is None and default_value is not None:
136155
type_ = type(default_value)
137156
elif type_ is ANYTYPE:
138157
type_ = None
139158

140-
self.options[name] = Option(name, type_, default_value)
141-
setattr(self, name, self.options[name])
142-
143-
def has_option(self, name):
144-
""" Returns whether the given option is defined in this class.
145-
"""
146-
return hasattr(self, name)
159+
self._options[name] = Option(name, type_, default_value)
147160

148161
def add_option_if_not_defined(self, name, type_=None, default_value=None):
149-
if self.has_option(name):
162+
if name in self._options:
150163
return
151164
self.add_option(name, type_, default_value)
152165

153-
def remove_option(self, name):
154-
if name not in self.options.keys():
155-
raise UndefinedOptionError(name)
166+
def __delattr__(self, item: str):
167+
del self[item]
168+
169+
def __getattr__(self, item: str):
170+
return self[item].value
171+
172+
def __setattr__(self, key: str, value: Any):
173+
if key == '_options':
174+
self.__dict__[key] = value
175+
return
176+
177+
self[key] = value
178+
179+
def __getitem__(self, item: str) -> Option:
180+
if item not in self._options:
181+
raise UndefinedOptionError(option_name=item)
182+
183+
return self._options[item]
184+
185+
def __delitem__(self, item):
186+
if item not in self._options:
187+
raise UndefinedOptionError(item)
188+
189+
del self._options[item]
156190

157-
del self.options[name]
158-
delattr(self, name)
191+
def __setitem__(self, key: str, value: Any):
192+
if key not in self._options:
193+
raise UndefinedOptionError(option_name=key)
159194

160-
def option(self, name):
161-
if name not in self.options.keys():
162-
raise UndefinedOptionError(name)
195+
self._options[key].value = value
163196

164-
return self.options[name]
197+
def __contains__(self, item: str):
198+
return item in self._options

api/symboltable.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,17 @@ def __delitem__(self, key):
111111
del self.caseins[key.lower()]
112112

113113
def values(self, filter_by_opt=True):
114-
if filter_by_opt and OPTIONS.optimization.value > 1:
114+
if filter_by_opt and OPTIONS.optimization > 1:
115115
return [y for x, y in self.symbols.items() if y.accessed]
116116
return [y for x, y in self.symbols.items()]
117117

118118
def keys(self, filter_by_opt=True):
119-
if filter_by_opt and OPTIONS.optimization.value > 1:
119+
if filter_by_opt and OPTIONS.optimization > 1:
120120
return [x for x, y in self.symbols.items() if y.accessed]
121121
return self.symbols.keys()
122122

123123
def items(self, filter_by_opt=True):
124-
if filter_by_opt and OPTIONS.optimization.value > 1:
124+
if filter_by_opt and OPTIONS.optimization > 1:
125125
return [(x, y) for x, y in self.symbols.items() if y.accessed]
126126
return self.symbols.items()
127127

@@ -183,7 +183,7 @@ def declare(self, id_: str, lineno: int, entry):
183183
if self[self.current_scope][id2] is not None:
184184
return None
185185

186-
entry.caseins = OPTIONS.case_insensitive.value
186+
entry.caseins = OPTIONS.case_insensitive
187187
self[self.current_scope][id2] = entry
188188
entry.name = id2 # Removes DEPRECATED SUFFIXES if any
189189

0 commit comments

Comments
 (0)