This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY-9381
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY-9381 by this push:
new 646eb6fb18 GROOVY-9381: Support async/await like ES7(grammar)
646eb6fb18 is described below
commit 646eb6fb1868b7c51fa3a872506b9a10a12c0f60
Author: Daniel Sun <[email protected]>
AuthorDate: Sun Oct 26 23:30:16 2025 +0900
GROOVY-9381: Support async/await like ES7(grammar)
---
src/antlr/GroovyLexer.g4 | 3 +
src/antlr/GroovyParser.g4 | 8 +
.../apache/groovy/parser/antlr4/AstBuilder.java | 225 ++++++++++++++++++++-
.../groovy/parser/antlr4/ModifierManager.java | 3 +-
.../java/org/codehaus/groovy/ast/ModifierNode.java | 4 +-
src/test-resources/core/AsyncAwait_01x.groovy | 29 +++
.../util/concurrent/async/AsyncHelperTest.groovy | 198 +++++++++---------
.../groovy/parser/antlr4/GroovyParserTest.groovy | 5 +
8 files changed, 372 insertions(+), 103 deletions(-)
diff --git a/src/antlr/GroovyLexer.g4 b/src/antlr/GroovyLexer.g4
index 79ddf78dbd..cc9eb54377 100644
--- a/src/antlr/GroovyLexer.g4
+++ b/src/antlr/GroovyLexer.g4
@@ -406,7 +406,9 @@ BuiltInPrimitiveType
;
ABSTRACT : 'abstract';
+ASYNC : 'async';
ASSERT : 'assert';
+AWAIT : 'await';
fragment
BOOLEAN : 'boolean';
@@ -485,6 +487,7 @@ VOLATILE : 'volatile';
WHILE : 'while';
YIELD : 'yield';
+
// ยง3.10.1 Integer Literals
IntegerLiteral
diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index b41faad333..fd315dfd91 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -130,6 +130,7 @@ modifier
: classOrInterfaceModifier
| m=( NATIVE
| SYNCHRONIZED
+ | ASYNC
| TRANSIENT
| VOLATILE
| DEF
@@ -776,6 +777,9 @@ expression
// must come before postfixExpression to resolve the ambiguities between
casting and call on parentheses expression, e.g. (int)(1 / 2)
: castParExpression castOperandExpression
#castExprAlt
+ // await expression
+ | AWAIT nls expression
#awaitExprAlt
+
// qualified names, array expressions, method invocation, post inc/dec
| postfixExpression
#postfixExprAlt
@@ -1226,6 +1230,8 @@ identifier
: Identifier
| CapitalizedIdentifier
| AS
+ | ASYNC
+ | AWAIT
| IN
| PERMITS
| RECORD
@@ -1243,7 +1249,9 @@ builtInType
keywords
: ABSTRACT
| AS
+ | ASYNC
| ASSERT
+ | AWAIT
| BREAK
| CASE
| CATCH
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 74d8c062e3..c96fe153f5 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -20,11 +20,13 @@ package org.apache.groovy.parser.antlr4;
import groovy.lang.Tuple2;
import groovy.lang.Tuple3;
+import groovy.transform.Async;
import groovy.transform.CompileStatic;
import groovy.transform.NonSealed;
import groovy.transform.Sealed;
import groovy.transform.Trait;
import groovy.transform.TupleConstructor;
+import groovy.util.concurrent.async.AsyncHelper;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
@@ -39,6 +41,7 @@ import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
+import org.apache.groovy.parser.antlr4.GroovyParser.AwaitExprAltContext;
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;
@@ -97,6 +100,7 @@ import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.RangeExpression;
import org.codehaus.groovy.ast.expr.SpreadExpression;
import org.codehaus.groovy.ast.expr.SpreadMapExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
@@ -151,9 +155,214 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import static groovy.lang.Tuple.tuple;
-import static org.apache.groovy.parser.antlr4.GroovyParser.*;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ADD;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ARROW;
+import static org.apache.groovy.parser.antlr4.GroovyParser.AS;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ASYNC;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AdditiveExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.AndExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AnnotatedQualifiedClassNameContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.AnnotationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AnnotationNameContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AnnotationsOptContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AnonymousInnerClassDeclarationContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ArgumentsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ArrayInitializerContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AssertStatementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.AssignmentExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.BlockContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.BlockStatementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.BlockStatementsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.BlockStatementsOptContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.BooleanLiteralAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.BreakStatementContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.BuiltInTypeContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.CASE;
+import static org.apache.groovy.parser.antlr4.GroovyParser.CastExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.CastParExpressionContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.CatchClauseContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.CatchTypeContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ClassBodyContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ClassBodyDeclarationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ClassDeclarationContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ClassNameContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceModifierContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceModifiersContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ClassOrInterfaceModifiersOptContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ClosureContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ClosureOrLambdaExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.CommandArgumentContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.CommandExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.CommandExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.CompactConstructorDeclarationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.CompilationUnitContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ConditionalExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ConditionalStatementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ContinueStatementContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.CreatedNameContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.CreatorContext;
+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.DoWhileStmtAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.DynamicMemberNameContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ElementValueArrayInitializerContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ElementValueContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ElementValuePairContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ElementValuePairsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ElementValuesContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EnhancedArgumentListElementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EnhancedArgumentListInParContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EnhancedExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EnhancedForControlContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EnhancedStatementExpressionContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.EnumConstantContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EnumConstantsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.EqualityExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ExclusiveOrExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ExpressionInParContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ExpressionListContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ExpressionListElementContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.FINAL;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.FieldDeclarationContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.FinallyBlockContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.FloatingPointLiteralAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ForControlContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ForInitContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ForStmtAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ForUpdateContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.FormalParameterContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.FormalParameterListContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.FormalParametersContext;
+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.GroovyParserRuleContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.GstringContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.GstringPathContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.GstringValueContext;
+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.IdentifierContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.IdentifierPrmrAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.IfElseStatementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ImplicationExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ImportDeclarationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.InclusiveOrExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.IndexPropertyArgsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.IndexVariableContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.IntegerLiteralAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.KeywordsContext;
+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.LabeledStmtAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.LambdaBodyContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ListContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.LocalVariableDeclarationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.LogicalAndExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.LogicalOrExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.LoopStmtAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.MapContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.MapEntryContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.MapEntryLabelContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.MapEntryListContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.MatchingTypeContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.MemberDeclarationContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.MethodBodyContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.MethodDeclarationContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.MethodNameContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ModifierContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ModifiersContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ModifiersOptContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.MultipleAssignmentExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.MultiplicativeExprAltContext;
+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.NamePartContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.NamedPropertyArgsContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.NewPrmrAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.NonWildcardTypeArgumentsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.NullLiteralAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.OriginalForControlContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.PRIVATE;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.PackageDeclarationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ParExpressionContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.PathElementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.PathExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.PostfixExpressionContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.PowerExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.PrimitiveTypeContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.QualifiedClassNameContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.QualifiedClassNameListContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.QualifiedNameContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.QualifiedNameElementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.QualifiedStandardClassNameContext;
+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.ReferenceTypeContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.RegexExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.RelationalExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ResourceContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ResourceListContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ResourcesContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ReturnStmtAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ReturnTypeContext;
+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.ScriptStatementsContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ShiftExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.StandardLambdaExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.StandardLambdaParametersContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.StatementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.StringLiteralContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.SuperPrmrAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SwitchBlockStatementExpressionGroupContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SwitchBlockStatementGroupContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SwitchExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SwitchExpressionContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SwitchExpressionLabelContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.SwitchLabelContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SwitchStatementContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.SynchronizedStmtAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.ThisFormalParameterContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ThisPrmrAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.ThrowStmtAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TryCatchStatementContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.TypeArgumentContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TypeArgumentsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TypeArgumentsOrDiamondContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.TypeBoundContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.TypeContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TypeDeclarationContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.TypeListContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.TypeNamePairContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TypeNamePairsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TypeParameterContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.TypeParametersContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.UnaryAddExprAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.UnaryNotExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.VAR;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclarationContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclaratorContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclaratorIdContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableDeclaratorsContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableInitializerContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableModifierContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableModifiersContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableModifiersOptContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.VariableNamesContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.WhileStmtAltContext;
+import static
org.apache.groovy.parser.antlr4.GroovyParser.YieldStatementContext;
+import static org.apache.groovy.parser.antlr4.GroovyParser.YieldStmtAltContext;
import static
org.apache.groovy.parser.antlr4.util.PositionConfigureUtils.configureAST;
import static
org.apache.groovy.parser.antlr4.util.PositionConfigureUtils.configureEndPosition;
+import static org.codehaus.groovy.ast.ClassHelper.make;
import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
@@ -1758,6 +1967,11 @@ public class AstBuilder extends
GroovyParserBaseVisitor<Object> {
methodNode.getVariableScope().setInStaticContext(true);
}
+ if (modifierManager.containsAny(ASYNC)) {
+ AnnotationNode asyncAnnotationNode =
makeAnnotationNode(Async.class);
+ methodNode.addAnnotation(asyncAnnotationNode);
+ }
+
configureAST(methodNode, ctx);
validateMethodDeclaration(ctx, methodNode, modifierManager, classNode);
@@ -2944,6 +3158,13 @@ public class AstBuilder extends
GroovyParserBaseVisitor<Object> {
return configureAST(cast, ctx);
}
+ @Override
+ public Expression visitAwaitExprAlt(AwaitExprAltContext ctx) {
+ Expression expr = (Expression) this.visit(ctx.expression());
+ StaticMethodCallExpression awaitMethodCallExpression =
callX(ASYNC_HELPER_TYPE, "await", expr);
+ return configureAST(awaitMethodCallExpression, ctx);
+ }
+
@Override
public BinaryExpression visitPowerExprAlt(final PowerExprAltContext ctx) {
return this.createBinaryExpression(ctx.left, ctx.op, ctx.right, ctx);
@@ -4795,6 +5016,8 @@ public class AstBuilder extends
GroovyParserBaseVisitor<Object> {
private Tuple2<GroovyParserRuleContext, Exception> numberFormatError;
+ private static final ClassNode ASYNC_HELPER_TYPE = make(AsyncHelper.class);
+
private int visitingClosureCount;
private int visitingLoopStatementCount;
private int visitingSwitchStatementCount;
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/ModifierManager.java
b/src/main/java/org/apache/groovy/parser/antlr4/ModifierManager.java
index 4d86449b8d..c4a903a55f 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/ModifierManager.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/ModifierManager.java
@@ -41,13 +41,14 @@ import static
org.apache.groovy.parser.antlr4.GroovyLangParser.FINAL;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.NATIVE;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.STATIC;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.VOLATILE;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.ASYNC;
/**
* Process modifiers for AST nodes
*/
class ModifierManager {
private static final Map<Class, List<Integer>> INVALID_MODIFIERS_MAP =
Maps.of(
- ConstructorNode.class, Arrays.asList(STATIC, FINAL, ABSTRACT,
NATIVE),
+ ConstructorNode.class, Arrays.asList(STATIC, FINAL, ABSTRACT,
NATIVE, ASYNC),
MethodNode.class, Arrays.asList(VOLATILE/*, TRANSIENT*/) //
Transient is left open for properties for legacy reasons but should be removed
before ClassCompletionVerifier runs (CLASSGEN)
);
private AstBuilder astBuilder;
diff --git a/src/main/java/org/codehaus/groovy/ast/ModifierNode.java
b/src/main/java/org/codehaus/groovy/ast/ModifierNode.java
index e76e1b4849..83f86e98fb 100644
--- a/src/main/java/org/codehaus/groovy/ast/ModifierNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ModifierNode.java
@@ -27,6 +27,7 @@ import java.util.Objects;
import static org.apache.groovy.parser.antlr4.GroovyParser.ABSTRACT;
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.ASYNC;
import static org.apache.groovy.parser.antlr4.GroovyParser.FINAL;
import static org.apache.groovy.parser.antlr4.GroovyParser.NATIVE;
import static org.apache.groovy.parser.antlr4.GroovyParser.NON_SEALED;
@@ -72,7 +73,8 @@ public class ModifierNode extends ASTNode {
NON_SEALED, 0,
FINAL, Opcodes.ACC_FINAL,
STRICTFP, Opcodes.ACC_STRICT,
- DEFAULT, 0 // no flag for specifying a default method in the JVM
spec, hence no ACC_DEFAULT flag in ASM
+ DEFAULT, 0, // no flag for specifying a default method in the JVM
spec, hence no ACC_DEFAULT flag in ASM
+ ASYNC, 0 // a virtual modifier with no corresponding JVM flag
);
public ModifierNode(Integer type) {
diff --git a/src/test-resources/core/AsyncAwait_01x.groovy
b/src/test-resources/core/AsyncAwait_01x.groovy
new file mode 100644
index 0000000000..1bcbf169c8
--- /dev/null
+++ b/src/test-resources/core/AsyncAwait_01x.groovy
@@ -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.
+ */
+async fetchData() {
+ return 1
+}
+
+async processData() {
+ def data = await fetchData()
+ return data + 2
+}
+
+def result = await processData() // TODO should we support top-level await?
+assert result == 3
diff --git
a/src/test/groovy/groovy/util/concurrent/async/AsyncHelperTest.groovy
b/src/test/groovy/groovy/util/concurrent/async/AsyncHelperTest.groovy
index 20a288ad42..44a06b489e 100644
--- a/src/test/groovy/groovy/util/concurrent/async/AsyncHelperTest.groovy
+++ b/src/test/groovy/groovy/util/concurrent/async/AsyncHelperTest.groovy
@@ -32,8 +32,6 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
-import static groovy.util.concurrent.async.AsyncHelper.async
-import static groovy.util.concurrent.async.AsyncHelper.await
import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertFalse
import static org.junit.jupiter.api.Assertions.assertNotNull
@@ -52,50 +50,50 @@ class AsyncHelperTest {
@Test
@DisplayName("should execute simple async operation")
void testSimpleAsync() {
- Promise<Integer> promise = async(() -> 42)
- Integer result = await(promise)
+ Promise<Integer> promise = AsyncHelper.async(() -> 42)
+ Integer result = AsyncHelper.await(promise)
assertEquals(42, result)
}
@Test
@DisplayName("should execute async operation with string")
void testAsyncWithString() {
- Promise<String> promise = async(() -> "Hello, Async!")
- String result = await(promise)
+ Promise<String> promise = AsyncHelper.async(() -> "Hello, Async!")
+ String result = AsyncHelper.await(promise)
assertEquals("Hello, Async!", result)
}
@Test
@DisplayName("should handle async operation returning null")
void testAsyncReturningNull() {
- Promise<Object> promise = async(() -> null)
- Object result = await(promise)
+ Promise<Object> promise = AsyncHelper.async(() -> null)
+ Object result = AsyncHelper.await(promise)
assertNull(result)
}
@Test
@DisplayName("should execute multiple async operations")
void testMultipleAsyncOperations() {
- Promise<Integer> p1 = async(() -> 10)
- Promise<Integer> p2 = async(() -> 20)
- Promise<Integer> p3 = async(() -> 30)
+ Promise<Integer> p1 = AsyncHelper.async(() -> 10)
+ Promise<Integer> p2 = AsyncHelper.async(() -> 20)
+ Promise<Integer> p3 = AsyncHelper.async(() -> 30)
- assertEquals(10, await(p1))
- assertEquals(20, await(p2))
- assertEquals(30, await(p3))
+ assertEquals(10, AsyncHelper.await(p1))
+ assertEquals(20, AsyncHelper.await(p2))
+ assertEquals(30, AsyncHelper.await(p3))
}
@Test
@DisplayName("should handle computation in async")
void testAsyncComputation() {
- Promise<Integer> promise = async(() -> {
+ Promise<Integer> promise = AsyncHelper.async(() -> {
int sum = 0
for (int i = 1; i <= 100; i++) {
sum += i
}
return sum
})
- assertEquals(5050, await(promise))
+ assertEquals(5050, AsyncHelper.await(promise))
}
}
@@ -117,12 +115,12 @@ class AsyncHelperTest {
customExecutor = Executors.newSingleThreadExecutor()
AtomicReference<String> threadName = new AtomicReference<>()
- Promise<Integer> promise = async(() -> {
+ Promise<Integer> promise = AsyncHelper.async(() -> {
threadName.set(Thread.currentThread().getName())
return 100
}, customExecutor)
- assertEquals(100, await(promise))
+ assertEquals(100, AsyncHelper.await(promise))
assertNotNull(threadName.get())
}
@@ -131,11 +129,11 @@ class AsyncHelperTest {
void testMultipleOperationsWithCustomExecutor() {
customExecutor = Executors.newFixedThreadPool(2)
- Promise<Integer> p1 = async(() -> 1, customExecutor)
- Promise<Integer> p2 = async(() -> 2, customExecutor)
- Promise<Integer> p3 = async(() -> 3, customExecutor)
+ Promise<Integer> p1 = AsyncHelper.async(() -> 1, customExecutor)
+ Promise<Integer> p2 = AsyncHelper.async(() -> 2, customExecutor)
+ Promise<Integer> p3 = AsyncHelper.async(() -> 3, customExecutor)
- assertEquals(6, await(p1) + await(p2) + await(p3))
+ assertEquals(6, AsyncHelper.await(p1) + AsyncHelper.await(p2) +
AsyncHelper.await(p3))
}
@Test
@@ -146,12 +144,12 @@ class AsyncHelperTest {
for (int i = 0; i < 10; i++) {
final int value = i
- promises.add(async(() -> value * 2, customExecutor))
+ promises.add(AsyncHelper.async(() -> value * 2,
customExecutor))
}
int sum = 0
for (Promise<Integer> p : promises) {
- sum += await(p)
+ sum += AsyncHelper.await(p)
}
assertEquals(90, sum)
}
@@ -164,24 +162,24 @@ class AsyncHelperTest {
@Test
@DisplayName("should chain async operations like Promise.then()")
void testChainedAsync() {
- Promise<Integer> result = async(() -> 10)
+ Promise<Integer> result = AsyncHelper.async(() -> 10)
.thenApply(n -> n * 2)
.thenApply(n -> n + 5)
- assertEquals(25, await(result))
+ assertEquals(25, AsyncHelper.await(result))
}
@Test
@DisplayName("should handle sequential async operations")
void testSequentialAsync() {
- Promise<String> step1 = async(() -> "Step1")
- String result1 = await(step1)
+ Promise<String> step1 = AsyncHelper.async(() -> "Step1")
+ String result1 = AsyncHelper.await(step1)
- Promise<String> step2 = async(() -> result1 + "-Step2")
- String result2 = await(step2)
+ Promise<String> step2 = AsyncHelper.async(() -> result1 + "-Step2")
+ String result2 = AsyncHelper.await(step2)
- Promise<String> step3 = async(() -> result2 + "-Step3")
- String result3 = await(step3)
+ Promise<String> step3 = AsyncHelper.async(() -> result2 + "-Step3")
+ String result3 = AsyncHelper.await(step3)
assertEquals("Step1-Step2-Step3", result3)
}
@@ -190,45 +188,45 @@ class AsyncHelperTest {
@DisplayName("should handle parallel async operations like
Promise.all()")
@Timeout(2)
void testParallelAsync() {
- Promise<Integer> p1 = async(() -> {
+ Promise<Integer> p1 = AsyncHelper.async(() -> {
sleep(100)
return 1
})
- Promise<Integer> p2 = async(() -> {
+ Promise<Integer> p2 = AsyncHelper.async(() -> {
sleep(100)
return 2
})
- Promise<Integer> p3 = async(() -> {
+ Promise<Integer> p3 = AsyncHelper.async(() -> {
sleep(100)
return 3
})
Promise<Void> all = SimplePromise.allOf(p1, p2, p3)
- await(all)
+ AsyncHelper.await(all)
- assertEquals(1, await(p1))
- assertEquals(2, await(p2))
- assertEquals(3, await(p3))
+ assertEquals(1, AsyncHelper.await(p1))
+ assertEquals(2, AsyncHelper.await(p2))
+ assertEquals(3, AsyncHelper.await(p3))
}
@Test
@DisplayName("should handle race conditions like Promise.race()")
@Timeout(1)
void testAsyncRace() {
- Promise<String> slow = async(() -> {
+ Promise<String> slow = AsyncHelper.async(() -> {
sleep(500)
return "slow"
})
- Promise<String> fast = async(() -> {
+ Promise<String> fast = AsyncHelper.async(() -> {
sleep(50)
return "fast"
})
Promise<Object> winner = SimplePromise.anyOf(fast, slow)
- String result = await(winner)
+ String result = AsyncHelper.await(winner)
assertEquals("fast", result)
}
@@ -236,7 +234,7 @@ class AsyncHelperTest {
@Test
@DisplayName("should handle async/await with exception handling")
void testAsyncWithExceptionHandling() {
- Promise<Integer> promise = async(() -> {
+ Promise<Integer> promise = AsyncHelper.async(() -> {
throw new RuntimeException("Simulated error")
})
@@ -245,13 +243,13 @@ class AsyncHelperTest {
return -1
})
- assertEquals(-1, await(recovered))
+ assertEquals(-1, AsyncHelper.await(recovered))
}
@Test
@DisplayName("should handle async/await with data transformation
pipeline")
void testAsyncDataPipeline() {
- Promise<? extends List<Integer>> result = async(() -> List.of(1,
2, 3, 4, 5))
+ Promise<? extends List<Integer>> result = AsyncHelper.async(() ->
List.of(1, 2, 3, 4, 5))
.thenApply(list -> {
List<Integer> doubled = new ArrayList<>()
for (Integer n : list) {
@@ -270,18 +268,18 @@ class AsyncHelperTest {
})
List<Integer> expected = List.of(6, 8, 10)
- assertEquals(expected, await(result))
+ assertEquals(expected, AsyncHelper.await(result))
}
@Test
@DisplayName("should handle nested async operations")
void testNestedAsync() {
- Promise<Integer> outer = async(() -> {
- Promise<Integer> inner = async(() -> 5)
- return await(inner) * 2
+ Promise<Integer> outer = AsyncHelper.async(() -> {
+ Promise<Integer> inner = AsyncHelper.async(() -> 5)
+ return AsyncHelper.await(inner) * 2
})
- assertEquals(10, await(outer))
+ assertEquals(10, AsyncHelper.await(outer))
}
}
@@ -294,7 +292,7 @@ class AsyncHelperTest {
void testAsyncRetryPattern() {
AtomicInteger attempts = new AtomicInteger(0)
- Promise<String> result = async(() -> {
+ Promise<String> result = AsyncHelper.async(() -> {
int count = attempts.incrementAndGet()
if (count < 3) {
throw new RuntimeException("Not ready yet")
@@ -302,13 +300,13 @@ class AsyncHelperTest {
return "Success after " + count + " attempts"
}).exceptionallyCompose(ex -> {
sleep(50)
- return async(() -> {
+ return AsyncHelper.async(() -> {
int count = attempts.incrementAndGet()
return "Success after " + count + " attempts"
})
})
- String finalResult = await(result)
+ String finalResult = AsyncHelper.await(result)
assertTrue(finalResult.contains("Success"))
assertTrue(attempts.get() >= 2)
}
@@ -317,7 +315,7 @@ class AsyncHelperTest {
@DisplayName("should handle async timeout pattern")
@Timeout(1)
void testAsyncTimeoutPattern() throws Exception {
- Promise<String> slowTask = async(() -> {
+ Promise<String> slowTask = AsyncHelper.async(() -> {
sleep(5000)
return "completed"
})
@@ -337,12 +335,12 @@ class AsyncHelperTest {
List<Promise<Integer>> squarePromises = new ArrayList<>()
for (Integer n : numbers) {
def tmpN = n
- squarePromises.add(async(() -> tmpN * tmpN))
+ squarePromises.add(AsyncHelper.async(() -> tmpN * tmpN))
}
int total = 0
for (Promise<Integer> p : squarePromises) {
- total += await(p)
+ total += AsyncHelper.await(p)
}
assertEquals(55, total)
@@ -351,24 +349,24 @@ class AsyncHelperTest {
@Test
@DisplayName("should handle async combine operations")
void testAsyncCombine() {
- Promise<Integer> p1 = async(() -> 10)
- Promise<Integer> p2 = async(() -> 20)
+ Promise<Integer> p1 = AsyncHelper.async(() -> 10)
+ Promise<Integer> p2 = AsyncHelper.async(() -> 20)
Promise<Integer> combined = p1.thenCombine(p2, Integer::sum)
- assertEquals(30, await(combined))
+ assertEquals(30, AsyncHelper.await(combined))
}
@Test
@DisplayName("should handle async compose operations")
void testAsyncCompose() {
- Promise<Integer> initial = async(() -> 5)
+ Promise<Integer> initial = AsyncHelper.async(() -> 5)
Promise<Integer> composed = initial.thenCompose(n ->
- async(() -> n * 3)
+ AsyncHelper.async(() -> n * 3)
)
- assertEquals(15, await(composed))
+ assertEquals(15, AsyncHelper.await(composed))
}
}
@@ -379,7 +377,7 @@ class AsyncHelperTest {
@Test
@DisplayName("should simulate API call with data transformation")
void testSimulateApiCall() {
- Promise<String> apiCall = async(() -> {
+ Promise<String> apiCall = AsyncHelper.async(() -> {
sleep(50)
return "{\"userId\":1,\"name\":\"John\"}"
})
@@ -388,7 +386,7 @@ class AsyncHelperTest {
json.replace("John", "Jane")
)
- String result = await(transformed)
+ String result = AsyncHelper.await(transformed)
assertTrue(result.contains("Jane"))
assertFalse(result.contains("John"))
}
@@ -397,17 +395,17 @@ class AsyncHelperTest {
@DisplayName("should handle multiple parallel API calls")
@Timeout(1)
void testMultipleParallelApiCalls() {
- Promise<String> userApi = async(() -> {
+ Promise<String> userApi = AsyncHelper.async(() -> {
sleep(100)
return "User data"
})
- Promise<String> orderApi = async(() -> {
+ Promise<String> orderApi = AsyncHelper.async(() -> {
sleep(100)
return "Order data"
})
- Promise<String> productApi = async(() -> {
+ Promise<String> productApi = AsyncHelper.async(() -> {
sleep(100)
return "Product data"
})
@@ -415,7 +413,7 @@ class AsyncHelperTest {
Promise<String> combined = userApi.thenCombine(orderApi, (u, o) ->
u + ", " + o)
.thenCombine(productApi, (uo, p) -> uo + ", " + p)
- String result = await(combined)
+ String result = AsyncHelper.await(combined)
assertEquals("User data, Order data, Product data", result)
}
@@ -425,7 +423,7 @@ class AsyncHelperTest {
AtomicReference<String> cache = new AtomicReference<>()
AtomicInteger fetchCount = new AtomicInteger(0)
- Promise<String> getCachedData = async(() -> {
+ Promise<String> getCachedData = AsyncHelper.async(() -> {
if (cache.get() != null) {
return cache.get()
}
@@ -436,12 +434,12 @@ class AsyncHelperTest {
return data
})
- String firstCall = await(getCachedData)
+ String firstCall = AsyncHelper.await(getCachedData)
assertEquals("Fresh data", firstCall)
assertEquals(1, fetchCount.get())
- Promise<String> secondCall = async(() -> cache.get())
- assertEquals("Fresh data", await(secondCall))
+ Promise<String> secondCall = AsyncHelper.async(() -> cache.get())
+ assertEquals("Fresh data", AsyncHelper.await(secondCall))
assertEquals(1, fetchCount.get())
}
@@ -455,7 +453,7 @@ class AsyncHelperTest {
List<Promise<Void>> tasks = new ArrayList<>()
for (Integer item : queue) {
def tmp = item
- tasks.add(async(() -> {
+ tasks.add(AsyncHelper.async(() -> {
sleep(50)
processed.addAndGet(tmp)
return
@@ -463,7 +461,7 @@ class AsyncHelperTest {
}
Promise<Void> allProcessed = SimplePromise.allOf(tasks as
Promise[])
- await(allProcessed)
+ AsyncHelper.await(allProcessed)
assertEquals(150, processed.get())
}
@@ -473,15 +471,15 @@ class AsyncHelperTest {
void testAsyncBatchProcessing() {
List<Integer> batch = List.of(1, 2, 3, 4, 5)
- Promise<Integer> batchSum = async(() -> {
+ Promise<Integer> batchSum = AsyncHelper.async(() -> {
int sum = 0
for (Integer item : batch) {
- sum += await(async(() -> item * 2))
+ sum += AsyncHelper.await(AsyncHelper.async(() -> item * 2))
}
return sum
})
- assertEquals(30, await(batchSum))
+ assertEquals(30, AsyncHelper.await(batchSum))
}
}
@@ -492,28 +490,28 @@ class AsyncHelperTest {
@Test
@DisplayName("should propagate exceptions in async chain")
void testExceptionPropagation() {
- Promise<Integer> promise = async(() -> 10)
+ Promise<Integer> promise = AsyncHelper.async(() -> 10)
.thenApply(n -> {
throw new RuntimeException("Chain error")
})
- assertThrows(AwaitException.class, () -> await(promise))
+ assertThrows(AwaitException.class, () ->
AsyncHelper.await(promise))
}
@Test
@DisplayName("should handle exception in async operation")
void testAsyncException() {
- Promise<Integer> promise = async(() -> {
+ Promise<Integer> promise = AsyncHelper.async(() -> {
throw new IllegalStateException("Async error")
})
- assertThrows(AwaitException.class, () -> await(promise))
+ assertThrows(AwaitException.class, () ->
AsyncHelper.await(promise))
}
@Test
@DisplayName("should recover from exception with fallback")
void testExceptionRecovery() {
- Promise<Object> promise = async(() -> {
+ Promise<Object> promise = AsyncHelper.async(() -> {
throw new RuntimeException("Error")
}).handle((result, ex) -> {
if (ex != null) {
@@ -522,31 +520,31 @@ class AsyncHelperTest {
return result
})
- assertEquals("Fallback value", await(promise))
+ assertEquals("Fallback value", AsyncHelper.await(promise))
}
@Test
@DisplayName("should handle exception with exceptionally")
void testExceptionallyHandler() {
- Promise<Integer> promise = async(() -> {
+ Promise<Integer> promise = AsyncHelper.async(() -> {
throw new RuntimeException("Error")
}).exceptionally(ex -> {
assertTrue(ex.getCause() instanceof RuntimeException)
return 999
})
- assertEquals(999, await(promise))
+ assertEquals(999, AsyncHelper.await(promise))
}
@Test
@DisplayName("should handle null pointer exception")
void testNullPointerException() {
- Promise<String> promise = async(() -> {
+ Promise<String> promise = AsyncHelper.async(() -> {
String s = null
return s.length() + ""
})
- assertThrows(AwaitException.class, () -> await(promise))
+ assertThrows(AwaitException.class, () ->
AsyncHelper.await(promise))
}
}
@@ -562,7 +560,7 @@ class AsyncHelperTest {
CountDownLatch latch = new CountDownLatch(100)
for (int i = 0; i < 100; i++) {
- async(() -> {
+ AsyncHelper.async(() -> {
counter.incrementAndGet()
latch.countDown()
return null
@@ -580,14 +578,14 @@ class AsyncHelperTest {
List<Promise<Void>> promises = new ArrayList<>()
for (int i = 0; i < 10; i++) {
- promises.add(async(() -> {
+ promises.add(AsyncHelper.async(() -> {
shared.incrementAndGet()
return
}))
}
for (Promise<Void> p : promises) {
- await(p)
+ AsyncHelper.await(p)
}
assertEquals(10, shared.get())
@@ -601,38 +599,38 @@ class AsyncHelperTest {
@Test
@DisplayName("should handle empty result")
void testEmptyResult() {
- Promise<Void> promise = async(() -> null)
- assertNull(await(promise))
+ Promise<Void> promise = AsyncHelper.async(() -> null)
+ assertNull(AsyncHelper.await(promise))
}
@Test
@DisplayName("should handle boolean results")
void testBooleanResults() {
- Promise<Boolean> truePromise = async(() -> true)
- Promise<Boolean> falsePromise = async(() -> false)
+ Promise<Boolean> truePromise = AsyncHelper.async(() -> true)
+ Promise<Boolean> falsePromise = AsyncHelper.async(() -> false)
- assertTrue(await(truePromise))
- assertFalse(await(falsePromise))
+ assertTrue(AsyncHelper.await(truePromise))
+ assertFalse(AsyncHelper.await(falsePromise))
}
@Test
@DisplayName("should handle long running tasks")
@Timeout(2)
void testLongRunningTask() {
- Promise<String> promise = async(() -> {
+ Promise<String> promise = AsyncHelper.async(() -> {
sleep(500)
return "Long task completed"
})
- assertEquals("Long task completed", await(promise))
+ assertEquals("Long task completed", AsyncHelper.await(promise))
}
@Test
@DisplayName("should handle immediate completion")
void testImmediateCompletion() {
long start = System.currentTimeMillis()
- Promise<String> promise = async(() -> "Immediate")
- String result = await(promise)
+ Promise<String> promise = AsyncHelper.async(() -> "Immediate")
+ String result = AsyncHelper.await(promise)
long duration = System.currentTimeMillis() - start
assertEquals("Immediate", result)
diff --git
a/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
b/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
index 60973387db..35fd8fb3b5 100644
--- a/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -345,6 +345,11 @@ final class GroovyParserTest {
doTest('core/Label_01.groovy')
}
+ @Test
+ void 'groovy core - async-await'() {
+ doRunAndTestAntlr4('core/AsyncAwait_01x.groovy')
+ }
+
@Test
void 'groovy core - LocalVariableDeclaration'() {
doTest('core/LocalVariableDeclaration_01.groovy', [Token]) // [class
org.codehaus.groovy.syntax.Token][startLine]:: 9 != 8