Accept inline component definitions - #55
Merged
Merged
Conversation
`new component { ... }` declares and instantiates in one expression.
newComponentExpression required a path and a parenthesised argument list, and
the inline form has neither.
The new alternative is `NEW componentDeclaration`, reusing the existing rule
rather than restating its shape, so attributes, directives and members behave
exactly as they do in a named component.
CFAnonymousComponentExpression follows CFAnonymousFunctionExpression: a
declaration statement hanging off an expression, which is the same problem this
repo already solved once for function(){}. A walk reaches the inline
component's members through decomposeScript --
CFAnonymousComponentExpression
CFCompDeclStatement
CFFuncDeclStatement name=buildApp
which is the part that matters; a green parse would have proved nothing.
Adding the alternative regressed parsing/cached_cf573.cfc, whose function
carries `cachedwithin=createTimeSpan(1,0,0,0)` before its body. That is the
latent bug in #45 one rule over: simpleFunctionCall also had an optional
trailing block, so the call swallowed the function's body. The new alternative
only changed which way prediction fell. Removing that body restores the
fixture's recorded tree untouched, which is the evidence the removal is right
rather than convenient -- as with functionCall, no visitor reads it; the ctx.body
handling belongs to visitQualifiedFunctionCall, whose own rule keeps its own.
Differential harness 8 disagreements to 7, nothing newly broken. Verified end to
end -- 313 cfparser tests, ./gradlew build, CFLint's 675.
Closes #49
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 #49.
var msal = new component javaSettings='{"maven":["com.microsoft.azure:msal4j:1.23.1"]}' { function buildApp() { ... } };newComponentExpressionrequired a path and a parenthesised argument list. The inline form has neither.Grammar
The new alternative is
NEW componentDeclaration— reusing the existing rule rather than restating its shape, so attributes, directives and members behave exactly as they do in a named component.AST
CFAnonymousComponentExpressionfollowsCFAnonymousFunctionExpression: a declaration statement hanging off an expression. The issue pointed at that precedent and it holds up — same problem, already solved once forfunction(){}.The check that matters isn't the parse, it's the walk:
Members reachable via
decomposeScript(). PerCLAUDE.md, a green parse would have proved nothing here — this is exactly where #16 and #18 went wrong.It regressed an existing fixture, and that was the interesting part
Adding the alternative broke
parsing/cached_cf573.cfc, whose function carriescachedwithin=createTimeSpan(1,0,0,0)before its body.That's the latent bug from #45 one rule over:
simpleFunctionCallalso had an optional trailing block, so the call swallowed the function's body. My alternative didn't create that — it only changed which way prediction fell.Removing that body makes the fixture pass with its recorded tree untouched. I deliberately did not regenerate it: an unchanged expected file is the evidence that the removal restores correct behaviour rather than rationalising a new one. As with
functionCallin #45, no visitor reads it — thectx.bodyhandling belongs tovisitQualifiedFunctionCall, whose own rule keeps its own.Worth noting for review order: #45 removes the same thing from
functionCall. Different lines, so no textual conflict, but they're two halves of one problem.Verification
./gradlew build, no expected file regeneratedcomponents/inline_component_49.cfcfails withcfml.parsing/src/mainstashedGenerated by Claude Code