Skip to content

Commit cfc9a57

Browse files
authored
Merge pull request #524 from boriel/feature/use-config-file
Isolate config setup into a module
2 parents b261606 + be331d2 commit cfc9a57

21 files changed

Lines changed: 342 additions & 279 deletions

.github/workflows/python-app.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ jobs:
2626
pip install poetry tox
2727
poetry install
2828
- name: Run Tox
29-
run: tox
29+
run: tox -- --no-cov

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ install:
1414
- pip install tox-travis
1515

1616
# command to run tests
17-
script: tox
17+
script: tox -- --no-cov

src/api/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
from src.api import debug # noqa
1313
from src.api import errors # noqa
1414
from src.api import errmsg # noqa
15+
from src.api import utils # noqa

src/api/config.py

Lines changed: 40 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from . import options
2020
from . import global_
2121

22-
from .options import ANYTYPE, Actions
22+
from .options import ANYTYPE, Action
2323

2424

2525
# ------------------------------------------------------
@@ -86,7 +86,7 @@ class OPTION:
8686

8787
def load_config_from_file(filename: str, section: str, options_: options.Options = None, stop_on_error=True) -> bool:
8888
""" Opens file and read options from the given section. If stop_on_error is set,
89-
the program stop. Otherwise the result of the operation will be
89+
the program stop if any error is found. Otherwise the result of the operation will be
9090
returned (True on success, False on failure)
9191
"""
9292
if options_ is None:
@@ -166,63 +166,55 @@ def save_config_into_file(filename: str, section: str, options_: options.Options
166166

167167

168168
def init():
169+
""" Default Options and Compilation Flags
169170
"""
170-
Default Options and Compilation Flags
171-
172-
optimization -- Optimization level. Use -O flag to change.
173-
case_insensitive -- Whether user identifiers are case insensitive
174-
or not
175-
array_base -- Default array lower bound
176-
param_byref --Default parameter passing. TRUE => By Reference
177-
"""
178-
179-
OPTIONS(Actions.CLEAR)
171+
OPTIONS(Action.CLEAR)
180172

181-
OPTIONS(Actions.ADD, name=OPTION.OUTPUT_FILENAME, type=str)
182-
OPTIONS(Actions.ADD, name=OPTION.INPUT_FILENAME, type=str)
183-
OPTIONS(Actions.ADD, name=OPTION.STDERR_FILENAME, type=str)
184-
OPTIONS(Actions.ADD, name=OPTION.DEBUG, type=int, default=0)
173+
OPTIONS(Action.ADD, name=OPTION.OUTPUT_FILENAME, type=str)
174+
OPTIONS(Action.ADD, name=OPTION.INPUT_FILENAME, type=str)
175+
OPTIONS(Action.ADD, name=OPTION.STDERR_FILENAME, type=str, ignore_none=True)
176+
OPTIONS(Action.ADD, name=OPTION.DEBUG, type=int, default=0, ignore_none=True)
185177

186178
# Default console redirections
187-
OPTIONS(Actions.ADD, name=OPTION.STDIN, type=ANYTYPE, default=sys.stdin)
188-
OPTIONS(Actions.ADD, name=OPTION.STDOUT, type=ANYTYPE, default=sys.stdout)
189-
OPTIONS(Actions.ADD, name=OPTION.STDERR, type=ANYTYPE, default=sys.stderr)
179+
OPTIONS(Action.ADD, name=OPTION.STDIN, type=ANYTYPE, default=sys.stdin)
180+
OPTIONS(Action.ADD, name=OPTION.STDOUT, type=ANYTYPE, default=sys.stdout)
181+
OPTIONS(Action.ADD, name=OPTION.STDERR, type=ANYTYPE, default=sys.stderr)
190182

191-
OPTIONS(Actions.ADD, name=OPTION.O_LEVEL, type=int, default=global_.DEFAULT_OPTIMIZATION_LEVEL)
192-
OPTIONS(Actions.ADD, name=OPTION.CASE_INS, type=bool, default=False)
193-
OPTIONS(Actions.ADD, name=OPTION.ARRAY_BASE, type=int, default=0)
194-
OPTIONS(Actions.ADD, name=OPTION.DEFAULT_BYREF, type=bool, default=False)
195-
OPTIONS(Actions.ADD, name=OPTION.MAX_SYN_ERRORS, type=int, default=global_.DEFAULT_MAX_SYNTAX_ERRORS)
196-
OPTIONS(Actions.ADD, name=OPTION.STR_BASE, type=int, default=0)
197-
OPTIONS(Actions.ADD, name=OPTION.MEMORY_MAP, type=str, default=None)
198-
OPTIONS(Actions.ADD, name=OPTION.FORCE_ASM_BRACKET, type=bool, default=False)
183+
OPTIONS(Action.ADD, name=OPTION.O_LEVEL, type=int, default=global_.DEFAULT_OPTIMIZATION_LEVEL, ignore_none=True)
184+
OPTIONS(Action.ADD, name=OPTION.CASE_INS, type=bool, default=False, ignore_none=True)
185+
OPTIONS(Action.ADD, name=OPTION.ARRAY_BASE, type=int, default=0, ignore_none=True)
186+
OPTIONS(Action.ADD, name=OPTION.DEFAULT_BYREF, type=bool, default=False, ignore_none=True)
187+
OPTIONS(Action.ADD, name=OPTION.MAX_SYN_ERRORS, type=int, default=global_.DEFAULT_MAX_SYNTAX_ERRORS)
188+
OPTIONS(Action.ADD, name=OPTION.STR_BASE, type=int, default=0, ignore_none=True)
189+
OPTIONS(Action.ADD, name=OPTION.MEMORY_MAP, type=str, default=None, ignore_none=True)
190+
OPTIONS(Action.ADD, name=OPTION.FORCE_ASM_BRACKET, type=bool, default=False, ignore_none=True)
199191

200-
OPTIONS(Actions.ADD, name=OPTION.USE_BASIC_LOADER, type=bool, default=False) # Whether to use a loader
192+
OPTIONS(Action.ADD, name=OPTION.USE_BASIC_LOADER, type=bool, default=False) # Whether to use a loader
201193

202194
# Whether to add autostart code (needs basic loader = true)
203-
OPTIONS(Actions.ADD, name=OPTION.AUTORUN, type=bool, default=False)
204-
OPTIONS(Actions.ADD, name=OPTION.OUTPUT_FILE_TYPE, type=str, default='bin') # bin, tap, tzx etc...
205-
OPTIONS(Actions.ADD, name=OPTION.INCLUDE_PATH, type=str, default='') # Include path, like '/var/lib:/var/include'
206-
207-
OPTIONS(Actions.ADD, name=OPTION.CHECK_MEMORY, type=bool, default=False)
208-
OPTIONS(Actions.ADD, name=OPTION.STRICT_BOOL, type=bool, default=False)
209-
OPTIONS(Actions.ADD, name=OPTION.CHECK_ARRAYS, type=bool, default=False)
210-
211-
OPTIONS(Actions.ADD, name=OPTION.ENABLE_BREAK, type=bool, default=False)
212-
OPTIONS(Actions.ADD, name=OPTION.EMIT_BACKEND, type=bool, default=False)
213-
OPTIONS(Actions.ADD, name='__DEFINES', type=dict, default={})
214-
OPTIONS(Actions.ADD, name=OPTION.EXPLICIT, type=bool, default=False)
215-
OPTIONS(Actions.ADD, name='sinclair', type=bool, default=False)
216-
OPTIONS(Actions.ADD, name=OPTION.STRICT, type=bool, default=False) # True to force type checking
217-
OPTIONS(Actions.ADD, name=OPTION.ASM_ZXNEXT, type=bool, default=False) # True to enable ZX Next ASM opcodes
218-
OPTIONS(Actions.ADD, name=OPTION.ARCH, type=str, default=None) # Architecture
219-
OPTIONS(Actions.ADD, name=OPTION.EXPECTED_WARNINGS, type=int, default=0) # Expected Warnings that will be silenced
195+
OPTIONS(Action.ADD, name=OPTION.AUTORUN, type=bool, default=False)
196+
OPTIONS(Action.ADD, name=OPTION.OUTPUT_FILE_TYPE, type=str, default='bin') # bin, tap, tzx etc...
197+
OPTIONS(Action.ADD, name=OPTION.INCLUDE_PATH, type=str, default='') # Include path, like '/var/lib:/var/include'
198+
199+
OPTIONS(Action.ADD, name=OPTION.CHECK_MEMORY, type=bool, default=False, ignore_none=True)
200+
OPTIONS(Action.ADD, name=OPTION.STRICT_BOOL, type=bool, default=False, ignore_none=True)
201+
OPTIONS(Action.ADD, name=OPTION.CHECK_ARRAYS, type=bool, default=False, ignore_none=True)
202+
203+
OPTIONS(Action.ADD, name=OPTION.ENABLE_BREAK, type=bool, default=False, ignore_none=True)
204+
OPTIONS(Action.ADD, name=OPTION.EMIT_BACKEND, type=bool, default=False)
205+
OPTIONS(Action.ADD, name='__DEFINES', type=dict, default={})
206+
OPTIONS(Action.ADD, name=OPTION.EXPLICIT, type=bool, default=False, ignore_none=True)
207+
OPTIONS(Action.ADD, name='sinclair', type=bool, default=False)
208+
OPTIONS(Action.ADD, name=OPTION.STRICT, type=bool, default=False, ignore_none=True) # True to force type checking
209+
OPTIONS(Action.ADD, name=OPTION.ASM_ZXNEXT, type=bool, default=False, ignore_none=True) # Enable ZX Next ASM
210+
OPTIONS(Action.ADD, name=OPTION.ARCH, type=str, default=None, ignore_none=True) # Architecture
211+
OPTIONS(Action.ADD, name=OPTION.EXPECTED_WARNINGS, type=int, default=0, ignore_none=True)
220212

221213
# Whether to show WXXX warning codes or not
222-
OPTIONS(Actions.ADD, name=OPTION.HIDE_WARNING_CODES, type=bool, default=False)
214+
OPTIONS(Action.ADD, name=OPTION.HIDE_WARNING_CODES, type=bool, default=False, ignore_none=True)
223215

224-
OPTIONS(Actions.ADD, name=OPTION.PROJECT_FILENAME, type=str, default=os.path.join(os.path.abspath(os.path.curdir),
225-
'project.ini'))
216+
OPTIONS(Action.ADD, name=OPTION.PROJECT_FILENAME, type=str, default=os.path.join(os.path.abspath(os.path.curdir),
217+
'project.ini'))
226218

227219

228220
init()

src/api/options.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from .errors import Error
1919

20-
__all__ = ['Option', 'Options', 'ANYTYPE', 'Actions']
20+
__all__ = ['Option', 'Options', 'ANYTYPE', 'Action']
2121

2222

2323
class ANYTYPE:
@@ -98,9 +98,11 @@ class Option:
9898
""" A simple container for options with optional type checking
9999
on vale assignation.
100100
"""
101-
def __init__(self, name: str, type_, value=None):
101+
def __init__(self, name: str, type_, value=None, ignore_none=False):
102102
self.name = name
103103
self.type = type_
104+
self.ignore_none = ignore_none
105+
self.__value = None
104106
self.value = value
105107
self.stack: List[Any] = [] # An option stack
106108

@@ -110,6 +112,9 @@ def value(self) -> Any:
110112

111113
@value.setter
112114
def value(self, value):
115+
if value is None and self.ignore_none:
116+
return
117+
113118
if value is not None and self.type is not None and not isinstance(value, self.type):
114119
try:
115120
if isinstance(value, str) and self.type == bool:
@@ -156,7 +161,7 @@ def pop(self) -> Any:
156161
# ----------------------------------------------------------------------
157162
# Options commands
158163
# ----------------------------------------------------------------------
159-
class Actions:
164+
class Action:
160165
ADD = 'add'
161166
ADD_IF_NOT_DEFINED = 'add_if_not_defined'
162167
CLEAR = 'clear'
@@ -182,7 +187,7 @@ def __init__(self, init_value=None):
182187
else:
183188
raise InvalidConfigInitialization(invalid_value=init_value)
184189

185-
def __add_option(self, name, type_=None, default=None):
190+
def __add_option(self, name, type_=None, default=None, ignore_none=False):
186191
if name in self._options:
187192
raise DuplicatedOptionError(name)
188193

@@ -191,12 +196,12 @@ def __add_option(self, name, type_=None, default=None):
191196
elif type_ is ANYTYPE:
192197
type_ = None
193198

194-
self._options[name] = Option(name, type_, default)
199+
self._options[name] = Option(name, type_, default, ignore_none)
195200

196-
def __add_option_if_not_defined(self, name, type_=None, default=None):
201+
def __add_option_if_not_defined(self, name, type_=None, default=None, ignore_none=False):
197202
if name in self._options:
198203
return
199-
self.__add_option(name, type_, default)
204+
self.__add_option(name, type_, default, ignore_none)
200205

201206
def __delattr__(self, item: str):
202207
del self[item]
@@ -250,33 +255,39 @@ def check_allowed_args(action: str, kwargs_, allowed_args, required_args=None):
250255

251256
# With no parameters
252257
if not kwargs:
253-
if not args or args == (Actions.LIST, ):
258+
if not args or args == (Action.LIST,):
254259
return {x: y for x, y in self._options.items()}
255260

256-
assert args, f"Missing one action of {', '.join(Actions.allowed)}"
257-
assert len(args) == 1 and args[0] in Actions.allowed, \
258-
f"Only one action of {', '.join(Actions.allowed)} can be specified"
261+
assert args, f"Missing one action of {', '.join(Action.allowed)}"
262+
assert len(args) == 1 and args[0] in Action.allowed, \
263+
f"Only one action of {', '.join(Action.allowed)} can be specified"
259264

260265
# clear
261-
if args[0] == Actions.CLEAR:
262-
check_allowed_args(Actions.CLEAR, kwargs, {})
266+
if args[0] == Action.CLEAR:
267+
check_allowed_args(Action.CLEAR, kwargs, {})
263268
self._options.clear()
264269
return
265270

266271
# list
267-
if args[0] == Actions.LIST:
268-
check_allowed_args(Actions.LIST, kwargs, {'options'})
272+
if args[0] == Action.LIST:
273+
check_allowed_args(Action.LIST, kwargs, {'options'})
269274
options = set(kwargs['options'])
270275
return {x: y for x, y in self._options.items() if x in options}
271276

272-
if args[0] == Actions.ADD:
277+
if args[0] == Action.ADD:
273278
kwargs['type'] = kwargs.get('type')
274279
kwargs['default'] = kwargs.get('default')
275-
check_allowed_args(Actions.ADD, kwargs, {'name', 'type', 'default'}, ['name'])
276-
self.__add_option(kwargs['name'], kwargs['type'], kwargs['default'])
280+
kwargs['ignore_none'] = kwargs.get('ignore_none', False)
281+
check_allowed_args(Action.ADD, kwargs, {'name', 'type', 'default', 'ignore_none'}, ['name'])
282+
kwargs['type_'] = kwargs['type']
283+
del kwargs['type']
284+
self.__add_option(**kwargs)
277285

278-
if args[0] == Actions.ADD_IF_NOT_DEFINED:
286+
if args[0] == Action.ADD_IF_NOT_DEFINED:
279287
kwargs['type'] = kwargs.get('type')
280288
kwargs['default'] = kwargs.get('default')
281-
check_allowed_args(Actions.ADD, kwargs, {'name', 'type', 'default'}, ['name'])
282-
self.__add_option_if_not_defined(kwargs['name'], kwargs['type'], kwargs['default'])
289+
kwargs['ignore_none'] = kwargs.get('ignore_none', False)
290+
check_allowed_args(Action.ADD, kwargs, {'name', 'type', 'default', 'ignore_none'}, ['name'])
291+
kwargs['type_'] = kwargs['type']
292+
del kwargs['type']
293+
self.__add_option_if_not_defined(**kwargs)

src/arch/zx48k/backend/__init__.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
# External functions
9696
from ..optimizer.helpers import HI16, LO16
9797
from src.arch.zx48k.optimizer.asm import Asm
98-
from src.api.config import OPTIONS, Actions
98+
from src.api.config import OPTIONS, Action
9999
from src.arch.zx48k.peephole import engine
100100

101101
import src.api.fp
@@ -134,10 +134,10 @@
134134
FLAG_end_emitted = False
135135

136136
# Default code ORG
137-
OPTIONS(Actions.ADD_IF_NOT_DEFINED, name='org', type=int, default=32768)
137+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name='org', type=int, default=32768)
138138

139139
# Default HEAP SIZE (Dynamic memory) in bytes
140-
OPTIONS(Actions.ADD_IF_NOT_DEFINED, name='heap_size', type=int, default=4768) # A bit more than 4K
140+
OPTIONS(Action.ADD_IF_NOT_DEFINED, name='heap_size', type=int, default=4768) # A bit more than 4K
141141

142142
# List of modules (in alphabetical order) that, if included, should call MEM_INIT
143143
MEMINITS = {
@@ -196,15 +196,15 @@ def init():
196196
FLAG_end_emitted = False
197197

198198
# Default code ORG
199-
OPTIONS(Actions.ADD, name='org', type=int, default=32768)
199+
OPTIONS(Action.ADD, name='org', type=int, default=32768)
200200
# Default HEAP SIZE (Dynamic memory) in bytes
201-
OPTIONS(Actions.ADD, name='heap_size', type=int, default=4768) # A bit more than 4K
201+
OPTIONS(Action.ADD, name='heap_size', type=int, default=4768, ignore_none=True) # A bit more than 4K
202202
# Labels for HEAP START (might not be used if not needed)
203-
OPTIONS(Actions.ADD, name='heap_start_label', type=str, default=f'{NAMESPACE}.ZXBASIC_MEM_HEAP')
203+
OPTIONS(Action.ADD, name='heap_start_label', type=str, default=f'{NAMESPACE}.ZXBASIC_MEM_HEAP')
204204
# Labels for HEAP SIZE (might not be used if not needed)
205-
OPTIONS(Actions.ADD, name='heap_size_label', type=str, default=f'{NAMESPACE}.ZXBASIC_HEAP_SIZE')
205+
OPTIONS(Action.ADD, name='heap_size_label', type=str, default=f'{NAMESPACE}.ZXBASIC_HEAP_SIZE')
206206
# Flag for headerless mode (No prologue / epilogue)
207-
OPTIONS(Actions.ADD, name='headerless', type=bool, default=False)
207+
OPTIONS(Action.ADD, name='headerless', type=bool, default=False, ignore_none=True)
208208

209209
engine.main() # inits the optimizer
210210

src/outfmt/codeemitter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,4 @@
1515
class CodeEmitter(object):
1616
""" The base code emission interface.
1717
"""
18-
1918
pass

0 commit comments

Comments
 (0)