Skip to content

Add support for nested loops#71

Merged
shenanigansd merged 4 commits intomainfrom
copilot/add-support-for-nested-loops
Apr 12, 2026
Merged

Add support for nested loops#71
shenanigansd merged 4 commits intomainfrom
copilot/add-support-for-nested-loops

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 12, 2026

  • Fix validate_syntax to use a depth counter instead of a boolean flag so nested brackets are validated correctly
  • Track the most recently seen [ in error messages (reports innermost unclosed bracket for deep nesting)
  • Fix run to precompute matching bracket pairs and use them for JUMP_FORWARD / JUMP_BACKWARD jumps
  • Add comment explaining the stack invariant in run
  • Create examples/hello-world-nested-loops.bf with the content from the issue
  • Add the new example file to the parametrized test in test_example_files.py
  • Fix KeyError crash: use memory.get(position, 0) in output_current_byte and loop-condition checks in handle_token so uninitialized sparse-dict cells are treated as 0
  • Replace single-letter variable names (i, j) with descriptive names (token_index, open_bracket_index)

Copilot AI linked an issue Apr 12, 2026 that may be closed by this pull request
Agent-Logs-Url: https://github.com/letsbuilda/bpp/sessions/898602c6-472d-43bf-a777-e7eccc8aa770

Co-authored-by: shenanigansd <54628770+shenanigansd@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for nested loops Add support for nested loops Apr 12, 2026
Copilot AI requested a review from shenanigansd April 12, 2026 17:31
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.04%. Comparing base (483dd3a) to head (552a4d3).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #71      +/-   ##
==========================================
+ Coverage   98.54%   99.04%   +0.49%     
==========================================
  Files          10       10              
  Lines         206      209       +3     
  Branches       31       31              
==========================================
+ Hits          203      207       +4     
+ Partials        3        2       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@shenanigansd
Copy link
Copy Markdown
Member

@copilot fix this new test failure:

===================================================================== FAILURES ======================================================================
___________________________________________________ test_example_files[example_file1-hello world] ___________________________________________________

example_file = PosixPath('examples/hello-world-nested-loops.bf'), expected_result = 'hello world'

    @pytest.mark.parametrize(
        ("example_file", "expected_result"),
        [
            (Path("./examples/hello-world.bf"), "Hello, World!"),
            (Path("./examples/hello-world-nested-loops.bf"), "hello world"),
            (Path("./examples/jump.bf"), ""),
            (Path("./examples/decrement_not_in_memory.bf"), ""),
        ],
    )
    def test_example_files(example_file: Path, expected_result: str) -> None:
        """Test example files."""
        source = example_file.read_text()
        interpreter = Interpreter()
>       assert interpreter.run(source) == expected_result
               ^^^^^^^^^^^^^^^^^^^^^^^

tests/test_example_files.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/bpp/interpreter.py:162: in run
    match self.handle_token(token):
          ^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <bpp.interpreter.Interpreter object at 0x7c2e29cff5b0>, token = <Token.LOOP_START: '['>

    def handle_token(self: Self, token: Token) -> ResultState:  # noqa: C901
        """Handle a single token.
    
        Returns
        -------
        The state of the interpreter after handling the token
        """
        match token:
            case Token.INCREMENT_POINTER:
                self.increment_pointer()
            case Token.DECREMENT_POINTER:
                self.decrement_pointer()
            case Token.INCREMENT_BYTE:
                self.increment_byte_at_current_pointer()
            case Token.DECREMENT_BYTE:
                self.decrement_byte_at_current_pointer()
            case Token.OUTPUT_BYTE:
                self.output_current_byte()
            case Token.INPUT_BYTE:
                self.get_input()
            case Token.LOOP_START:
>               if self.memory[self.current_position] == 0:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E               KeyError: 1

src/bpp/interpreter.py:129: KeyError
============================================================== short test summary info ==============================================================
FAILED tests/test_example_files.py::test_example_files[example_file1-hello world] - KeyError: 1
=========================================================== 1 failed, 17 passed in 0.21s ============================================================
@shenanigansd ➜ /workspaces/bpp (copilot/add-support-for-nested-loops) $ 

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 12, 2026

@copilot fix this new test failure:

===================================================================== FAILURES ======================================================================

...

Fixed in cb13182. The failure was a KeyError: the interpreter stores memory as a sparse dict, but output_current_byte and the loop-condition checks in handle_token read directly from the dict (self.memory[pos]) without a default. The nested-loops program accesses cells that haven't been written yet. Changed all three read sites to use self.memory.get(self.current_position, 0) to treat uninitialized cells as 0, consistent with how the write methods already behave.

@shenanigansd
Copy link
Copy Markdown
Member

@copilot replace all single letter variable names with full words.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 12, 2026

@copilot replace all single letter variable names with full words.

Done in 552a4d3. Renamed itoken_index and jopen_bracket_index in the bracket-map loop inside run().

@shenanigansd shenanigansd marked this pull request as ready for review April 12, 2026 17:52
@shenanigansd shenanigansd merged commit 65287d3 into main Apr 12, 2026
13 checks passed
@shenanigansd shenanigansd deleted the copilot/add-support-for-nested-loops branch April 12, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for nested loops

2 participants