Remove the unreachable VAR (FINAL | STATIC) alternative - #69
Merged
Conversation
localAssignmentExpression declared a trailing modifier form that no input could reach. FINAL and STATIC are both in the identifier rule, put there by #46 so code naming a variable final keeps working, so "var final" matches the plain VAR alternative with final as the identifier before the longer one is considered. Prediction commits there and never reaches the third alternative. Removed rather than made reachable, because "var final" already means something and cfparser gets it right: var final = getValue(); -> var final = getValue() tree-sitter-cfml's corpus tests exactly that under a case named "keywords as variable names", with the expected tree showing an identifier. Making "var final x = 1" parse would resolve that ambiguity against a documented and tested reading in favour of one with no evidence behind it. I could find no support for "var final x = 1", "var static x = 1" or "static final x = 1" in the tree-sitter corpus or grammar, the shipped dictionaries, CFLint's real-world test corpus, or cfdocs -- and cfdocs cannot answer it either way, since it documents 806 functions and 170 tags but no language keywords at all, not even var. Adobe and Lucee documentation was unreachable from here. "final x = 1" is not affected and stays. It is Lucee's immutable local and the reason FINAL is in this rule. The change is behaviour-neutral by construction, and that is verified rather than asserted: parse and decompile output across thirteen forms is byte-identical before and after, including the three that fail. The new fixture therefore passes with cfml.parsing/src/main stashed, by design -- it exists to pin the keyword-as-name readings against a future change to this rule, not to demonstrate a fix. VAR STATIC was added in #65, mirroring the existing VAR FINAL, so half of what this removes is mine. 326 tests, ./gradlew build, differential harness unchanged at 1 with nothing newly broken, CFLint's 675 against a clean build. Closes #68
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 #68.
The trailing form could not be reached by any input.
FINALandSTATICare both in theidentifierrule — put there by #46 so code naming a variablefinalkeeps working — sovar finalmatches the plainVARalternative withfinalas the identifier, prediction commits, and the third alternative is never considered.Removed rather than repaired
var finalalready means something, and cfparser gets it right:tree-sitter-cfml's corpus tests exactly these under a case named "keywords as variable names", with the expected tree showingleft: (identifier). Makingvar final x = 1;parse would resolve that ambiguity against a documented, tested reading in favour of one with nothing behind it.I could find no support for
var final x = 1,var static x = 1orstatic final x = 1in:tree-sitter-cfmlcorpusvar final = getValue()is a variable namedfinaltree-sitter-cfmlgrammar.jsfinal/staticmodifier modelledcf9–cf11,lucee5)foundeo/cfdocs)varfinal x = 1;is unaffected and stays — Lucee's immutable local, and the reasonFINALis in this rule at all.Behaviour-neutral, and verified as such
Parse and decompile output across thirteen forms is byte-identical before and after, including the three that fail:
That is the proof the alternative was dead. It also means the new fixture passes with
cfml.parsing/src/mainstashed, which is by design rather than a weak test: it exists to pin the keyword-as-name readings against a future change to this rule, not to demonstrate a fix. Worth saying plainly, since every other grammar PR in this series used the revert-check as evidence and this one cannot.Provenance
VAR FINALcame in with292ba9c, whose message saysfinal"takes VAR's shape and may combine with it" — an assertion with no corpus case behind it.VAR STATICwas mine in #65, written to mirror it, so half of what this removes I added three PRs ago.Verification
./gradlew buildStill open
static final x = 1;remains unparsed. Unlike the above it was never declared, so it is a gap rather than dead grammar, and it has the same evidence problem. If someone can confirm it against a live Lucee or ACF, it is a small change to this same line.Generated by Claude Code