[
https://issues.apache.org/jira/browse/GROOVY-12353?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18111756#comment-18111756
]
ASF GitHub Bot commented on GROOVY-12353:
-----------------------------------------
testlens-app[bot] commented on PR #2877:
URL: https://github.com/apache/groovy/pull/2877#issuecomment-5547426949
## ✅ All tests passed ✅
🏷️ Commit: a32b515ebff79d6487b9a11a48238bd592720449
▶️ Tests: 116986 executed
⚪️ Checks: 31/31 completed
---
_Learn more about TestLens at
[testlens.app/docs](https://testlens.app/docs/features/pr-comment/)._
> Improve remaining common syntax error messages (unclosed literals, unexpected
> characters, missing punctuation, reserved keywords)
> ---------------------------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12353
> URL: https://issues.apache.org/jira/browse/GROOVY-12353
> Project: Groovy
> Issue Type: Improvement
> Reporter: Daniel Sun
> Priority: Major
>
> h3. Problem
> After GROOVY-12169 and GROOVY-12171, several everyday syntax mistakes still
> produce a generic *Unexpected input* or *Unexpected character* message that
> does not name the actual problem.
> Invisible characters (zero-width space, BOM, NUL, form feed) appear as an
> empty glyph in quotes. Unclosed quotes and comments are reported as an
> unexpected quote or slash rather than as an unclosed literal. {{if true}}
> without parentheses, {{x ? y}}, and {{const x = 1}} look like random
> unexpected tokens instead of a missing {{(}} / {{:}} or an unimplemented
> keyword.
> h3. Examples (before)
> * Source:
> {noformat}
> println 'Hello
> {noformat}
> Report:
> {noformat}
> Unexpected character: ''' @ line 1, column 9.
> {noformat}
> (caret on the opening quote)
> * Source:
> {noformat}
> /* comment
> {noformat}
> Report:
> {noformat}
> Unexpected input: '/'
> {noformat}
> (no mention of an unclosed comment)
> * Source: {{def}} + zero-width space + {{name = null}}
> Report:
> {noformat}
> Unexpected character: ''
> {noformat}
> (the offending character is invisible)
> * Source:
> {noformat}
> if true { x = 1 }
> {noformat}
> Report:
> {noformat}
> Unexpected input: 'true'
> {noformat}
> * Source:
> {noformat}
> const x = 1
> {noformat}
> Report:
> {noformat}
> Unexpected input: 'const'
> {noformat}
> * Source:
> {noformat}
> def n = 1_
> {noformat}
> Report:
> {noformat}
> Number ending with underscores is invalid @ line 1, column 10 @ line 1,
> column 10.
> {noformat}
> (position duplicated)
> * Source:
> {noformat}
> def m(int... a, int b) {}
> {noformat}
> Report:
> {noformat}
> The var-arg parameter strs must be the last parameter
> {noformat}
> (hard-coded name {{strs}})
> h3. Root cause
> * Lexer {{UNEXPECTED_CHAR}} inlined the raw character with only a
> quote-escape, so control / format characters vanish in the message. An
> unexpected quote is almost always an unclosed string, but the message never
> said so.
> * Unclosed block comments failed the comment rule and were retokenised as
> {{/}}, so the parser saw an unexpected slash.
> * Parser fallback wording was still ANTLR's *Unexpected input*, even when
> the expected set was a single punctuation token (open paren, colon, {{>}}) or
> the offending token was a reserved keyword ({{const}}, {{goto}}, {{else}},
> {{catch}}, {{finally}}, {{case}}) or EOF.
> * Lexer {{require(..., true)}} appended {{@ line N, column M}} to
> {{GroovySyntaxError}}, and {{SyntaxException}} appended the same location
> again.
> * {{AstBuilder}} used a hard-coded parameter name {{strs}} in the
> varargs-not-last diagnostic.
> Grammar-level parser error alternatives are not an option: GROOVY-9588 showed
> they enlarge the ATN and slow successful parses.
> h3. Goal
> Give javac-aligned, developer-facing sentences for these common mistakes,
> with an accurate caret, without reintroducing parser error alternatives on
> the hot path.
> h3. Approach
> Error-path-only, two layers:
> * Lexer ({{GroovyLexer.g4}} / {{AbstractLexer}}): unexpected quote becomes
> *Unclosed string literal*; unclosed block comment becomes *Unclosed comment*
> at the opener (same-rule EOF alternative, not a second lexer rule); other
> unexpected characters via {{getCharErrorDisplay}} (shared with the GString
> {{$}} path from GROOVY-12171). Stop attaching position text on lexer
> {{require}} calls so {{SyntaxException}} is the only source of {{@ line N,
> column M}}.
> * Parser ({{AbstractFriendlyErrorStrategy}}): {{MissingDelimiterDiagnostic}}
> still relocates the caret for a missing closer (GROOVY-12169). Everything
> else only refines the fallback sentence and keeps ANTLR's offending token:
> reserved/misplaced keyword, then a singleton expected punctuation token
> ({{Missing '('}}, {{Missing ':'}}, {{Missing '>'}}, ...), then *Unexpected
> end of input* for EOF.
> {{AstBuilder}} reports the actual varargs parameter name.
> h3. Expected result (after)
> * unclosed single-quoted string becomes *Unclosed string literal*
> * unclosed block comment becomes *Unclosed comment* (caret on the opener)
> * zero-width space in an identifier becomes {{Unexpected character:
> '\u200b'}}
> * {{if true}} without parentheses becomes {{Missing '('}}
> * {{x ? y}} becomes {{Missing ':'}}
> * a generic type missing {{>}} before {{(}} becomes {{Missing '>'}}
> * {{const x = 1}} becomes {{'const' is not supported; use 'val' or 'static
> final' instead}}
> * {{goto label}} becomes {{'goto' is not supported}}
> * stray {{else}} / {{catch}} / {{case}} become {{'else' without 'if'}} /
> {{'catch' without 'try'}} / {{'case' outside of switch}}
> * {{throw}} at EOF becomes *Unexpected end of input*
> * {{def n = 1_}} becomes *Number ending with underscores is invalid*
> (position once)
> * {{def m(int... a, int b)}} with a later parameter becomes {{The var-arg
> parameter a must be the last parameter}}
> Valid programs are unchanged. Successful parses never enter these helpers.
> h3. Related
> GROOVY-12169, GROOVY-12171, GROOVY-9588, GROOVY-10146
--
This message was sent by Atlassian Jira
(v8.20.10#820010)