This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch GROOVY-12173 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit a76dcfd73db98d8d18e3a2a6fede0e314b5a3f4f Author: Daniel Sun <[email protected]> AuthorDate: Sat Jul 18 19:25:22 2026 +0900 GROOVY-12173: Left-factor parser rules to reduce lookahead on hot parse paths --- src/antlr/GroovyParser.g4 | 53 ++++++++++++++-------- .../apache/groovy/parser/antlr4/AstBuilder.java | 32 +++++-------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4 index 3eb0dedeed..8ab7bf6fb3 100644 --- a/src/antlr/GroovyParser.g4 +++ b/src/antlr/GroovyParser.g4 @@ -118,8 +118,10 @@ packageDeclaration ; importDeclaration - : annotationsOpt IMPORT STATIC? qualifiedName (DOT MUL | AS alias=identifier)? - | annotationsOpt IMPORT MODULE qualifiedName + : annotationsOpt IMPORT + ( MODULE qualifiedName + | STATIC? qualifiedName (DOT MUL | AS alias=identifier)? + ) ; @@ -557,8 +559,7 @@ block ; blockStatement - : localVariableDeclaration - | statement + : statement ; localVariableDeclaration @@ -579,8 +580,11 @@ variableDeclaration[int t] ; typeNamePairs - : LPAREN typeNamePair (COMMA typeNamePair)* RPAREN - | LPAREN keyedPair (COMMA keyedPair)* RPAREN + : LPAREN + ( typeNamePair (COMMA typeNamePair)* + | keyedPair (COMMA keyedPair)* + ) + RPAREN ; typeNamePair @@ -978,21 +982,32 @@ pathExpression returns [int t] pathElement returns [int t] : nls ( - DOT nls NEW creator[1] - { $t = 6; } - | - // AT: foo.@bar selects the field (or attribute), not property - ( - ( DOT // The all-powerful dot. - | SPREAD_DOT // Spread operator: x*.y === x?.collect{it.y} - | SAFE_DOT // Optional-null operator: x?.y === (x==null)?null:x.y - | SAFE_CHAIN_DOT // Optional-null chain operator: x??.y.z === x?.y?.z - ) nls (AT | nonWildcardTypeArguments)? - | - METHOD_POINTER nls // Method pointer operator: foo.&y == foo.metaClass.getMethodPointer(foo, "y") + // DOT is left-factored: `obj.new X` (inner-class creator) vs `obj.prop` + // previously sat in two alternatives that both started with DOT, forcing + // SLL prediction to explore both branches. After DOT, NEW is LL(1). + DOT nls + ( NEW creator[1] + { $t = 6; } | - METHOD_REFERENCE nls (nonWildcardTypeArguments)? // Method reference: System.out::println + // AT: foo.@bar selects the field (or attribute), not property + (AT | nonWildcardTypeArguments)? + namePart + { $t = 1; } ) + | + // Non-DOT member selection operators (still share namePart tail) + ( SPREAD_DOT // Spread operator: x*.y === x?.collect{it.y} + | SAFE_DOT // Optional-null operator: x?.y === (x==null)?null:x.y + | SAFE_CHAIN_DOT // Optional-null chain operator: x??.y.z === x?.y?.z + ) nls (AT | nonWildcardTypeArguments)? + namePart + { $t = 1; } + | + METHOD_POINTER nls // Method pointer operator: foo.&y == foo.metaClass.getMethodPointer(foo, "y") + namePart + { $t = 1; } + | + METHOD_REFERENCE nls (nonWildcardTypeArguments)? // Method reference: System.out::println namePart { $t = 1; } 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 aaeb90b9fd..deaaf9988d 100644 --- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java +++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java @@ -4351,29 +4351,21 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { @Override public Statement visitBlockStatement(final BlockStatementContext ctx) { - if (asBoolean(ctx.localVariableDeclaration())) { - return configureAST(this.visitLocalVariableDeclaration(ctx.localVariableDeclaration()), ctx); - } - - if (asBoolean(ctx.statement())) { - Object astNode = this.visit(ctx.statement()); //this.configureAST((Statement) this.visit(ctx.statement()), ctx); - - if (null == astNode) { - return null; - } + Object astNode = this.visit(ctx.statement()); - if (astNode instanceof Statement) { - return (Statement) astNode; - } else if (astNode instanceof MethodNode) { - throw createParsingFailedException("Method definition not expected here", ctx); - } else if (astNode instanceof ImportNode) { - throw createParsingFailedException("Import statement not expected here", ctx); - } else { - throw createParsingFailedException("The statement(" + astNode.getClass() + ") not expected here", ctx); - } + if (null == astNode) { + return null; } - throw createParsingFailedException("Unsupported block statement: " + ctx.getText(), ctx); + if (astNode instanceof Statement) { + return (Statement) astNode; + } else if (astNode instanceof MethodNode) { + throw createParsingFailedException("Method definition not expected here", ctx); + } else if (astNode instanceof ImportNode) { + throw createParsingFailedException("Import statement not expected here", ctx); + } else { + throw createParsingFailedException("The statement(" + astNode.getClass() + ") not expected here", ctx); + } } @Override
