Stop the tag scanner ending a tag inside an arrow operator - #50
Merged
Conversation
<cfset f = (x) => x + 1> was scanned as the tag `<cfset f = (x) =>`, because CFMLStartTag.getEnd returns at the first unquoted '>' and the second character of => is one. The truncated text `f = (x) =` then parsed to `f = (x)` -- an expression the visitor accepted, with the body silently gone. Nothing to do with the thin arrow or with lambdaDeclaration, both of which work: `=>` failed identically, and had since long before either was touched. The grammar was never reached with the whole expression. getEnd already special-cases quotes and the ---> of a comment; an arrow joins them. A '-' only counts when it does not follow another '-', so the decrement in <cfset a = i--> still ends the tag, which the fixture pins alongside the arrows. A TestTagFiles fixture rather than a JUnit case: this is the tag path, and nothing under src/test/resources/tag exercised an arrow function, which is why the suite was green. Verified end to end -- 313 cfparser tests, ./gradlew build, CFLint's 675. Differential harness 8 disagreements to 7. Closes #44 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GzpZFd4rnE1Yi2sVHAji35
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 #44.
My diagnosis in the issue was wrong
#44 says the
expressionrule likely commits before the arrow is seen. It doesn't — the grammar never gets the chance.CFMLStartTag.getEnd()returns at the first unquoted>, and the second character of=>is one:The truncated text
e = (x) =then parses toe = (x)— a well-formed expression the visitor accepts, with the body gone. That's why it was silent.Fix
getEndalready special-cases quotes and the--->of a comment. An arrow joins them.The
-case needs care:<cfset a = i-->is a decrement followed by the tag end, not an arrow. So-only counts when it doesn't follow another-. The fixture pins that alongside the arrows, alongsidegt(where the>never appears) and a quotedsubject="x=>y"(already handled by the quote tracking).Fixture, not a JUnit case
This is the tag path, so
TestTagFiles. Nothing undersrc/test/resources/tagexercised an arrow function, which is exactly why the suite stayed green. The recorded output shows each<cfset>capturing its whole expression and building alambdaDeclaration:Reverting
cfml.parsing/src/mainfails it.Verification
TestGetStartTagEndcases, which is what I most expected to break),./gradlew buildGenerated by Claude Code