Switch statement coverage: state-machine tests, mini-sample, docs#535
Open
Copilot wants to merge 2 commits into
Open
Switch statement coverage: state-machine tests, mini-sample, docs#535Copilot wants to merge 2 commits into
Copilot wants to merge 2 commits into
Conversation
5 tasks
Agent-Logs-Url: https://github.com/jonathanpeppers/dotnes/sessions/75bd402b-4c42-406c-86de-f4a5e97f7589 Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Add transpiler support for C# switch statements
Switch statement coverage: state-machine tests, mini-sample, docs
May 22, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Adds coverage and a runnable example for the IL switch opcode lowering in dotnes (IL → CMP/BNE + JMP trampolines), plus updates docs to reflect current support.
Changes:
- Added two Roslyn-based tests exercising larger
switchpatterns (includingdefault:and a controller-driven state machine loop). - Added a new
samples/statemachine/project demonstrating a game-styleswitch (state)loop on the NES. - Updated 8bitworkshop sample documentation to remove
switch/casefrom the missing-features list and to reference the new tests.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/dotnes.tests/ControlFlowTests.cs | Adds SwitchWithDefault and SwitchStateMachine tests for switch dispatch patterns |
| samples/statemachine/statemachine.csproj | New sample project file for the state machine demo |
| samples/statemachine/Program.cs | New sample program demonstrating switch-based state machine |
| samples/statemachine/chr_generic.s | CHR data for the new sample |
| docs/8bitworkshop-samples.md | Documentation updates reflecting switch/case support and test coverage |
Comment on lines
+145
to
+155
| var hex = Convert.ToHexString(bytes); | ||
| // CMP #$01, #$02, #$03 for cases 1..3 | ||
| Assert.Contains("C901", hex); | ||
| Assert.Contains("C902", hex); | ||
| Assert.Contains("C903", hex); | ||
| // BNE (D0) for skipping JMP on mismatch | ||
| Assert.Contains("D0", hex); | ||
| // JMP (4C) for jumping to case/default targets | ||
| Assert.Contains("4C", hex); | ||
| // The default value 0x26 must appear (LDA #$26 = A926) | ||
| Assert.Contains("A926", hex); |
Comment on lines
+161
to
+205
| // The state-machine pattern from the issue: title / playing / over with a default. | ||
| // Roslyn lowers a dense byte switch with default into IL `switch` + br to default. | ||
| var bytes = GetProgramBytes( | ||
| """ | ||
| const byte STATE_TITLE = 0; | ||
| const byte STATE_PLAYING = 1; | ||
| const byte STATE_OVER = 2; | ||
|
|
||
| byte state = STATE_TITLE; | ||
| byte lives = 3; | ||
|
|
||
| while (true) | ||
| { | ||
| pad_poll(0); | ||
| switch (state) | ||
| { | ||
| case STATE_TITLE: | ||
| if ((pad_trigger(0) & PAD.START) != 0) | ||
| state = STATE_PLAYING; | ||
| break; | ||
| case STATE_PLAYING: | ||
| if (lives == 0) | ||
| state = STATE_OVER; | ||
| break; | ||
| case STATE_OVER: | ||
| if ((pad_trigger(0) & PAD.START) != 0) | ||
| state = STATE_TITLE; | ||
| break; | ||
| default: | ||
| state = STATE_TITLE; | ||
| break; | ||
| } | ||
| ppu_wait_nmi(); | ||
| } | ||
| """); | ||
| Assert.NotNull(bytes); | ||
| Assert.NotEmpty(bytes); | ||
|
|
||
| var hex = Convert.ToHexString(bytes); | ||
| // CMP #$01 and CMP #$02 for case 1 and case 2 of the dense switch | ||
| Assert.Contains("C901", hex); | ||
| Assert.Contains("C902", hex); | ||
| // JMP (4C) trampolines from the switch dispatch | ||
| Assert.Contains("4C", hex); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The transpiler already lowers the IL
switchopcode to CMP/BNE+JMP trampolines (with correct fall-through todefault:), but the feature lacked coverage for the canonical game-state-machine pattern from the issue and a runnable sample. ExistingSwitchSmallandSwitchEnumtests covered dense dispatch andenum : byte, but nothing exerciseddefault:or the fullpad_trigger/PAD.STARTdispatch loop.Changes
Tests (
src/dotnes.tests/ControlFlowTests.cs)SwitchWithDefault— 5-wayswitch (byte)withdefault:; asserts CMP#$01..#$03, BNE/JMP trampolines, and that the default arm'sLDA #$26is emitted.SwitchStateMachine— the exact title/playing/over example from the issue, includingpad_trigger(0) & PAD.STARTand adefault:arm.Sample (
samples/statemachine/) — minimal title/playing/over state machine that recolors the backdrop on START. Disassembly of the produced ROM shows the expected dispatch:Docs (
docs/8bitworkshop-samples.md)switch/casefromcrypto.c's missing-features list.default:fall-through and reference the four switch tests (Small, Enum, WithDefault, StateMachine).No transpiler code changed; the existing
HandleSwitchimplementation inIL2NESWriter.ILDispatch.csalready handled all four acceptance scenarios.