This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-10683
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY-10683 by this push:
     new 4619471d90 GROOVY-10683: support `for (index, item in list)` looping
4619471d90 is described below

commit 4619471d9011e9879b44b48d463bdfa3dbd0cc21
Author: Eric Milles <[email protected]>
AuthorDate: Sun Mar 30 20:03:46 2025 -0500

    GROOVY-10683: support `for (index, item in list)` looping
---
 src/antlr/GroovyParser.g4                                    |  6 +++++-
 .../java/org/apache/groovy/parser/antlr4/AstBuilder.java     | 12 ++++++++++++
 src/spec/test/SemanticsTest.groovy                           |  5 +++++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index edf75c4cde..b41faad333 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -691,7 +691,11 @@ forControl
     ;
 
 enhancedForControl
-    :   variableModifiersOpt type? identifier (COLON | IN) expression
+    :   (indexVariable COMMA)? variableModifiersOpt type? identifier (COLON | 
IN) expression
+    ;
+
+indexVariable
+    :   (BuiltInPrimitiveType | DEF | VAR)? identifier
     ;
 
 originalForControl
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java 
b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index e6903c80d4..92fdba3f85 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -497,10 +497,22 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
     public Tuple2<Parameter, Expression> visitEnhancedForControl(final 
EnhancedForControlContext ctx) {
         var parameter = configureAST(new Parameter(this.visitType(ctx.type()), 
this.visitIdentifier(ctx.identifier())), ctx.identifier());
         new ModifierManager(this, 
this.visitVariableModifiersOpt(ctx.variableModifiersOpt())).processParameter(parameter);
+        if (asBoolean(ctx.indexVariable())) {
+            var indexParameter = this.visitIndexVariable(ctx.indexVariable());
+        }
 
         return tuple(parameter, (Expression) this.visit(ctx.expression()));
     }
 
+    @Override
+    public Parameter visitIndexVariable(final IndexVariableContext ctx) {
+        var primitiveType = ctx.BuiltInPrimitiveType();
+        if (primitiveType != null && primitiveType.getText().length() != 3) {
+            throw this.createParsingFailedException(primitiveType.getText() + 
" is not allowed here", ctx);
+        }
+        return configureAST(new Parameter(ClassHelper.int_TYPE, 
this.visitIdentifier(ctx.identifier())), ctx.identifier());
+    }
+
     @Override
     public Tuple2<Parameter, Expression> visitOriginalForControl(final 
OriginalForControlContext ctx) {
         ClosureListExpression closureListExpression = new 
ClosureListExpression();
diff --git a/src/spec/test/SemanticsTest.groovy 
b/src/spec/test/SemanticsTest.groovy
index da6a4ca13f..9cb17789d4 100644
--- a/src/spec/test/SemanticsTest.groovy
+++ b/src/spec/test/SemanticsTest.groovy
@@ -245,6 +245,11 @@ final class SemanticsTest {
             list.add(c)
         }
         assert list == ['a', 'b', 'c']
+
+        // iterate with index
+        for ( int i, k in map.keySet() ) {
+        //  assert map.get(k) == i + 1
+        }
         // end::groovy_for_loop_example[]
     }
 

Reply via email to