[ 
https://issues.apache.org/jira/browse/GROOVY-12169?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18097234#comment-18097234
 ] 

ASF GitHub Bot commented on GROOVY-12169:
-----------------------------------------

Copilot commented on code in PR #2718:
URL: https://github.com/apache/groovy/pull/2718#discussion_r3607248156


##########
src/test/java/org/apache/groovy/parser/antlr4/internal/ThrowingTokenStream.java:
##########
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.parser.antlr4.internal;
+
+import org.antlr.v4.runtime.RuleContext;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenSource;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.misc.Interval;
+
+/**
+ * Token stream that fails on every access — used to exercise defensive
+ * catch paths in {@link MissingDelimiterDiagnostic}.
+ */
+final class ThrowingTokenStream implements TokenStream {
+    @Override
+    public Token LT(int k) {
+        throw new IndexOutOfBoundsException("test");
+    }
+
+    @Override
+    public Token get(int index) {
+        throw new IndexOutOfBoundsException("test");
+    }
+
+    @Override
+    public TokenSource getTokenSource() {
+        return null;
+    }
+
+    @Override
+    public String getText(Interval interval) {
+        return "";
+    }
+
+    @Override
+    public String getText() {
+        return "";
+    }
+
+    @Override
+    public String getText(RuleContext ctx) {
+        return "";
+    }
+
+    @Override
+    public String getText(Object start, Object stop) {
+        return "";
+    }

Review Comment:
   The TokenStream#getText overload is declared with (Object start, Object 
stop), which is unlikely to match the ANTLR TokenStream API (it expects Token 
start/stop). With `@Override` present, this will not compile if the signature 
doesn’t exactly match the interface method.





> Improve syntax error messages and caret positions for missing ')', ']', and 
> '}'
> -------------------------------------------------------------------------------
>
>                 Key: GROOVY-12169
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12169
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Daniel Sun
>            Priority: Major
>
> h3. Problem
> When Groovy source is missing a closing delimiter (right paren, right 
> bracket, or right brace), the ANTLR4 parser often reports a generic 
> *Unexpected input* message at a *misleading* location (commonly the opening 
> token or an earlier construct), instead of a clear *Missing ...* message at 
> the place where the closer should be inserted.
> That makes simple typos hard to diagnose, especially with:
>  * casts and parenthesised expressions (missing right paren)
>  * lists, maps, and indexing (missing right bracket, including safe-index)
>  * blocks, classes, and closures (missing right brace)
> h3. Examples (before)
>  * Source:
> {noformat}
> println ((int 123)
> {noformat}
> Report: Unexpected input for open-paren at the *opening* parenthesis
>  * Source:
> {noformat}
> [1, 2
> {noformat}
> Report: Unexpected input: '<EOF>' at end of input
>  * Source:
> {noformat}
> foo[1
> {noformat}
> Report: Unexpected input for the open-bracket token
>  * Source:
> {noformat}
> def m() {
>     println 1
> {noformat}
> Report: Unexpected input far from the missing brace
>  * Source:
> {noformat}
> foo([1, 2)
> {noformat}
> Report: Unexpected input for open-paren (real issue: missing right bracket 
> before right paren)
> h3. Root cause
>  * ANTLR4 does not recover missing tokens as helpfully as the old Antlr2 path.
>  * Grammar-level error alternatives (for example on {{{}rparen{}}}) can yield 
> a *Missing right-paren* message, but they enlarge the ATN and hurt 
> {*}successful{*}-parse performance. They were removed in the GROOVY-9588 work 
> for that reason.
>  * With {{BailErrorStrategy}} plus generic mismatch reporting, prediction 
> often abandons a deep delimited alternative and falls back to a shorter 
> parse, so the surface error points far from the real omission.
> h3. Goal
> Report {*}Missing right-paren{*}, {*}Missing right-bracket{*}, or *Missing 
> right-brace* with an accurate caret when the token stream clearly indicates a 
> missing or incomplete closer — *without* reintroducing grammar error 
> alternatives on the hot (successful) parse path.
> h3. Approach
> Error-path-only diagnostics wired into the existing error strategy:
>  * {{DescriptiveErrorStrategy}} — on input mismatch / no viable alternative, 
> prefer a missing-delimiter hit over the generic message.
>  * {{MissingDelimiterDiagnostic}} — one linear scan of the fully filled token 
> stream *after* failure; no work on successful parses.
> Detection order (most specific first):
> *1. Sole expected closer* — RecognitionException whose *sole* expected token 
> is RPAREN, RBRACK, or RBRACE, and the corresponding open-depth is still 
> positive. This avoids false positives where delimiters are balanced but an 
> intermediate token is wrong, for example:
> {noformat}
> foo(1;2;3)
> {noformat}
> *2. Cast pattern* — open-paren, type, then expression-start without the 
> cast's close-paren, for example:
> {noformat}
> (int 123
> {noformat}
> *3. Delimiter stack* — walk openers for paren, bracket, safe-index, and 
> brace; report the *innermost* missing closer on mismatch or at EOF, for 
> example:
> {noformat}
> foo([1, 2)
> {noformat}
> (missing right bracket before the right paren)
> The token stream is force-filled to EOF before scanning so a trailing closer 
> is visible even when the parser failed earlier inside the construct.
> h3. Expected result (after)
>  * Source:
> {noformat}
> println ((int 123)
> {noformat}
> Expected: *Missing right-paren* at 123
>  * Source:
> {noformat}
> def x() {
>     println((int) 123
> }
> {noformat}
> Expected: *Missing right-paren* after 123
>  * Source:
> {noformat}
> def m( {
> }
> {noformat}
> Expected: *Missing right-paren* at the open brace
>  * Source:
> {noformat}
> foo(1, 2
> {noformat}
> Expected: *Missing right-paren* at end of line
>  * Source:
> {noformat}
> [1, 2
> {noformat}
> Expected: *Missing right-bracket* at end of line
>  * Source:
> {noformat}
> foo[1
> {noformat}
> Expected: *Missing right-bracket* after 1
>  * Source:
> {noformat}
> def x = [[1, 2]
> {noformat}
> Expected: *Missing right-bracket* after the inner closing bracket
>  * Source:
> {noformat}
> foo([1, 2)
> {noformat}
> Expected: *Missing right-bracket* before the closing paren
>  * Source:
> {noformat}
> a?[0
> {noformat}
> Expected: *Missing right-bracket* after 0
>  * Source:
> {noformat}
> def m() {
>     println 1
> {noformat}
> Expected: *Missing right-brace* after 1
>  * Source:
> {noformat}
> class C {
>     def x
> {noformat}
> Expected: *Missing right-brace* after x
>  * Source:
> {noformat}
> def c = { it
> {noformat}
> Expected: *Missing right-brace* after it
> False-positive guard (delimiters balanced; must *not* report a 
> Missing-delimiter message):
> {noformat}
> [].bar(1;2;3)
> {noformat}
> h3. Compatibility and performance
>  * No grammar, lexer, or public API changes — valid programs parse as before.
>  * Successful path remains {{BailErrorStrategy}} with no ATN error 
> alternatives.
>  * Extra work is a single O\(n\) token scan only after a recognition failure.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to