oaknut-basic 12.17.1__tar.gz → 12.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/PKG-INFO +8 -8
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/README.md +7 -7
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/__init__.py +1 -1
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/cli.py +2 -2
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/detect.py +2 -6
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/dialect.py +1 -3
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/exceptions.py +2 -6
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/float5.py +1 -3
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/tokeniser.py +1 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/PKG-INFO +8 -8
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_data_cli.py +1 -3
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_detect.py +1 -1
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_greedy_crunch.py +1 -3
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_keyword_coverage.py +3 -1
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_numbering.py +2 -2
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_packaging.py +1 -3
- oaknut_basic-12.18.0/tests/test_rom_golden.py +100 -0
- oaknut_basic-12.18.0/tests/test_rom_golden_detokenise.py +54 -0
- oaknut_basic-12.17.1/tests/test_rom_golden.py +0 -100
- oaknut_basic-12.17.1/tests/test_rom_golden_detokenise.py +0 -51
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/LICENSE +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/pyproject.toml +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/setup.cfg +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/datafile.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/detokeniser.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/linenumber.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/numbering.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/scanner.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut/basic/tokens.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/SOURCES.txt +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/dependency_links.txt +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/entry_points.txt +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/requires.txt +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/top_level.txt +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_basic.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_basic_v.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_cli.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_crunch_rules.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_datafile.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_detokeniser.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_float5.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_linenumber.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_scanner.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_tokeniser.py +0 -0
- {oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/tests/test_tokens.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oaknut-basic
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.18.0
|
|
4
4
|
Summary: BBC BASIC tools: program tokeniser/de-tokeniser and PRINT#/INPUT# data-file reader/writer
|
|
5
5
|
Author-email: Robert Smallshire <robert@smallshire.org.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -131,9 +131,9 @@ Programs are handled by the functions `tokenise`, `detokenise`, and
|
|
|
131
131
|
```python
|
|
132
132
|
from oaknut.basic import tokenise, detokenise
|
|
133
133
|
|
|
134
|
-
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10\n')
|
|
135
|
-
listing = detokenise(program)
|
|
136
|
-
assert tokenise(detokenise(program)) == program
|
|
134
|
+
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10\n') # str -> bytes
|
|
135
|
+
listing = detokenise(program) # bytes -> str
|
|
136
|
+
assert tokenise(detokenise(program)) == program # byte-exact
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
When the program lives in a disc image, prefer the path-object wrappers
|
|
@@ -150,12 +150,12 @@ polymorphic `write` picks the record type from the Python value; typed
|
|
|
150
150
|
from oaknut.basic import datafile
|
|
151
151
|
|
|
152
152
|
with datafile.open("scores.dat", "w") as f:
|
|
153
|
-
f.write("ALICE")
|
|
154
|
-
f.write(42)
|
|
155
|
-
f.write(3.5)
|
|
153
|
+
f.write("ALICE") # str -> string record
|
|
154
|
+
f.write(42) # int -> integer record
|
|
155
|
+
f.write(3.5) # float -> real record
|
|
156
156
|
|
|
157
157
|
with datafile.open("scores.dat", "r") as f:
|
|
158
|
-
for value in f:
|
|
158
|
+
for value in f: # yields "ALICE", 42, 3.5
|
|
159
159
|
print(value)
|
|
160
160
|
```
|
|
161
161
|
|
|
@@ -107,9 +107,9 @@ Programs are handled by the functions `tokenise`, `detokenise`, and
|
|
|
107
107
|
```python
|
|
108
108
|
from oaknut.basic import tokenise, detokenise
|
|
109
109
|
|
|
110
|
-
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10\n')
|
|
111
|
-
listing = detokenise(program)
|
|
112
|
-
assert tokenise(detokenise(program)) == program
|
|
110
|
+
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10\n') # str -> bytes
|
|
111
|
+
listing = detokenise(program) # bytes -> str
|
|
112
|
+
assert tokenise(detokenise(program)) == program # byte-exact
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
When the program lives in a disc image, prefer the path-object wrappers
|
|
@@ -126,12 +126,12 @@ polymorphic `write` picks the record type from the Python value; typed
|
|
|
126
126
|
from oaknut.basic import datafile
|
|
127
127
|
|
|
128
128
|
with datafile.open("scores.dat", "w") as f:
|
|
129
|
-
f.write("ALICE")
|
|
130
|
-
f.write(42)
|
|
131
|
-
f.write(3.5)
|
|
129
|
+
f.write("ALICE") # str -> string record
|
|
130
|
+
f.write(42) # int -> integer record
|
|
131
|
+
f.write(3.5) # float -> real record
|
|
132
132
|
|
|
133
133
|
with datafile.open("scores.dat", "r") as f:
|
|
134
|
-
for value in f:
|
|
134
|
+
for value in f: # yields "ALICE", 42, 3.5
|
|
135
135
|
print(value)
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -217,8 +217,8 @@ def _listing_to_bytes(listing: str, encoding: str) -> bytes:
|
|
|
217
217
|
type=click.Choice(["rom", "greedy"]),
|
|
218
218
|
default="rom",
|
|
219
219
|
show_default=True,
|
|
220
|
-
help=
|
|
221
|
-
|
|
220
|
+
help='Which tokeniser to emulate. "rom" is byte-exact to the BBC BASIC '
|
|
221
|
+
'ROM. Use "greedy" to reproduce the greedier third-party tokeniser '
|
|
222
222
|
"behind some early-1980s commercial programs, so their de-tokenised "
|
|
223
223
|
"source re-tokenises byte-identically.",
|
|
224
224
|
)
|
|
@@ -162,8 +162,7 @@ def detect(data: bytes | bytearray) -> Detection:
|
|
|
162
162
|
if line_count == 0:
|
|
163
163
|
return Detection(
|
|
164
164
|
Verdict.NOT_BASIC,
|
|
165
|
-
f"&0D &{marker:02X} at offset 0 — terminator with no lines, "
|
|
166
|
-
"not a program",
|
|
165
|
+
f"&0D &{marker:02X} at offset 0 — terminator with no lines, not a program",
|
|
167
166
|
)
|
|
168
167
|
program_length = pos + 2
|
|
169
168
|
trailing = n - program_length
|
|
@@ -195,10 +194,7 @@ def detect(data: bytes | bytearray) -> Detection:
|
|
|
195
194
|
line_no = (marker << 8) | data[pos + 2]
|
|
196
195
|
length = data[pos + 3]
|
|
197
196
|
if length < HEADER_LENGTH:
|
|
198
|
-
return broke(
|
|
199
|
-
f"line {line_no} at offset {pos} has length {length} "
|
|
200
|
-
f"(< {HEADER_LENGTH})"
|
|
201
|
-
)
|
|
197
|
+
return broke(f"line {line_no} at offset {pos} has length {length} (< {HEADER_LENGTH})")
|
|
202
198
|
if pos + length > n:
|
|
203
199
|
return broke(f"line {line_no} at offset {pos} runs {length} bytes past end of data")
|
|
204
200
|
|
|
@@ -142,9 +142,7 @@ _BASIC_V_SINGLE_BYTE_OVERRIDES = {
|
|
|
142
142
|
# (so a bare prefix never resolves to AUTO/DELETE/LOAD), then apply the
|
|
143
143
|
# re-purposed single-byte slots.
|
|
144
144
|
_basic_v_single_byte = {
|
|
145
|
-
token: keyword
|
|
146
|
-
for token, keyword in TOKEN_TO_KEYWORD.items()
|
|
147
|
-
if token not in (0xC6, 0xC7, 0xC8)
|
|
145
|
+
token: keyword for token, keyword in TOKEN_TO_KEYWORD.items() if token not in (0xC6, 0xC7, 0xC8)
|
|
148
146
|
}
|
|
149
147
|
_basic_v_single_byte.update(_BASIC_V_SINGLE_BYTE_OVERRIDES)
|
|
150
148
|
|
|
@@ -96,8 +96,7 @@ class LineNumberRangeError(TokeniseError):
|
|
|
96
96
|
|
|
97
97
|
def __init__(self, line_index: int, line_number: int, line_text: str) -> None:
|
|
98
98
|
super().__init__(
|
|
99
|
-
f"line {line_index}: line number {line_number} is out of range "
|
|
100
|
-
f"(0-{MAX_LINE_NUMBER})",
|
|
99
|
+
f"line {line_index}: line number {line_number} is out of range (0-{MAX_LINE_NUMBER})",
|
|
101
100
|
line_index=line_index,
|
|
102
101
|
line_text=line_text,
|
|
103
102
|
)
|
|
@@ -300,10 +299,7 @@ class IntegerRangeError(DataFileError):
|
|
|
300
299
|
"""
|
|
301
300
|
|
|
302
301
|
def __init__(self, value: int) -> None:
|
|
303
|
-
super().__init__(
|
|
304
|
-
f"{value} is out of range for a BBC integer "
|
|
305
|
-
f"(must be -2**31 .. 2**31 - 1)"
|
|
306
|
-
)
|
|
302
|
+
super().__init__(f"{value} is out of range for a BBC integer (must be -2**31 .. 2**31 - 1)")
|
|
307
303
|
self.value = value
|
|
308
304
|
|
|
309
305
|
|
|
@@ -58,9 +58,7 @@ def unpack_float5(packed: bytes) -> float:
|
|
|
58
58
|
return 0.0
|
|
59
59
|
sign_and_msb = packed[1]
|
|
60
60
|
negative = bool(sign_and_msb & 0x80)
|
|
61
|
-
significand = (
|
|
62
|
-
((sign_and_msb | 0x80) << 24) | (packed[2] << 16) | (packed[3] << 8) | packed[4]
|
|
63
|
-
)
|
|
61
|
+
significand = ((sign_and_msb | 0x80) << 24) | (packed[2] << 16) | (packed[3] << 8) | packed[4]
|
|
64
62
|
value = math.ldexp(significand, exponent - _EXPONENT_FOLD)
|
|
65
63
|
return -value if negative else value
|
|
66
64
|
|
|
@@ -72,6 +72,7 @@ Crunch = Literal["rom", "greedy"]
|
|
|
72
72
|
def _split_source_lines(source: str) -> list[str]:
|
|
73
73
|
return LINE_SEPARATOR_RE.split(source)
|
|
74
74
|
|
|
75
|
+
|
|
75
76
|
# Keyword entries grouped by first character, preserving ROM order within
|
|
76
77
|
# each group, so the crunch only scans the relevant group.
|
|
77
78
|
_KEYWORDS_BY_FIRST: dict[str, list[tuple[str, int, int]]] = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oaknut-basic
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.18.0
|
|
4
4
|
Summary: BBC BASIC tools: program tokeniser/de-tokeniser and PRINT#/INPUT# data-file reader/writer
|
|
5
5
|
Author-email: Robert Smallshire <robert@smallshire.org.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -131,9 +131,9 @@ Programs are handled by the functions `tokenise`, `detokenise`, and
|
|
|
131
131
|
```python
|
|
132
132
|
from oaknut.basic import tokenise, detokenise
|
|
133
133
|
|
|
134
|
-
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10\n')
|
|
135
|
-
listing = detokenise(program)
|
|
136
|
-
assert tokenise(detokenise(program)) == program
|
|
134
|
+
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10\n') # str -> bytes
|
|
135
|
+
listing = detokenise(program) # bytes -> str
|
|
136
|
+
assert tokenise(detokenise(program)) == program # byte-exact
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
When the program lives in a disc image, prefer the path-object wrappers
|
|
@@ -150,12 +150,12 @@ polymorphic `write` picks the record type from the Python value; typed
|
|
|
150
150
|
from oaknut.basic import datafile
|
|
151
151
|
|
|
152
152
|
with datafile.open("scores.dat", "w") as f:
|
|
153
|
-
f.write("ALICE")
|
|
154
|
-
f.write(42)
|
|
155
|
-
f.write(3.5)
|
|
153
|
+
f.write("ALICE") # str -> string record
|
|
154
|
+
f.write(42) # int -> integer record
|
|
155
|
+
f.write(3.5) # float -> real record
|
|
156
156
|
|
|
157
157
|
with datafile.open("scores.dat", "r") as f:
|
|
158
|
-
for value in f:
|
|
158
|
+
for value in f: # yields "ALICE", 42, 3.5
|
|
159
159
|
print(value)
|
|
160
160
|
```
|
|
161
161
|
|
|
@@ -58,9 +58,7 @@ class TestEncode:
|
|
|
58
58
|
|
|
59
59
|
def test_encode_pound_sign_uses_acorn(self, tmp_path):
|
|
60
60
|
out = tmp_path / "out.dat"
|
|
61
|
-
result = CliRunner().invoke(
|
|
62
|
-
cli, ["data", "encode", "-", str(out)], input=json.dumps(["£"])
|
|
63
|
-
)
|
|
61
|
+
result = CliRunner().invoke(cli, ["data", "encode", "-", str(out)], input=json.dumps(["£"]))
|
|
64
62
|
assert result.exit_code == 0, result.output
|
|
65
63
|
# 00 (string tag) 01 (length) 60 (pound) — single char, reversal a no-op.
|
|
66
64
|
assert out.read_bytes() == bytes.fromhex("000160")
|
|
@@ -23,7 +23,7 @@ def _program(*lines: tuple[int, bytes]) -> bytes:
|
|
|
23
23
|
|
|
24
24
|
class TestClean:
|
|
25
25
|
def test_tokenised_program_is_basic(self):
|
|
26
|
-
program = tokenise(
|
|
26
|
+
program = tokenise('10 PRINT "HELLO"\n20 GOTO 10')
|
|
27
27
|
result = detect(program)
|
|
28
28
|
assert result.verdict is Verdict.BASIC
|
|
29
29
|
assert result.is_basic
|
|
@@ -61,9 +61,7 @@ _VECTORS = [
|
|
|
61
61
|
# Rule 2 — an FN/PROC name breaks at a FLAG_START keyword (THEN/ELSE).
|
|
62
62
|
(
|
|
63
63
|
"IFA THENPROCWTKEYELSEPROCBKKEY",
|
|
64
|
-
bytes.fromhex(
|
|
65
|
-
"e7 41 20 8c f2 57 54 4b 45 59 45 4c 53 45 50 52 4f 43 42 4b 4b 45 59"
|
|
66
|
-
),
|
|
64
|
+
bytes.fromhex("e7 41 20 8c f2 57 54 4b 45 59 45 4c 53 45 50 52 4f 43 42 4b 4b 45 59"),
|
|
67
65
|
bytes.fromhex("e7 41 20 8c f2 57 54 4b 45 59 8b f2 42 4b 4b 45 59"),
|
|
68
66
|
),
|
|
69
67
|
# Rule 2 — a function keyword embedded in a name is not a break point.
|
|
@@ -66,7 +66,9 @@ def test_every_keyword_tokenises_to_its_token(keyword, token, flags):
|
|
|
66
66
|
assert _body(prefix + keyword) == prefix.encode("latin-1") + bytes([token])
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
@pytest.mark.parametrize(
|
|
69
|
+
@pytest.mark.parametrize(
|
|
70
|
+
("keyword", "token"), [(kw, t) for kw, t, _f in KEYWORDS], ids=_ids(KEYWORDS)
|
|
71
|
+
)
|
|
70
72
|
def test_every_token_detokenises_to_its_keyword(keyword, token):
|
|
71
73
|
program = b"\x0d\x00\x0a\x05" + bytes([token]) + b"\x0d\xff"
|
|
72
74
|
assert detokenise(program) == f"10{keyword}\n"
|
|
@@ -16,8 +16,8 @@ _DATA_DIRPATH = Path(__file__).parent / "data"
|
|
|
16
16
|
|
|
17
17
|
class TestNumberLines:
|
|
18
18
|
def test_numbers_each_line_from_ten_in_tens(self):
|
|
19
|
-
source =
|
|
20
|
-
assert basic.number_lines(source) ==
|
|
19
|
+
source = 'PRINT "Hello"\nEND'
|
|
20
|
+
assert basic.number_lines(source) == '10 PRINT "Hello"\n20 END'
|
|
21
21
|
|
|
22
22
|
def test_custom_step(self):
|
|
23
23
|
source = "A\nB\nC"
|
|
@@ -48,9 +48,7 @@ def test_console_script_is_declared():
|
|
|
48
48
|
|
|
49
49
|
def test_cli_dependencies_are_unconditional():
|
|
50
50
|
unconditional = _unconditional_requirements()
|
|
51
|
-
missing = [
|
|
52
|
-
name for name in _CLI_REQUIREMENTS if name.lower() not in unconditional
|
|
53
|
-
]
|
|
51
|
+
missing = [name for name in _CLI_REQUIREMENTS if name.lower() not in unconditional]
|
|
54
52
|
assert not missing, (
|
|
55
53
|
f"{_DISTRIBUTION} ships a console script but these imports of "
|
|
56
54
|
f"oaknut.basic.cli are not unconditional dependencies: {missing}. "
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Golden tokeniser vectors from the genuine BBC BASIC II ROM.
|
|
2
|
+
|
|
3
|
+
Generated by scripts (basictool's 6502 emulation of the BASIC II ROM)
|
|
4
|
+
and committed as static data: the ROM is the authority for what the
|
|
5
|
+
tokeniser must produce, and this test holds it to that. basictool is
|
|
6
|
+
NOT a test dependency — regenerate with scripts/gen_rom_golden.py if the
|
|
7
|
+
vector set changes.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from oaknut.basic import tokenise
|
|
12
|
+
|
|
13
|
+
# (source after the line number, tokenised body the ROM produces).
|
|
14
|
+
_GOLDEN = [
|
|
15
|
+
('PRINT "Hi"', b' \xf1 "Hi"'),
|
|
16
|
+
("END", b" \xe0"),
|
|
17
|
+
("GOTO 100", b" \xe5 \x8dDd@"),
|
|
18
|
+
("FOR I=1 TO 10 STEP 2", b" \xe3 I=1 \xb8 10 \x88 2"),
|
|
19
|
+
("NEXT I", b" \xed I"),
|
|
20
|
+
("REPEAT", b" \xf5"),
|
|
21
|
+
("UNTIL X>5", b" \xfd X>5"),
|
|
22
|
+
("IF A=1 THEN PRINT A", b" \xe7 A=1 \x8c \xf1 A"),
|
|
23
|
+
("X=INT(RND(1)*6)+1", b" X=\xa8(\xb3(1)*6)+1"),
|
|
24
|
+
("PROCdraw(x%,y%)", b" \xf2draw(x%,y%)"),
|
|
25
|
+
("DEF PROCgbpb(A$,T%)", b" \xdd \xf2gbpb(A$,T%)"),
|
|
26
|
+
("DEF FNsq(x)=x*x", b" \xdd \xa4sq(x)=x*x"),
|
|
27
|
+
("=FNsq(3)", b" =\xa4sq(3)"),
|
|
28
|
+
("P.", b" \xf1"),
|
|
29
|
+
("PR.", b" \xf1"),
|
|
30
|
+
("PRO.", b" \xf2"),
|
|
31
|
+
("F.", b" \xe3"),
|
|
32
|
+
("N.", b" \xed"),
|
|
33
|
+
("G.100", b" \xe5\x8dDd@"),
|
|
34
|
+
("REP.", b" \xf5"),
|
|
35
|
+
("AND0", b" \x80\x8dT@@"),
|
|
36
|
+
("TO1", b" \xb8\x8dTA@"),
|
|
37
|
+
("PRINT1", b" \xf11"),
|
|
38
|
+
("DIV9", b" \x81\x8dTI@"),
|
|
39
|
+
("SIN1", b" \xb5\x8dTA@"),
|
|
40
|
+
("TAB(1", b" \x8a\x8dTA@"),
|
|
41
|
+
("X=2", b" X=2"),
|
|
42
|
+
("5", b" \x8dTE@"),
|
|
43
|
+
("GOTO0", b" \xe5\x8dT@@"),
|
|
44
|
+
("GOTO1", b" \xe5\x8dTA@"),
|
|
45
|
+
("GOTO 10", b" \xe5 \x8dTJ@"),
|
|
46
|
+
("GOTO 32767", b" \xe5 \x8d`\x7f\x7f"),
|
|
47
|
+
("GOSUB 100", b" \xe4 \x8dDd@"),
|
|
48
|
+
("RESTORE 100,200", b" \xf7 \x8dDd@,\x8ddH@"),
|
|
49
|
+
("ON X GOTO 10,20,30", b" \xee X \xe5 \x8dTJ@,\x8dTT@,\x8dT^@"),
|
|
50
|
+
("IF A THEN 100 ELSE 200", b" \xe7 A \x8c \x8dDd@ \x8b \x8ddH@"),
|
|
51
|
+
("GOTO X", b" \xe5 X"),
|
|
52
|
+
("GOTO -5", b" \xe5 -5"),
|
|
53
|
+
("RESTORE", b" \xf7"),
|
|
54
|
+
("TRACE 500", b" \xfc \x8ddtA"),
|
|
55
|
+
("RENUMBER 100,10", b" \xcc \x8dDd@,\x8dTJ@"),
|
|
56
|
+
("PAGE=&2000", b" \xd0=&2000"),
|
|
57
|
+
("X=PAGE", b" X=\x90"),
|
|
58
|
+
("PRINT PAGE", b" \xf1 \x90"),
|
|
59
|
+
("TIME=0", b" \xd1=0"),
|
|
60
|
+
("X=TIME", b" X=\x91"),
|
|
61
|
+
("PTR#3=0", b" \xcf#3=0"),
|
|
62
|
+
("X=PTR#3", b" X=\x8f#3"),
|
|
63
|
+
("HIMEM=&7C00", b" \xd3=&7C00"),
|
|
64
|
+
("LOMEM=PAGE", b" \xd2=\x90"),
|
|
65
|
+
("? ERR PAGE", b" ? \x9f \x90"),
|
|
66
|
+
("GET$;,PTR", b" \xbe;,\x8f"),
|
|
67
|
+
("INSTR(A$,B$) PTR", b" \xa7A$,B$) \x8f"),
|
|
68
|
+
("OPENOUT LOMEM", b" \xae \xd2"),
|
|
69
|
+
("SQR RAD PTR", b" \xb6 \xb2 \xcf"),
|
|
70
|
+
("RND * SQR ENDPROC", b" \xb3 * SQR ENDPROC"),
|
|
71
|
+
('A$="he""llo"', b' A$="he""llo"'),
|
|
72
|
+
('PRINT "GOTO 10"', b' \xf1 "GOTO 10"'),
|
|
73
|
+
("X=&FF+&1A2B", b" X=&FF+&1A2B"),
|
|
74
|
+
("Y=1.5E3+.25", b" Y=1.5E3+.25"),
|
|
75
|
+
('PRINT "unterminated GOTO', b' \xf1 "unterminated GOTO'),
|
|
76
|
+
("REM this has PRINT GOTO 10", b" \xf4 this has PRINT GOTO 10"),
|
|
77
|
+
("DATA 1,2,PRINT,3:X=4", b" \xdc 1,2,PRINT,3:X=4"),
|
|
78
|
+
("*CAT", b" *CAT"),
|
|
79
|
+
("*FX 21,0", b" *FX 21,0"),
|
|
80
|
+
("X=3*4", b" X=3*4"),
|
|
81
|
+
("PRINT~&FF", b" \xf1~&FF"),
|
|
82
|
+
("VDU 26,12;0;", b" \xef 26,12;0;"),
|
|
83
|
+
("TIMER", b" TIMER"),
|
|
84
|
+
("TRUEELSE", b" TRUEELSE"),
|
|
85
|
+
("GDIV40", b" GDIV40"),
|
|
86
|
+
("TOTAL", b" \xb8TAL"),
|
|
87
|
+
("DIVMOD", b" \x81\x83"),
|
|
88
|
+
("TRUE+", b" \xb9+"),
|
|
89
|
+
("text%?p%=ASC(MID$(A$,i%,1))", b" text%?p%=\x97(\xc1A$,i%,1))"),
|
|
90
|
+
("?(a%+1)=&FF", b" ?(a%+1)=&FF"),
|
|
91
|
+
("A=1:B=2:PRINT A,B", b" A=1:B=2:\xf1 A,B"),
|
|
92
|
+
("COLOUR 129:CLS", b" \xfb 129:\xdb"),
|
|
93
|
+
("MODE 7:VDU 23", b" \xeb 7:\xef 23"),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@pytest.mark.parametrize(("source", "expected_body"), _GOLDEN, ids=[v[0] for v in _GOLDEN])
|
|
98
|
+
def test_tokenises_like_the_basic_ii_rom(source, expected_body):
|
|
99
|
+
program = tokenise("10 " + source)
|
|
100
|
+
assert program[4 : program[3]] == expected_body
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Golden de-tokeniser vectors from the genuine BBC BASIC II ROM.
|
|
2
|
+
|
|
3
|
+
Generated by scripts/gen_rom_detok_golden.py from basictool's 6502
|
|
4
|
+
emulation of the BASIC II ROM and committed as static data: the ROM's
|
|
5
|
+
LIST output is the authority for what de-tokenising must produce (the
|
|
6
|
+
expected text is rebuilt in our plain line-number style from the ROM's
|
|
7
|
+
LIST bodies). basictool is NOT a test dependency.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from oaknut.basic import detokenise
|
|
12
|
+
|
|
13
|
+
# (tokenised program bytes, expected de-tokenised text).
|
|
14
|
+
_GOLDEN = [
|
|
15
|
+
(b'\r\x00\n\x16 \xf1 "Hello, world!"\r\xff', '10 PRINT "Hello, world!"\n'),
|
|
16
|
+
(b"\r\x00\n\x0b \xe5 \x8dDd@\r\xff", "10 GOTO 100\n"),
|
|
17
|
+
(b"\r\x00\n\r \xe4 \x8ddH@:\xf8\r\xff", "10 GOSUB 200:RETURN\n"),
|
|
18
|
+
(b"\r\x00\n\x19 \xee X \xe5 \x8dTJ@,\x8dTT@,\x8dT^@\r\xff", "10 ON X GOTO 10,20,30\n"),
|
|
19
|
+
(b"\r\x00\n\x18 \xe7 A=1 \x8c \x8dTr@ \x8b \x8dT|@\r\xff", "10 IF A=1 THEN 50 ELSE 60\n"),
|
|
20
|
+
(b"\r\x00\n\x11 \xf7 \x8dDd@:\xf3 A,B\r\xff", "10 RESTORE 100:READ A,B\n"),
|
|
21
|
+
(b"\r\x00\n\x17 \xe3 I=1 \xb8 10 \x88 2:\xed I\r\xff", "10 FOR I=1 TO 10 STEP 2:NEXT I\n"),
|
|
22
|
+
(b"\r\x00\n\x0c \xf5:\xfd X>5\r\xff", "10 REPEAT:UNTIL X>5\n"),
|
|
23
|
+
(b"\r\x00\n\x0c \xd0=&2000\r\xff", "10 PAGE=&2000\n"),
|
|
24
|
+
(b"\r\x00\n\x08 X=\x90\r\xff", "10 X=PAGE\n"),
|
|
25
|
+
(b"\r\x00\n\n \xcf#3=0\r\xff", "10 PTR#3=0\n"),
|
|
26
|
+
(b"\r\x00\n\x0c \xd1=0:X=\x91\r\xff", "10 TIME=0:X=TIME\n"),
|
|
27
|
+
(b"\r\x00\n\x10 \xd3=&7C00:\xd2=\x90\r\xff", "10 HIMEM=&7C00:LOMEM=PAGE\n"),
|
|
28
|
+
(b'\r\x00\n\x15 A$=\xbd(34)+"quote"\r\xff', '10 A$=CHR$(34)+"quote"\n'),
|
|
29
|
+
(b'\r\x00\n\x1d \xf1 "GOTO 10 is text here"\r\xff', '10 PRINT "GOTO 10 is text here"\n'),
|
|
30
|
+
(b"\r\x00\n\x16 X=&FF+&1A2B \x80 &F0\r\xff", "10 X=&FF+&1A2B AND &F0\n"),
|
|
31
|
+
(b"\r\x00\n\x10 Y=1.5E3+.25\r\xff", "10 Y=1.5E3+.25\n"),
|
|
32
|
+
(
|
|
33
|
+
b"\r\x00\n$ \xf4 this REM has PRINT GOTO in it\r\xff",
|
|
34
|
+
"10 REM this REM has PRINT GOTO in it\n",
|
|
35
|
+
),
|
|
36
|
+
(b"\r\x00\n\x18 \xdc 1,2,PRINT,3,hello\r\xff", "10 DATA 1,2,PRINT,3,hello\n"),
|
|
37
|
+
(b"\r\x00\n\t *CAT\r\xff", "10 *CAT\n"),
|
|
38
|
+
(b"\r\x00\n\x14 \xef 23,255;0;0;0;\r\xff", "10 VDU 23,255;0;0;0;\n"),
|
|
39
|
+
(b"\r\x00\n\x13 \xf2draw(x%,y%):\xe1\r\xff", "10 PROCdraw(x%,y%):ENDPROC\n"),
|
|
40
|
+
(b"\r\x00\n\x11 \xdd \xa4sq(x)=x*x\r\xff", "10 DEF FNsq(x)=x*x\n"),
|
|
41
|
+
(b"\r\x00\n\x11 L%=\xa9(A$)+\xb1-\x9c\r\xff", "10 L%=LEN(A$)+POS-COUNT\n"),
|
|
42
|
+
(b"\r\x00\n\x12 X=\xa8(\xb3(1)*6)+1\r\xff", "10 X=INT(RND(1)*6)+1\n"),
|
|
43
|
+
(b"\r\x00\n\n \xf1~&AB\r\xff", "10 PRINT~&AB\n"),
|
|
44
|
+
(b"\r\x00\n\x14 @%=&90A:\xf1 \x8a5);X\r\xff", "10 @%=&90A:PRINT TAB(5);X\n"),
|
|
45
|
+
(b"\r\x00\n\x12 \xfb 129:\xe6 0,1:\xdb\r\xff", "10 COLOUR 129:GCOL 0,1:CLS\n"),
|
|
46
|
+
(b"\r\x00\n\x10 \xeb 7:\xf1'\x8a10)'\r\xff", "10 MODE 7:PRINT'TAB(10)'\n"),
|
|
47
|
+
(b"\r\x00\n\x17 ?(addr%+1)=base%?2\r\xff", "10 ?(addr%+1)=base%?2\n"),
|
|
48
|
+
(b'\r\x00\n\x19 \xf1 "unterminated GOTO\r\xff', '10 PRINT "unterminated GOTO\n'),
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.mark.parametrize(("program", "expected"), _GOLDEN, ids=range(len(_GOLDEN)))
|
|
53
|
+
def test_detokenises_like_the_basic_ii_rom(program, expected):
|
|
54
|
+
assert detokenise(program) == expected
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"""Golden tokeniser vectors from the genuine BBC BASIC II ROM.
|
|
2
|
-
|
|
3
|
-
Generated by scripts (basictool's 6502 emulation of the BASIC II ROM)
|
|
4
|
-
and committed as static data: the ROM is the authority for what the
|
|
5
|
-
tokeniser must produce, and this test holds it to that. basictool is
|
|
6
|
-
NOT a test dependency — regenerate with scripts/gen_rom_golden.py if the
|
|
7
|
-
vector set changes.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import pytest
|
|
11
|
-
from oaknut.basic import tokenise
|
|
12
|
-
|
|
13
|
-
# (source after the line number, tokenised body the ROM produces).
|
|
14
|
-
_GOLDEN = [
|
|
15
|
-
('PRINT "Hi"', b' \xf1 "Hi"'),
|
|
16
|
-
('END', b' \xe0'),
|
|
17
|
-
('GOTO 100', b' \xe5 \x8dDd@'),
|
|
18
|
-
('FOR I=1 TO 10 STEP 2', b' \xe3 I=1 \xb8 10 \x88 2'),
|
|
19
|
-
('NEXT I', b' \xed I'),
|
|
20
|
-
('REPEAT', b' \xf5'),
|
|
21
|
-
('UNTIL X>5', b' \xfd X>5'),
|
|
22
|
-
('IF A=1 THEN PRINT A', b' \xe7 A=1 \x8c \xf1 A'),
|
|
23
|
-
('X=INT(RND(1)*6)+1', b' X=\xa8(\xb3(1)*6)+1'),
|
|
24
|
-
('PROCdraw(x%,y%)', b' \xf2draw(x%,y%)'),
|
|
25
|
-
('DEF PROCgbpb(A$,T%)', b' \xdd \xf2gbpb(A$,T%)'),
|
|
26
|
-
('DEF FNsq(x)=x*x', b' \xdd \xa4sq(x)=x*x'),
|
|
27
|
-
('=FNsq(3)', b' =\xa4sq(3)'),
|
|
28
|
-
('P.', b' \xf1'),
|
|
29
|
-
('PR.', b' \xf1'),
|
|
30
|
-
('PRO.', b' \xf2'),
|
|
31
|
-
('F.', b' \xe3'),
|
|
32
|
-
('N.', b' \xed'),
|
|
33
|
-
('G.100', b' \xe5\x8dDd@'),
|
|
34
|
-
('REP.', b' \xf5'),
|
|
35
|
-
('AND0', b' \x80\x8dT@@'),
|
|
36
|
-
('TO1', b' \xb8\x8dTA@'),
|
|
37
|
-
('PRINT1', b' \xf11'),
|
|
38
|
-
('DIV9', b' \x81\x8dTI@'),
|
|
39
|
-
('SIN1', b' \xb5\x8dTA@'),
|
|
40
|
-
('TAB(1', b' \x8a\x8dTA@'),
|
|
41
|
-
('X=2', b' X=2'),
|
|
42
|
-
('5', b' \x8dTE@'),
|
|
43
|
-
('GOTO0', b' \xe5\x8dT@@'),
|
|
44
|
-
('GOTO1', b' \xe5\x8dTA@'),
|
|
45
|
-
('GOTO 10', b' \xe5 \x8dTJ@'),
|
|
46
|
-
('GOTO 32767', b' \xe5 \x8d`\x7f\x7f'),
|
|
47
|
-
('GOSUB 100', b' \xe4 \x8dDd@'),
|
|
48
|
-
('RESTORE 100,200', b' \xf7 \x8dDd@,\x8ddH@'),
|
|
49
|
-
('ON X GOTO 10,20,30', b' \xee X \xe5 \x8dTJ@,\x8dTT@,\x8dT^@'),
|
|
50
|
-
('IF A THEN 100 ELSE 200', b' \xe7 A \x8c \x8dDd@ \x8b \x8ddH@'),
|
|
51
|
-
('GOTO X', b' \xe5 X'),
|
|
52
|
-
('GOTO -5', b' \xe5 -5'),
|
|
53
|
-
('RESTORE', b' \xf7'),
|
|
54
|
-
('TRACE 500', b' \xfc \x8ddtA'),
|
|
55
|
-
('RENUMBER 100,10', b' \xcc \x8dDd@,\x8dTJ@'),
|
|
56
|
-
('PAGE=&2000', b' \xd0=&2000'),
|
|
57
|
-
('X=PAGE', b' X=\x90'),
|
|
58
|
-
('PRINT PAGE', b' \xf1 \x90'),
|
|
59
|
-
('TIME=0', b' \xd1=0'),
|
|
60
|
-
('X=TIME', b' X=\x91'),
|
|
61
|
-
('PTR#3=0', b' \xcf#3=0'),
|
|
62
|
-
('X=PTR#3', b' X=\x8f#3'),
|
|
63
|
-
('HIMEM=&7C00', b' \xd3=&7C00'),
|
|
64
|
-
('LOMEM=PAGE', b' \xd2=\x90'),
|
|
65
|
-
('? ERR PAGE', b' ? \x9f \x90'),
|
|
66
|
-
('GET$;,PTR', b' \xbe;,\x8f'),
|
|
67
|
-
('INSTR(A$,B$) PTR', b' \xa7A$,B$) \x8f'),
|
|
68
|
-
('OPENOUT LOMEM', b' \xae \xd2'),
|
|
69
|
-
('SQR RAD PTR', b' \xb6 \xb2 \xcf'),
|
|
70
|
-
('RND * SQR ENDPROC', b' \xb3 * SQR ENDPROC'),
|
|
71
|
-
('A$="he""llo"', b' A$="he""llo"'),
|
|
72
|
-
('PRINT "GOTO 10"', b' \xf1 "GOTO 10"'),
|
|
73
|
-
('X=&FF+&1A2B', b' X=&FF+&1A2B'),
|
|
74
|
-
('Y=1.5E3+.25', b' Y=1.5E3+.25'),
|
|
75
|
-
('PRINT "unterminated GOTO', b' \xf1 "unterminated GOTO'),
|
|
76
|
-
('REM this has PRINT GOTO 10', b' \xf4 this has PRINT GOTO 10'),
|
|
77
|
-
('DATA 1,2,PRINT,3:X=4', b' \xdc 1,2,PRINT,3:X=4'),
|
|
78
|
-
('*CAT', b' *CAT'),
|
|
79
|
-
('*FX 21,0', b' *FX 21,0'),
|
|
80
|
-
('X=3*4', b' X=3*4'),
|
|
81
|
-
('PRINT~&FF', b' \xf1~&FF'),
|
|
82
|
-
('VDU 26,12;0;', b' \xef 26,12;0;'),
|
|
83
|
-
('TIMER', b' TIMER'),
|
|
84
|
-
('TRUEELSE', b' TRUEELSE'),
|
|
85
|
-
('GDIV40', b' GDIV40'),
|
|
86
|
-
('TOTAL', b' \xb8TAL'),
|
|
87
|
-
('DIVMOD', b' \x81\x83'),
|
|
88
|
-
('TRUE+', b' \xb9+'),
|
|
89
|
-
('text%?p%=ASC(MID$(A$,i%,1))', b' text%?p%=\x97(\xc1A$,i%,1))'),
|
|
90
|
-
('?(a%+1)=&FF', b' ?(a%+1)=&FF'),
|
|
91
|
-
('A=1:B=2:PRINT A,B', b' A=1:B=2:\xf1 A,B'),
|
|
92
|
-
('COLOUR 129:CLS', b' \xfb 129:\xdb'),
|
|
93
|
-
('MODE 7:VDU 23', b' \xeb 7:\xef 23'),
|
|
94
|
-
]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@pytest.mark.parametrize(("source", "expected_body"), _GOLDEN, ids=[v[0] for v in _GOLDEN])
|
|
98
|
-
def test_tokenises_like_the_basic_ii_rom(source, expected_body):
|
|
99
|
-
program = tokenise("10 " + source)
|
|
100
|
-
assert program[4 : program[3]] == expected_body
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"""Golden de-tokeniser vectors from the genuine BBC BASIC II ROM.
|
|
2
|
-
|
|
3
|
-
Generated by scripts/gen_rom_detok_golden.py from basictool's 6502
|
|
4
|
-
emulation of the BASIC II ROM and committed as static data: the ROM's
|
|
5
|
-
LIST output is the authority for what de-tokenising must produce (the
|
|
6
|
-
expected text is rebuilt in our plain line-number style from the ROM's
|
|
7
|
-
LIST bodies). basictool is NOT a test dependency.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import pytest
|
|
11
|
-
from oaknut.basic import detokenise
|
|
12
|
-
|
|
13
|
-
# (tokenised program bytes, expected de-tokenised text).
|
|
14
|
-
_GOLDEN = [
|
|
15
|
-
(b'\r\x00\n\x16 \xf1 "Hello, world!"\r\xff', '10 PRINT "Hello, world!"\n'),
|
|
16
|
-
(b'\r\x00\n\x0b \xe5 \x8dDd@\r\xff', '10 GOTO 100\n'),
|
|
17
|
-
(b'\r\x00\n\r \xe4 \x8ddH@:\xf8\r\xff', '10 GOSUB 200:RETURN\n'),
|
|
18
|
-
(b'\r\x00\n\x19 \xee X \xe5 \x8dTJ@,\x8dTT@,\x8dT^@\r\xff', '10 ON X GOTO 10,20,30\n'),
|
|
19
|
-
(b'\r\x00\n\x18 \xe7 A=1 \x8c \x8dTr@ \x8b \x8dT|@\r\xff', '10 IF A=1 THEN 50 ELSE 60\n'),
|
|
20
|
-
(b'\r\x00\n\x11 \xf7 \x8dDd@:\xf3 A,B\r\xff', '10 RESTORE 100:READ A,B\n'),
|
|
21
|
-
(b'\r\x00\n\x17 \xe3 I=1 \xb8 10 \x88 2:\xed I\r\xff', '10 FOR I=1 TO 10 STEP 2:NEXT I\n'),
|
|
22
|
-
(b'\r\x00\n\x0c \xf5:\xfd X>5\r\xff', '10 REPEAT:UNTIL X>5\n'),
|
|
23
|
-
(b'\r\x00\n\x0c \xd0=&2000\r\xff', '10 PAGE=&2000\n'),
|
|
24
|
-
(b'\r\x00\n\x08 X=\x90\r\xff', '10 X=PAGE\n'),
|
|
25
|
-
(b'\r\x00\n\n \xcf#3=0\r\xff', '10 PTR#3=0\n'),
|
|
26
|
-
(b'\r\x00\n\x0c \xd1=0:X=\x91\r\xff', '10 TIME=0:X=TIME\n'),
|
|
27
|
-
(b'\r\x00\n\x10 \xd3=&7C00:\xd2=\x90\r\xff', '10 HIMEM=&7C00:LOMEM=PAGE\n'),
|
|
28
|
-
(b'\r\x00\n\x15 A$=\xbd(34)+"quote"\r\xff', '10 A$=CHR$(34)+"quote"\n'),
|
|
29
|
-
(b'\r\x00\n\x1d \xf1 "GOTO 10 is text here"\r\xff', '10 PRINT "GOTO 10 is text here"\n'),
|
|
30
|
-
(b'\r\x00\n\x16 X=&FF+&1A2B \x80 &F0\r\xff', '10 X=&FF+&1A2B AND &F0\n'),
|
|
31
|
-
(b'\r\x00\n\x10 Y=1.5E3+.25\r\xff', '10 Y=1.5E3+.25\n'),
|
|
32
|
-
(b'\r\x00\n$ \xf4 this REM has PRINT GOTO in it\r\xff', '10 REM this REM has PRINT GOTO in it\n'),
|
|
33
|
-
(b'\r\x00\n\x18 \xdc 1,2,PRINT,3,hello\r\xff', '10 DATA 1,2,PRINT,3,hello\n'),
|
|
34
|
-
(b'\r\x00\n\t *CAT\r\xff', '10 *CAT\n'),
|
|
35
|
-
(b'\r\x00\n\x14 \xef 23,255;0;0;0;\r\xff', '10 VDU 23,255;0;0;0;\n'),
|
|
36
|
-
(b'\r\x00\n\x13 \xf2draw(x%,y%):\xe1\r\xff', '10 PROCdraw(x%,y%):ENDPROC\n'),
|
|
37
|
-
(b'\r\x00\n\x11 \xdd \xa4sq(x)=x*x\r\xff', '10 DEF FNsq(x)=x*x\n'),
|
|
38
|
-
(b'\r\x00\n\x11 L%=\xa9(A$)+\xb1-\x9c\r\xff', '10 L%=LEN(A$)+POS-COUNT\n'),
|
|
39
|
-
(b'\r\x00\n\x12 X=\xa8(\xb3(1)*6)+1\r\xff', '10 X=INT(RND(1)*6)+1\n'),
|
|
40
|
-
(b'\r\x00\n\n \xf1~&AB\r\xff', '10 PRINT~&AB\n'),
|
|
41
|
-
(b'\r\x00\n\x14 @%=&90A:\xf1 \x8a5);X\r\xff', '10 @%=&90A:PRINT TAB(5);X\n'),
|
|
42
|
-
(b'\r\x00\n\x12 \xfb 129:\xe6 0,1:\xdb\r\xff', '10 COLOUR 129:GCOL 0,1:CLS\n'),
|
|
43
|
-
(b"\r\x00\n\x10 \xeb 7:\xf1'\x8a10)'\r\xff", "10 MODE 7:PRINT'TAB(10)'\n"),
|
|
44
|
-
(b'\r\x00\n\x17 ?(addr%+1)=base%?2\r\xff', '10 ?(addr%+1)=base%?2\n'),
|
|
45
|
-
(b'\r\x00\n\x19 \xf1 "unterminated GOTO\r\xff', '10 PRINT "unterminated GOTO\n'),
|
|
46
|
-
]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@pytest.mark.parametrize(("program", "expected"), _GOLDEN, ids=range(len(_GOLDEN)))
|
|
50
|
-
def test_detokenises_like_the_basic_ii_rom(program, expected):
|
|
51
|
-
assert detokenise(program) == expected
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oaknut_basic-12.17.1 → oaknut_basic-12.18.0}/src/oaknut_basic.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|