Add select case statement - #1826
Open
TwitchBronBron wants to merge 1 commit into
Open
TwitchBronBron wants to merge 1 commit into
TwitchBronBron wants to merge 1 commit into
Conversation
Adds VB-style `select case` / `case` / `case else` / `end select` syntax (proposed in #15), which transpiles to a plain if/else-if chain. - parser support with tolerant recovery for partially-typed code - SelectCaseStatement and CaseStatement AST nodes - transpile to if/else chain, evaluating the subject exactly once - validation for syntax errors, missing `case else`, duplicate values, mismatched literal types, and empty cases that look like fallthrough - fix finalizeClone not re-parenting children of cloned arrays - docs page at docs/select-case.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
markwpearce
approved these changes
Sep 24, 2026
markwpearce
left a comment
Collaborator
There was a problem hiding this comment.
Finally.
Thanks for using "v1" Statement constructor syntax. :)
iObject
self-requested a review
September 25, 2026 11:43
iObject
approved these changes
Sep 25, 2026
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.
Closes #15, and follows the VB-style syntax proposed in this comment.
BrighterScript finally gets a switch statement. Since BrightScript is so heavily based on VB, we borrowed VB's
select casesyntax instead of inventing a C-styleswitch:It compiles down to exactly what you'd have written by hand:
So it runs on every device, and there's no runtime cost.
The full write-up, with all the edge cases, is in docs/select-case.md. Here are the parts most worth a reviewer's attention.
How it behaves
break. The first matching case runs, and that's it. To share a body between values, list them together:case "left", "right". Value lists can also wrap across lines if each line ends with a comma.select case getStatus()doesn't callgetStatus()once per case. Local variables and literals are used directly. Anything else is stored in a single temp variable,__bsSelectCase, first. We can reuse that one name even for nested selects, because once a case body starts running, the outer select never reads its subject again.select case trueworks the way VB devs expect. Each case is a condition, and we emit the conditions directly (if age < 13 then) instead oftrue = (age < 13).=get parentheses. For example,case a and bbecomessubject = (a and b), so operator precedence can't quietly change what a case means.exit for,continue for(including the goto rewrite for older firmware), andreturnall behave like they would inside anif.caseright afterselectis optional (select m.state), like in VB. This only works when the subject starts with a name, a literal, ornot, soselect(x)stays a function call.Nothing that works today should break
select,case, andendselectwere never reserved words, so real code may already use them as names. Variables, fields, methods, AA keys, and function names calledselect/caseall still work, and there are tests for that. The one catch: inside aselect case, a line starting withcaseis read as the next case. Assignment forms (case = 1,case.x = 1,case[0] = 1,case++) are excluded from that.Editor experience
The parser gets exercised on half-typed code all the time, so I put effort into recovery:
end selecteach gives one clear error, and the rest of the AST survives.end if) stops at the nextcase, instead of eating the rest of the select or function.casecan't accidentally end a function.New diagnostics (1158–1170)
case else(1158)"1" = 1is a runtime Type Mismatch crash in BrightScript (1167)casecase elsecase/end selectif.brsfilesA call for reviewers: the missing-
case elsewarning is the most opinionated one. A lot of people leave out a default on purpose, and it's easy to override withdiagnosticSeverityOverrides. Still, if folks would rather it be a hint, that's a one-line change.A note on the AST shape
SelectCaseStatementholds an array ofCaseStatements, andcase elseis just aCaseStatementwithisElseset. TypeScript and ESTree model these as "clauses" that are neither statements nor expressions. Our AST only has statements and expressions, though, and a case holds statements rather than producing a value. So it's aStatement, the same wayCatchStatementis fortry.One unrelated fix that came along
AstNode.finalizeClonewas setting.parenton the array instead of on each child. That means clonedBlock.statements(and every other array of child nodes) never got re-parented. I found it while writing the clone tests, and the fix is one line. The full suite still passes with it.Not in this PR
These VB features aren't included, and they'd make good follow-ups:
case 1 to 5,case is > 5, andexit select. The last one would need a goto label, the same waycontinuedoes for older firmware. For now, the docs point people toselect case truefor ranges.🤖 Generated with Claude Code