Accept an access modifier on a static block member, and keep the block - #66
Merged
Merged
Conversation
component { static { public myVar = "v"; } } failed to parse:
no viable alternative at input 'publicmyVar='
staticBlock took a bare statement, and an accessType is not part of one. The
block itself was fine -- static { myVar = "v"; } parsed -- so only members
carrying public, private, remote or package were rejected. All four are legal
there in ACF.
A staticMember rule now carries the optional accessType, which puts it on the
member rather than the block, where CFML puts it.
## The block was being thrown away
Fixed here because adding the modifier without it would have made things
worse. staticBlock had no visitor at all, so ANTLR's default visitChildren
flattened it:
before: component { static { myVar = "v"; } } -> component { myVar = 'v' }
after: component { static { myVar = "v"; } } -> component { static { myVar = 'v'; } }
Adding accessType to a rule the visitor ignores would have folded the modifier
into whatever was nearby -- the exact failure CLAUDE.md describes for arrow
functions in #16 and array slicing in #18. So CFStaticBlockStatement models
the block, holds its members in source order for decomposeScript, and records
each member's access type positionally.
No fixture covered a CFML static block before this, which is how a construct
that parsed and then vanished went unnoticed.
323 tests, ./gradlew build, differential harness unchanged at 1 with nothing
newly broken, CFLint's 675 against a clean build. The new fixture fails with
cfml.parsing/src/main stashed.
Closes #64
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 #64.
component { static { public myVar = "v"; } }staticBlocktook a barestatement, and anaccessTypeis not part of one. The block itself was fine —static { myVar = "v"; }parsed — so only members carryingpublic,private,remoteorpackagewere rejected. All four are legal there in ACF.A
staticMemberrule now carries the optionalaccessType, putting it on the member rather than the block, which is where CFML puts it.The block was being thrown away
This is the part worth reviewing.
staticBlockhad no visitor at all, so ANTLR's defaultvisitChildrenflattened it:The block vanished and its members leaked out as ordinary component members — the static-ness silently discarded.
I fixed it here rather than filing it separately because doing only the grammar half would have made things worse: adding
accessTypeto a rule the visitor ignores means the modifier gets folded into whatever is nearby. That is precisely the failureCLAUDE.mddocuments for arrow functions in #16 and array slicing in #18.So
CFStaticBlockStatementmodels the block, holds its members in source order fordecomposeScript(), and records each member's access type positionally.No fixture covered static blocks
Searching the corpus found none — which is how a construct that parsed cleanly and then disappeared from the tree went unnoticed. The new fixture pins all three shapes:
static { public myPublic = "p"; private myPrivate = "q"; myPlain = "r"; }decompiling to:
Access types preserved where written, absent where not.
Verification
./gradlew buildcomponents/static_block_modifier_64.cfcfails withcfml.parsing/src/mainstashedRelationship to #65
#65 fixes the other half of cfmleditor/CFLint#50 — the
static x = 1;NullPointerException. Different rules (localAssignmentExpressionvsstaticBlock), no textual overlap, mergeable in either order. Both are needed before CFLint#50 can close.Generated by Claude Code