diff --git a/adafruit_pioasm.py b/adafruit_pioasm.py index ad29fcb..b92a8be 100644 --- a/adafruit_pioasm.py +++ b/adafruit_pioasm.py @@ -12,7 +12,7 @@ """ try: - from typing import List, MutableSequence + from typing import List, Sequence, Any except ImportError: pass @@ -55,12 +55,20 @@ class Program: # pylint: disable=too-few-public-methods """ + assembled: array.array + """The assembled PIO program instructions""" + public_labels: dict[str, int] + """The offset of any labels delcared public""" + pio_kwargs: dict[str, Any] + """Settings from assembler directives to pass to the StateMachine constructor""" + def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: """Converts pioasm text to encoded instruction bytes""" # pylint: disable=too-many-branches,too-many-statements,too-many-locals assembled: List[int] = [] program_name = None labels = {} + public_labels = {} linemap = [] instructions: List[str] = [] sideset_count = 0 @@ -219,6 +227,9 @@ def parse_rxfifo_brackets(arg, fifo_dir): elif line.endswith(":"): label = line[:-1] + if line.startswith("public "): + label = label[7:] + public_labels[label] = len(instructions) if label in labels: raise SyntaxError(f"Duplicate label {repr(label)}") labels[label] = len(instructions) @@ -227,6 +238,7 @@ def parse_rxfifo_brackets(arg, fifo_dir): instructions.append(line) linemap.append(i) + mov_destinations: Sequence[str | None] if pio_version >= 1: mov_destinations = MOV_DESTINATIONS_V1 else: @@ -502,6 +514,8 @@ def parse_rxfifo_brackets(arg, fifo_dir): self.debuginfo = (linemap, text_program) if build_debuginfo else None + self.public_labels = public_labels + @classmethod def from_file(cls, filename: str, **kwargs) -> "Program": """Assemble a PIO program in a file""" @@ -557,7 +571,7 @@ def print_c_program(self, name: str, qualifier: str = "const") -> None: print() -def assemble(program_text: str) -> MutableSequence[int]: +def assemble(program_text: str) -> array.array: """Converts pioasm text to encoded instruction bytes In new code, prefer to use the `Program` class so that the extra arguments diff --git a/tests/test_label.py b/tests/test_label.py new file mode 100644 index 0000000..d9e9183 --- /dev/null +++ b/tests/test_label.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: 2024 Jeff Epler for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Tests out +""" + +from pytest_helpers import assert_assembly_fails +import adafruit_pioasm + + +def test_label() -> None: + source = [ + " jmp label1", + "label1:", + " jmp label2", + "public label2:", + " nop", + ] + program = adafruit_pioasm.Program("\n".join(source)) + assert program.public_labels == {"label2": 2} + + # Test each combination of public/privagte label duplication + source = [ + "label1:\n", + "nop\n", + "public label1:\n", + "nop\n", + ] + assert_assembly_fails( + "\n".join(source), match="Duplicate label", errtype=SyntaxError + ) + + source = [ + "label1:\n", + " nop\n", + "label1:\n", + " nop\n", + ] + assert_assembly_fails( + "\n".join(source), match="Duplicate label", errtype=SyntaxError + ) + + source = [ + "public label1:\n", + " nop\n", + "label1:\n", + " nop\n", + ] + assert_assembly_fails( + "\n".join(source), match="Duplicate label", errtype=SyntaxError + ) + + source = [ + "public label1:\n", + " nop\n", + "public label1:\n", + " nop\n", + ] + assert_assembly_fails( + "\n".join(source), match="Duplicate label", errtype=SyntaxError + )