Skip to content

Commit 6ecb579

Browse files
committed
Merged in feature/base_org_hexa (pull request #179)
Feature/base org hexa Approved-by: Jose Rodriguez <boriel@gmail.com>
2 parents 1e27377 + 0e1b501 commit 6ecb579

6 files changed

Lines changed: 106 additions & 7 deletions

File tree

api/utils.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,31 @@ def flatten_list(x):
7272
result.extend(flatten_list(l))
7373

7474
return result
75+
76+
77+
def parse_int(str_num):
78+
""" Given an integer number, return its value,
79+
or None if it could not be parsed.
80+
Allowed formats: DECIMAL, HEXA (0xnnn, $nnnn or nnnnh)
81+
:param str_num: (string) the number to be parsed
82+
:return: an integer number or None if it could not be parsedd
83+
"""
84+
str_num = (str_num or "").strip().upper()
85+
if not str_num:
86+
return None
87+
88+
base = 10
89+
if str_num.startswith('0X'):
90+
base = 16
91+
str_num = str_num[2:]
92+
if str_num.endswith('H'):
93+
base = 16
94+
str_num = str_num[:-1]
95+
if str_num.startswith('$'):
96+
base = 16
97+
str_num = str_num[1:]
98+
99+
try:
100+
return int(str_num, base)
101+
except ValueError:
102+
return None

tests/cmdline/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import sys
5+
import os
6+
import os.path
7+
8+
path = os.path.realpath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
9+
sys.path.insert(0, path)

tests/cmdline/empty.bas

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+

tests/cmdline/test_zxb.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import pytest
4+
import zxb
5+
import os
6+
7+
PATH = os.path.realpath(os.path.dirname(os.path.abspath(__file__)))
8+
9+
10+
class EnsureRemoveFile(object):
11+
""" Ensures a filename is removed if exists after
12+
a block of code is executed
13+
"""
14+
def __init__(self, output_file_name):
15+
self.fname = output_file_name
16+
17+
def remove_file(self):
18+
if os.path.isfile(self.fname):
19+
os.unlink(self.fname)
20+
21+
def __enter__(self):
22+
self.remove_file()
23+
24+
def __exit__(self, exc_type, exc_val, exc_tb):
25+
self.remove_file()
26+
27+
28+
@pytest.fixture
29+
def file_bas():
30+
return os.path.join(PATH, 'empty.bas')
31+
32+
33+
@pytest.fixture
34+
def file_bin():
35+
return os.path.join(PATH, 'empty.bin')
36+
37+
38+
def test_compile_only(file_bas, file_bin):
39+
""" Should not generate a file
40+
"""
41+
with EnsureRemoveFile(file_bin):
42+
zxb.main(['--parse-only', file_bas, '-o', file_bin])
43+
assert not os.path.isfile(file_bin), 'Should not create file "empty.bin"'
44+
45+
46+
def test_org_allows_0xnnnn_format(file_bas, file_bin):
47+
""" Should allow hexadecimal format 0x in org
48+
"""
49+
with EnsureRemoveFile(file_bin):
50+
zxb.main(['--parse-only', '--org', '0xC000', file_bas, '-o', file_bin])
51+
assert zxb.OPTIONS.org.value == 0xC000, 'Should set ORG to 0xC000'

tests/functional/test_.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ def flush(self):
1919
sys.stdout.flush()
2020

2121

22-
def process_file(fname):
22+
def process_file(fname, params=None):
23+
if params is None:
24+
params = ['-S', '-q']
25+
2326
try:
2427
current_path = os.path.abspath(os.getcwd())
2528
test.set_temp_dir()
@@ -29,7 +32,7 @@ def process_file(fname):
2932
fname = os.path.basename(fname)
3033
else:
3134
os.chdir(os.path.realpath(os.path.dirname(__file__)))
32-
test.main(['-S', '-q', fname])
35+
test.main(params + [fname])
3336
os.chdir(current_path)
3437
finally:
3538
os.rmdir(test.TEMP_DIR)

zxb.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def main(args=None):
106106
help="Sets the program to be run once loaded")
107107
parser.add_argument('-A', '--asm', action='store_true',
108108
help="Sets output format to asm")
109-
parser.add_argument('-S', '--org', type=int, default=OPTIONS.org.value,
109+
parser.add_argument('-S', '--org', type=str, default=str(OPTIONS.org.value),
110110
help="Start of machine code. By default %i" % OPTIONS.org.value)
111111
parser.add_argument('-e', '--errmsg', type=str, dest='stderr', default=OPTIONS.StdErrFileName.value,
112112
help='Error messages file (standard error console by default)')
@@ -144,6 +144,8 @@ def main(args=None):
144144
parser.add_argument('--headerless', action='store_true',
145145
help='Header-less mode: omit asm prologue and epilogue')
146146
parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(VERSION))
147+
parser.add_argument('--parse-only', action='store_true',
148+
help="Only parses to check for syntax and semantic errors")
147149

148150
options = parser.parse_args(args=args)
149151

@@ -158,7 +160,6 @@ def main(args=None):
158160
OPTIONS.array_base.value = options.array_base
159161
OPTIONS.string_base.value = options.string_base
160162
OPTIONS.Sinclair.value = options.sinclair
161-
OPTIONS.org.value = options.org
162163
OPTIONS.heap_size.value = options.heap_size
163164
OPTIONS.memoryCheck.value = options.debug_memory
164165
OPTIONS.strictBool.value = options.strict_bool or OPTIONS.Sinclair.value
@@ -170,6 +171,10 @@ def main(args=None):
170171
OPTIONS.strict.value = options.strict
171172
OPTIONS.headerless.value = options.headerless
172173

174+
OPTIONS.org.value = api.utils.parse_int(options.org)
175+
if OPTIONS.org.value is None:
176+
parser.error("Invalid --org option '{}'".format(options.org))
177+
173178
if options.defines:
174179
for i in options.defines:
175180
name, val = tuple(i.split('=', 1))
@@ -187,8 +192,9 @@ def main(args=None):
187192

188193
debug.ENABLED = OPTIONS.Debug.value
189194

190-
if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emit_backend) > 1:
191-
parser.error("Options --tap, --tzx, --emit-backend and --asm are mutually exclusive")
195+
if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emit_backend) + \
196+
int(options.parse_only) > 1:
197+
parser.error("Options --tap, --tzx, --emit-backend, --parse-only and --asm are mutually exclusive")
192198
return 3
193199

194200
if options.basic and not options.tzx and not options.tap:
@@ -319,7 +325,7 @@ def main(args=None):
319325
if options.asm: # Only output assembler file
320326
with open_file(OPTIONS.outputFileName.value, 'wt', 'utf-8') as output_file:
321327
output(asm_output, output_file)
322-
else:
328+
elif not options.parse_only:
323329
fout = StringIO()
324330
output(asm_output, fout)
325331
asmparse.assemble(fout.getvalue())

0 commit comments

Comments
 (0)