oaknut-basic 12.9.0__tar.gz → 12.10.1__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.9.0/src/oaknut_basic.egg-info → oaknut_basic-12.10.1}/PKG-INFO +1 -1
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/__init__.py +1 -1
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/numbering.py +27 -1
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/tokeniser.py +7 -10
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1/src/oaknut_basic.egg-info}/PKG-INFO +1 -1
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_numbering.py +7 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/LICENSE +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/README.md +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/pyproject.toml +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/setup.cfg +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/cli.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/datafile.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/detokeniser.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/exceptions.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/float5.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/linenumber.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/scanner.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut/basic/tokens.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut_basic.egg-info/SOURCES.txt +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut_basic.egg-info/dependency_links.txt +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut_basic.egg-info/entry_points.txt +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut_basic.egg-info/requires.txt +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/src/oaknut_basic.egg-info/top_level.txt +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_basic.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_cli.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_crunch_rules.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_data_cli.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_datafile.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_detokeniser.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_float5.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_keyword_coverage.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_linenumber.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_rom_golden.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_rom_golden_detokenise.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_scanner.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_tokeniser.py +0 -0
- {oaknut_basic-12.9.0 → oaknut_basic-12.10.1}/tests/test_tokens.py +0 -0
|
@@ -14,9 +14,35 @@ stream plumbing on top.
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
import re
|
|
18
|
+
|
|
17
19
|
DEFAULT_LINE_NUMBER = 10
|
|
18
20
|
DEFAULT_LINE_STEP = 10
|
|
19
21
|
|
|
22
|
+
# A BBC BASIC line ends only at a carriage return (or a host newline);
|
|
23
|
+
# Python's str.splitlines() additionally breaks on &0B, &0C, &1C-&1E and
|
|
24
|
+
# others, which occur legitimately inside string literals (mode-7 / VDU
|
|
25
|
+
# control codes), so split strictly on the real terminators only. This
|
|
26
|
+
# definition is shared with the tokeniser, which imports it from here.
|
|
27
|
+
LINE_SEPARATOR_RE = re.compile(r"\r\n|\r|\n")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def split_source_lines(source: str) -> list[str]:
|
|
31
|
+
"""Split BBC BASIC source into lines on real terminators only.
|
|
32
|
+
|
|
33
|
+
Matches :meth:`str.splitlines` semantics for the terminators a BBC
|
|
34
|
+
BASIC line actually ends on (``"\\n"``, ``"\\r"``, ``"\\r\\n"``) — an
|
|
35
|
+
empty *source* yields no lines and a single trailing terminator is
|
|
36
|
+
not treated as introducing a final empty line — but, unlike
|
|
37
|
+
:meth:`str.splitlines`, never breaks on the in-string control codes
|
|
38
|
+
(&0B, &0C, &1C-&1E, ...) that BBC BASIC string literals legitimately
|
|
39
|
+
contain.
|
|
40
|
+
"""
|
|
41
|
+
lines = LINE_SEPARATOR_RE.split(source)
|
|
42
|
+
if lines and lines[-1] == "":
|
|
43
|
+
lines.pop()
|
|
44
|
+
return lines
|
|
45
|
+
|
|
20
46
|
|
|
21
47
|
def number_lines(
|
|
22
48
|
source: str,
|
|
@@ -54,7 +80,7 @@ def number_lines(
|
|
|
54
80
|
|
|
55
81
|
number = start
|
|
56
82
|
numbered = []
|
|
57
|
-
for line in source
|
|
83
|
+
for line in split_source_lines(source):
|
|
58
84
|
numbered.append(f"{number} {line}")
|
|
59
85
|
number += step
|
|
60
86
|
|
|
@@ -27,8 +27,6 @@ the CLI does it at its I/O boundary.
|
|
|
27
27
|
|
|
28
28
|
from __future__ import annotations
|
|
29
29
|
|
|
30
|
-
import re
|
|
31
|
-
|
|
32
30
|
from oaknut.basic.exceptions import (
|
|
33
31
|
AlreadyNumberedError,
|
|
34
32
|
LineNumberOrderError,
|
|
@@ -37,7 +35,12 @@ from oaknut.basic.exceptions import (
|
|
|
37
35
|
UnnumberedLineError,
|
|
38
36
|
)
|
|
39
37
|
from oaknut.basic.linenumber import MAX_LINE_NUMBER, encode_line_number
|
|
40
|
-
from oaknut.basic.numbering import
|
|
38
|
+
from oaknut.basic.numbering import (
|
|
39
|
+
DEFAULT_LINE_NUMBER,
|
|
40
|
+
DEFAULT_LINE_STEP,
|
|
41
|
+
LINE_SEPARATOR_RE,
|
|
42
|
+
number_lines,
|
|
43
|
+
)
|
|
41
44
|
from oaknut.basic.tokens import (
|
|
42
45
|
FLAG_CONDITIONAL,
|
|
43
46
|
FLAG_FN_PROC,
|
|
@@ -56,15 +59,9 @@ from oaknut.basic.tokens import (
|
|
|
56
59
|
_CR = 0x0D
|
|
57
60
|
_END_MARKER = 0xFF
|
|
58
61
|
|
|
59
|
-
# A BBC BASIC line ends only at a carriage return (or a host newline);
|
|
60
|
-
# Python's str.splitlines() additionally breaks on &0B, &0C, &1C-&1E and
|
|
61
|
-
# others, which occur legitimately inside string literals (mode-7 / VDU
|
|
62
|
-
# control codes), so split strictly on the real terminators only.
|
|
63
|
-
_LINE_SEPARATOR_RE = re.compile(r"\r\n|\r|\n")
|
|
64
|
-
|
|
65
62
|
|
|
66
63
|
def _split_source_lines(source: str) -> list[str]:
|
|
67
|
-
return
|
|
64
|
+
return LINE_SEPARATOR_RE.split(source)
|
|
68
65
|
|
|
69
66
|
# Keyword entries grouped by first character, preserving ROM order within
|
|
70
67
|
# each group, so the crunch only scans the relevant group.
|
|
@@ -47,6 +47,13 @@ class TestNumberLines:
|
|
|
47
47
|
def test_blank_lines_are_numbered_too(self):
|
|
48
48
|
assert basic.number_lines("A\n\nB") == "10 A\n20 \n30 B"
|
|
49
49
|
|
|
50
|
+
def test_control_codes_in_string_literal_do_not_split_the_line(self):
|
|
51
|
+
# VDU / mode-7 control codes (here &0C, &1C) appear legitimately
|
|
52
|
+
# inside string literals; str.splitlines() would break on them,
|
|
53
|
+
# corrupting a single program line into several numbered lines.
|
|
54
|
+
source = 'PRINT "' + chr(0x0C) + chr(0x1C) + 'banner"'
|
|
55
|
+
assert basic.number_lines(source) == '10 PRINT "\x0c\x1cbanner"'
|
|
56
|
+
|
|
50
57
|
def test_internal_references_are_left_untouched(self):
|
|
51
58
|
# The facade only prepends numbers; it does not rewrite GOTO etc.
|
|
52
59
|
source = "GOTO 20\nEND"
|
|
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
|
|
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
|
|
File without changes
|