Skip to content

Commit

Permalink
GROOVY-11055: Support lambda expression as named value
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellansun committed Jun 15, 2024
1 parent 1c798a2 commit 59b427e
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 204 deletions.
17 changes: 11 additions & 6 deletions src/main/antlr/GroovyParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,11 @@ expressionListElement[boolean canSpread]
: MUL? expression
;

enhancedExpression
: expression
| standardLambdaExpression
;

enhancedStatementExpression
: statementExpression
| standardLambdaExpression
Expand Down Expand Up @@ -1093,20 +1098,20 @@ options { baseContext = mapEntryList; }
;

mapEntry
: mapEntryLabel COLON nls expression
| MUL COLON nls expression
: mapEntryLabel COLON nls enhancedExpression
| MUL COLON nls enhancedExpression
;

namedPropertyArg
options { baseContext = mapEntry; }
: namedPropertyArgLabel COLON nls expression
| MUL COLON nls expression
: namedPropertyArgLabel COLON nls enhancedExpression
| MUL COLON nls enhancedExpression
;

namedArg
options { baseContext = mapEntry; }
: namedArgLabel COLON nls expression
| MUL COLON nls expression
: namedArgLabel COLON nls enhancedExpression
| MUL COLON nls enhancedExpression
;

mapEntryLabel
Expand Down
215 changes: 17 additions & 198 deletions src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,176 +39,6 @@
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.groovy.ast.tools.AnnotatedNodeUtils;
import org.apache.groovy.parser.antlr4.GroovyParser.AdditiveExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AndExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AnnotatedQualifiedClassNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AnnotationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AnnotationNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AnnotationsOptContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AnonymousInnerClassDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ArgumentsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ArrayInitializerContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AssertStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.AssignmentExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BlockContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BlockStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BlockStatementsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BlockStatementsOptContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BooleanLiteralAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BreakStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.BuiltInTypeContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CastExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CastParExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CatchClauseContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CatchTypeContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassBodyContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassBodyDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceModifierContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceModifiersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceModifiersOptContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceTypeContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClassicalForControlContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClosureContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ClosureOrLambdaExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CommandArgumentContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CommandExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CommandExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CompactConstructorDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CompilationUnitContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ConditionalExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ConditionalStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ContinueStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CreatedNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.CreatorContext;
import org.apache.groovy.parser.antlr4.GroovyParser.DimContext;
import org.apache.groovy.parser.antlr4.GroovyParser.DoWhileStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.DynamicMemberNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ElementValueArrayInitializerContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ElementValueContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ElementValuePairContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ElementValuePairsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ElementValuesContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EmptyDimsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EmptyDimsOptContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EnhancedArgumentListElementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EnhancedArgumentListInParContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EnhancedForControlContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EnhancedStatementExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EnumConstantContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EnumConstantsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.EqualityExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ExclusiveOrExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ExpressionInParContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ExpressionListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ExpressionListElementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.FieldDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.FinallyBlockContext;
import org.apache.groovy.parser.antlr4.GroovyParser.FloatingPointLiteralAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ForControlContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ForInitContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ForStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ForUpdateContext;
import org.apache.groovy.parser.antlr4.GroovyParser.FormalParameterContext;
import org.apache.groovy.parser.antlr4.GroovyParser.FormalParameterListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.FormalParametersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.GroovyParserRuleContext;
import org.apache.groovy.parser.antlr4.GroovyParser.GstringContext;
import org.apache.groovy.parser.antlr4.GroovyParser.GstringPathContext;
import org.apache.groovy.parser.antlr4.GroovyParser.GstringValueContext;
import org.apache.groovy.parser.antlr4.GroovyParser.IdentifierContext;
import org.apache.groovy.parser.antlr4.GroovyParser.IdentifierPrmrAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.IfElseStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ImportDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.InclusiveOrExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.IndexPropertyArgsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.IntegerLiteralAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.KeywordsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.LabeledStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.LambdaBodyContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.LocalVariableDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.LogicalAndExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.LogicalOrExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.LoopStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MapContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MapEntryContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MapEntryLabelContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MapEntryListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MemberDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MethodBodyContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MethodDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MethodNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ModifierContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ModifiersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ModifiersOptContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MultipleAssignmentExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.MultiplicativeExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.NamePartContext;
import org.apache.groovy.parser.antlr4.GroovyParser.NamedPropertyArgsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.NewPrmrAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.NonWildcardTypeArgumentsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.NullLiteralAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.PackageDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ParExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.PathElementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.PathExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.PostfixExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.PowerExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.PrimitiveTypeContext;
import org.apache.groovy.parser.antlr4.GroovyParser.QualifiedClassNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.QualifiedClassNameListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.QualifiedNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.QualifiedNameElementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.QualifiedStandardClassNameContext;
import org.apache.groovy.parser.antlr4.GroovyParser.RegexExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.RelationalExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ResourceContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ResourceListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ResourcesContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ReturnStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ReturnTypeContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ScriptStatementsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ShiftExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.StandardLambdaExpressionContext;
import org.apache.groovy.parser.antlr4.GroovyParser.StandardLambdaParametersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.StatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.StringLiteralContext;
import org.apache.groovy.parser.antlr4.GroovyParser.SuperPrmrAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.SwitchBlockStatementGroupContext;
import org.apache.groovy.parser.antlr4.GroovyParser.SwitchLabelContext;
import org.apache.groovy.parser.antlr4.GroovyParser.SwitchStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.SynchronizedStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ThisFormalParameterContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ThisPrmrAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.ThrowStmtAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TryCatchStatementContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeArgumentContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeArgumentsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeArgumentsOrDiamondContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeBoundContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeListContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeNamePairContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeNamePairsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeParameterContext;
import org.apache.groovy.parser.antlr4.GroovyParser.TypeParametersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.UnaryAddExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.UnaryNotExprAltContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclarationContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclaratorContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclaratorIdContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclaratorsContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableInitializerContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableInitializersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableModifierContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableModifiersContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableModifiersOptContext;
import org.apache.groovy.parser.antlr4.GroovyParser.VariableNamesContext;
import org.apache.groovy.parser.antlr4.GroovyParser.WhileStmtAltContext;
import org.apache.groovy.parser.antlr4.internal.DescriptiveErrorStrategy;
import org.apache.groovy.parser.antlr4.internal.atnmanager.AtnManager;
import org.apache.groovy.parser.antlr4.util.StringUtils;
Expand Down Expand Up @@ -327,33 +157,7 @@
import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchExpressionLabelContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.YieldStatementContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.YieldStmtAltContext;
import static org.apache.groovy.parser.antlr4.GroovyParser.ADD;
import static org.apache.groovy.parser.antlr4.GroovyParser.AS;
import static org.apache.groovy.parser.antlr4.GroovyParser.CASE;
import static org.apache.groovy.parser.antlr4.GroovyParser.DEC;
import static org.apache.groovy.parser.antlr4.GroovyParser.DEF;
import static org.apache.groovy.parser.antlr4.GroovyParser.DEFAULT;
import static org.apache.groovy.parser.antlr4.GroovyParser.FINAL;
import static org.apache.groovy.parser.antlr4.GroovyParser.GE;
import static org.apache.groovy.parser.antlr4.GroovyParser.GT;
import static org.apache.groovy.parser.antlr4.GroovyParser.IN;
import static org.apache.groovy.parser.antlr4.GroovyParser.INC;
import static org.apache.groovy.parser.antlr4.GroovyParser.INSTANCEOF;
import static org.apache.groovy.parser.antlr4.GroovyParser.LE;
import static org.apache.groovy.parser.antlr4.GroovyParser.LT;
import static org.apache.groovy.parser.antlr4.GroovyParser.NON_SEALED;
import static org.apache.groovy.parser.antlr4.GroovyParser.NOT_IN;
import static org.apache.groovy.parser.antlr4.GroovyParser.NOT_INSTANCEOF;
import static org.apache.groovy.parser.antlr4.GroovyParser.PRIVATE;
import static org.apache.groovy.parser.antlr4.GroovyParser.RANGE_EXCLUSIVE_FULL;
import static org.apache.groovy.parser.antlr4.GroovyParser.RANGE_EXCLUSIVE_LEFT;
import static org.apache.groovy.parser.antlr4.GroovyParser.RANGE_EXCLUSIVE_RIGHT;
import static org.apache.groovy.parser.antlr4.GroovyParser.RANGE_INCLUSIVE;
import static org.apache.groovy.parser.antlr4.GroovyParser.SAFE_INDEX;
import static org.apache.groovy.parser.antlr4.GroovyParser.SEALED;
import static org.apache.groovy.parser.antlr4.GroovyParser.STATIC;
import static org.apache.groovy.parser.antlr4.GroovyParser.SUB;
import static org.apache.groovy.parser.antlr4.GroovyParser.VAR;
import static org.apache.groovy.parser.antlr4.GroovyParser.*;
import static org.apache.groovy.parser.antlr4.util.PositionConfigureUtils.configureAST;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
Expand Down Expand Up @@ -2692,6 +2496,21 @@ public Expression visitExpressionInPar(final ExpressionInParContext ctx) {
return this.visitEnhancedStatementExpression(ctx.enhancedStatementExpression());
}

@Override
public Expression visitEnhancedExpression(final EnhancedExpressionContext ctx) {
Expression expression;

if (asBoolean(ctx.expression())) {
expression = (Expression) this.visit(ctx.expression());
} else if (asBoolean(ctx.standardLambdaExpression())) {
expression = this.visitStandardLambdaExpression(ctx.standardLambdaExpression());
} else {
throw createParsingFailedException("Unsupported enhanced expression: " + ctx.getText(), ctx);
}

return configureAST(expression, ctx);
}

@Override
public Expression visitEnhancedStatementExpression(final EnhancedStatementExpressionContext ctx) {
Expression expression;
Expand Down Expand Up @@ -3762,7 +3581,7 @@ private List<MapEntryExpression> createMapEntryList(final List<? extends MapEntr
@Override
public MapEntryExpression visitMapEntry(final MapEntryContext ctx) {
Expression keyExpr;
Expression valueExpr = (Expression) this.visit(ctx.expression());
Expression valueExpr = this.visitEnhancedExpression(ctx.enhancedExpression());

if (asBoolean(ctx.MUL())) {
keyExpr = configureAST(new SpreadMapExpression(valueExpr), ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,4 +530,8 @@ class GroovyParserTest extends GroovyTestCase {
void "test groovy core - GROOVY-10659"() {
doTest('bugs/BUG-GROOVY-10659.groovy');
}

void "test groovy core - GROOVY-11055"() {
doRunAndTestAntlr4('bugs/GROOVY-11055.groovy')
}
}
29 changes: 29 additions & 0 deletions src/test/resources/bugs/GROOVY-11055.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.
*/

def m(Map paramMap) {
def name = paramMap.name
def hello = paramMap.hello
assert 'Hello, Daniel' == hello(name)
def hi = paramMap.hi
if (hi) assert 'Hi, Daniel' == hi(name)
}

m(hello: n -> 'Hello, ' + n, name: 'Daniel')
m(hello: n -> 'Hello, ' + n, hi: n -> 'Hi, ' + n, name: 'Daniel')

0 comments on commit 59b427e

Please sign in to comment.