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

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

commit 1d8c341300c2b7a5ebdb7d0a8281a459fc706385
Author: Daniel Sun <sun...@apache.org>
AuthorDate: Sat May 22 13:49:17 2021 +0800

    GROOVY-9272: Support switch expression
---
 src/antlr/GroovyLexer.g4                           |   1 +
 src/antlr/GroovyParser.g4                          |  32 +++
 .../apache/groovy/parser/antlr4/AstBuilder.java    | 320 ++++++++++++++++++++-
 .../groovy/parser/antlr4/SemanticPredicates.java   |   3 +-
 .../core/SwitchExpression_01x.groovy}              |  32 +--
 .../core/SwitchExpression_02x.groovy}              |  35 +--
 .../core/SwitchExpression_03x.groovy}              |  32 +--
 .../core/SwitchExpression_04x.groovy}              |  33 +--
 .../core/SwitchExpression_05x.groovy}              |  31 +-
 .../core/SwitchExpression_06x.groovy}              |  35 +--
 .../core/SwitchExpression_07x.groovy}              |  42 ++-
 .../core/SwitchExpression_08x.groovy}              |  45 ++-
 .../core/SwitchExpression_09x.groovy}              |  32 +--
 .../core/SwitchExpression_10x.groovy}              |  58 ++--
 .../core/SwitchExpression_11x.groovy               | 111 +++++++
 .../core/SwitchExpression_12x.groovy}              |  37 +--
 .../core/SwitchExpression_13x.groovy}              |  30 +-
 .../core/SwitchExpression_14x.groovy               |  79 +++++
 .../core/SwitchExpression_15x.groovy}              |  35 +--
 .../core/SwitchExpression_16x.groovy}              |  39 ++-
 .../fail/SwitchExpression_01x.groovy}              |  31 +-
 .../fail/SwitchExpression_02x.groovy}              |  31 +-
 .../fail/SwitchExpression_03x.groovy}              |  32 +--
 .../fail/SwitchExpression_04x.groovy}              |  32 +--
 .../fail/SwitchExpression_05x.groovy}              |  31 +-
 .../fail/SwitchExpression_06x.groovy}              |  31 +-
 .../fail/SwitchExpression_07x.groovy}              |  31 +-
 .../fail/SwitchExpression_08x.groovy}              |  31 +-
 src/test/groovy/MethodInBadPositionTest.groovy     |   2 +-
 .../groovy/parser/antlr4/GroovyParserTest.groovy   |  39 ++-
 .../groovy/parser/antlr4/SyntaxErrorTest.groovy    |  13 +-
 .../apache/groovy/parser/antlr4/TestUtils.groovy   |   5 +-
 .../test/org/apache/groovy/ginq/GinqTest.groovy    |  14 +
 33 files changed, 804 insertions(+), 581 deletions(-)

diff --git a/src/antlr/GroovyLexer.g4 b/src/antlr/GroovyLexer.g4
index 6eda984..1d1b9d8 100644
--- a/src/antlr/GroovyLexer.g4
+++ b/src/antlr/GroovyLexer.g4
@@ -408,6 +408,7 @@ fragment
 BOOLEAN       : 'boolean';
 
 BREAK         : 'break';
+YIELD         : 'yield';
 
 fragment
 BYTE          : 'byte';
diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index f971d33..64caa1a 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -45,6 +45,7 @@ options {
 }
 
 @members {
+    private int inSwitchExpressionLevel = 0;
 
     public static class GroovyParserRuleContext extends ParserRuleContext 
implements NodeMetaDataHandler {
         private Map metaDataMap = null;
@@ -614,6 +615,11 @@ breakStatement
         identifier?
     ;
 
+yieldStatement
+    :   YIELD
+        expression
+    ;
+
 tryCatchStatement
     :   TRY resources? nls block
         (nls catchClause)*
@@ -634,6 +640,8 @@ statement
     |   THROW expression                                                       
                             #throwStmtAlt
     |   breakStatement                                                         
                             #breakStmtAlt
     |   continueStatement                                                      
                             #continueStmtAlt
+    |   { inSwitchExpressionLevel > 0 }?
+        yieldStatement                                                         
                             #yieldStmtAlt
     |   identifier COLON nls statement                                         
                             #labeledStmtAlt
     |   assertStatement                                                        
                             #assertStmtAlt
     |   localVariableDeclaration                                               
                             #localVariableDeclarationStmtAlt
@@ -737,6 +745,26 @@ postfixExpression
     :   pathExpression op=(INC | DEC)?
     ;
 
+switchExpression
+@init {
+    inSwitchExpressionLevel++;
+}
+@after {
+    inSwitchExpressionLevel--;
+}
+    :   SWITCH expressionInPar nls LBRACE nls 
switchBlockStatementExpressionGroup* nls RBRACE
+    ;
+
+switchBlockStatementExpressionGroup
+    :   (switchExpressionLabel nls)+ blockStatements
+    ;
+
+switchExpressionLabel
+    :   (   CASE expressionList[true]
+        |   DEFAULT
+        ) ac=(ARROW | COLON)
+    ;
+
 expression
     // must come before postfixExpression to resovle the ambiguities between 
casting and call on parentheses expression, e.g. (int)(1 / 2)
     :   castParExpression castOperandExpression                                
             #castExprAlt
@@ -744,6 +772,8 @@ expression
     // qualified names, array expressions, method invocation, post inc/dec
     |   postfixExpression                                                      
             #postfixExprAlt
 
+    |   switchExpression                                                       
             #switchExprAlt
+
     // ~(BNOT)/!(LNOT) (level 1)
     |   (BITNOT | NOT) nls expression                                          
             #unaryNotExprAlt
 
@@ -1177,6 +1207,7 @@ identifier
 //  |   DEF
     |   TRAIT
     |   AS
+    |   YIELD
     ;
 
 builtInType
@@ -1229,6 +1260,7 @@ keywords
     |   VAR
     |   VOLATILE
     |   WHILE
+    |   YIELD
 
     |   NullLiteral
     |   BooleanLiteral
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 9801be9..fd13e64 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -214,6 +214,7 @@ import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.EnumConstantClassNode;
 import org.codehaus.groovy.ast.FieldNode;
@@ -314,6 +315,13 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static groovy.lang.Tuple.tuple;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.ARROW;
+import static 
org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchBlockStatementExpressionGroupContext;
+import static 
org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchExprAltContext;
+import static 
org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchExpressionContext;
+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;
@@ -339,11 +347,14 @@ 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.util.PositionConfigureUtils.configureAST;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.closureX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 import static org.codehaus.groovy.classgen.asm.util.TypeUtil.isPrimitiveType;
-import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
 
@@ -351,7 +362,6 @@ import static 
org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
  * Builds the AST from the parse tree generated by Antlr4.
  */
 public class AstBuilder extends GroovyParserBaseVisitor<Object> {
-
     public AstBuilder(final SourceUnit sourceUnit, final boolean 
groovydocEnabled, final boolean runtimeGroovydocEnabled) {
         this.sourceUnit = sourceUnit;
         this.moduleNode = new ModuleNode(sourceUnit);
@@ -1009,6 +1019,11 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
 
     @Override
     public ReturnStatement visitReturnStmtAlt(final ReturnStmtAltContext ctx) {
+        GroovyParserRuleContext gprc = switchExpressionRuleContextStack.peek();
+        if (gprc instanceof SwitchExpressionContext) {
+            throw createParsingFailedException("switch expression does not 
support `return`", ctx);
+        }
+
         return configureAST(new ReturnStatement(asBoolean(ctx.expression())
                         ? (Expression) this.visit(ctx.expression())
                         : ConstantExpression.EMPTY_EXPRESSION),
@@ -1037,6 +1052,11 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
             throw createParsingFailedException("break statement is only 
allowed inside loops or switches", ctx);
         }
 
+        GroovyParserRuleContext gprc = switchExpressionRuleContextStack.peek();
+        if (gprc instanceof SwitchExpressionContext) {
+            throw createParsingFailedException("switch expression does not 
support `break`", ctx);
+        }
+
         String label = asBoolean(ctx.identifier())
                 ? this.visitIdentifier(ctx.identifier())
                 : null;
@@ -1045,11 +1065,28 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
     }
 
     @Override
+    public ReturnStatement visitYieldStatement(YieldStatementContext ctx) {
+        ReturnStatement returnStatement = (ReturnStatement) 
returnS((Expression) this.visit(ctx.expression()));
+        returnStatement.putNodeMetaData(IS_YIELD_STATEMENT, true);
+        return configureAST(returnStatement, ctx);
+    }
+
+    @Override
+    public ReturnStatement visitYieldStmtAlt(YieldStmtAltContext ctx) {
+        return configureAST(this.visitYieldStatement(ctx.yieldStatement()), 
ctx);
+    }
+
+    @Override
     public ContinueStatement visitContinueStatement(final 
ContinueStatementContext ctx) {
         if (visitingLoopStatementCount == 0) {
             throw createParsingFailedException("continue statement is only 
allowed inside loops", ctx);
         }
 
+        GroovyParserRuleContext gprc = switchExpressionRuleContextStack.peek();
+        if (gprc instanceof SwitchExpressionContext) {
+            throw createParsingFailedException("switch expression does not 
support `continue`", ctx);
+        }
+
         String label = asBoolean(ctx.identifier())
                 ? this.visitIdentifier(ctx.identifier())
                 : null;
@@ -1058,6 +1095,249 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
 
     }
 
+    @Override
+    public Expression visitSwitchExprAlt(SwitchExprAltContext ctx) {
+        return 
configureAST(this.visitSwitchExpression(ctx.switchExpression()), ctx);
+    }
+
+    /**
+     * <pre>
+     * switch(a) {
+     *     case 0, 1  ->   'a';
+     *     case 2     ->   'b';
+     *     default    ->   'z';
+     * }
+     * </pre>
+     * the above code will be transformed to:
+     * <pre>
+     * {->
+     *     switch(a) {
+     *         case 0:
+     *         case 1:  return 'a';
+     *         case 2:  return 'b';
+     *         default: return 'z';
+     *     }
+     * }()
+     * </pre>
+     *
+     * @param ctx the parse tree
+     * @return {@link MethodCallExpression} instance
+     */
+    @Override
+    public MethodCallExpression visitSwitchExpression(SwitchExpressionContext 
ctx) {
+        switchExpressionRuleContextStack.push(ctx);
+        try {
+            validateSwitchExpressionLabels(ctx);
+            List<Statement> statementList =
+                    ctx.switchBlockStatementExpressionGroup().stream()
+                            .map(e -> 
this.visitSwitchBlockStatementExpressionGroup(e))
+                            .reduce(new LinkedList<>(), (r, e) -> {
+                                r.addAll(e);
+                                return r;
+                            });
+
+            List<CaseStatement> caseStatementList = new LinkedList<>();
+            List<Statement> defaultStatementList = new LinkedList<>();
+
+            statementList.forEach(e -> {
+                if (e instanceof CaseStatement) {
+                    caseStatementList.add((CaseStatement) e);
+                } else if (isTrue(e, IS_SWITCH_DEFAULT)) {
+                    defaultStatementList.add(e);
+                }
+            });
+
+            int defaultStatementListSize = defaultStatementList.size();
+            if (defaultStatementListSize > 1) {
+                throw createParsingFailedException("switch expression should 
have only one default case, which should appear at last", 
defaultStatementList.get(0));
+            }
+
+            if (defaultStatementListSize > 0 && last(statementList) instanceof 
CaseStatement) {
+                throw createParsingFailedException("default case should appear 
at last", defaultStatementList.get(0));
+            }
+
+            SwitchStatement switchStatement = configureAST(
+                    new SwitchStatement(
+                            this.visitExpressionInPar(ctx.expressionInPar()),
+                            caseStatementList,
+                            defaultStatementListSize == 0 ? 
EmptyStatement.INSTANCE : defaultStatementList.get(0)
+                    ),
+                    ctx);
+
+            return configureAST(
+                    callX(
+                            configureAST(
+                                    closureX(
+                                            null,
+                                            
createBlockStatement(switchStatement)
+                                    ),
+                                    ctx
+                            ),
+                            "call"
+                    ),
+                    ctx
+            );
+        } finally {
+            switchExpressionRuleContextStack.pop();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Statement> 
visitSwitchBlockStatementExpressionGroup(SwitchBlockStatementExpressionGroupContext
 ctx) {
+        int labelCnt = ctx.switchExpressionLabel().size();
+        List<Token> firstLabelHolder = new ArrayList<>(1);
+        final int[] arrowCntHolder = new int[1];
+
+        return (List<Statement>) ctx.switchExpressionLabel().stream()
+                .map(e -> (Object) this.visitSwitchExpressionLabel(e))
+                .reduce(new ArrayList<Statement>(4), (r, e) -> {
+                    List<Statement> statementList = (List<Statement>) r;
+                    Tuple3<Token, List<Expression>, Integer> tuple = 
(Tuple3<Token, List<Expression>, Integer>) e;
+
+                    boolean isArrow = ARROW == tuple.getV3();
+                    if (isArrow) {
+                        if (++arrowCntHolder[0] > 1 && 
!firstLabelHolder.isEmpty()) {
+                            throw createParsingFailedException("`case ... ->` 
does not support falling through cases", firstLabelHolder.get(0));
+                        }
+                    }
+
+                    boolean isLast = labelCnt - 1 == statementList.size();
+
+                    BlockStatement codeBlock = 
this.visitBlockStatements(ctx.blockStatements());
+                    List<Statement> statements = codeBlock.getStatements();
+                    int statementsCnt = statements.size();
+                    if (0 == statementsCnt) {
+                        throw createParsingFailedException("`yield` statement 
is expected", ctx.blockStatements());
+                    }
+
+                    if (statementsCnt > 1) {
+                        throw new GroovyBugError("statements count should be 
1, but the count is actually: " + statementsCnt);
+                    }
+
+                    if (!isArrow) {
+                        boolean[] hasYieldHolder = new boolean[1];
+                        boolean[] hasThrowHolder = new boolean[1];
+                        codeBlock.visit(new CodeVisitorSupport() {
+                            @Override
+                            public void visitReturnStatement(ReturnStatement 
statement) {
+                                if (isTrue(statement, IS_YIELD_STATEMENT)) {
+                                    hasYieldHolder[0] = true;
+                                    return;
+                                }
+
+                                super.visitReturnStatement(statement);
+                            }
+
+                            @Override
+                            public void visitThrowStatement(ThrowStatement 
statement) {
+                                hasThrowHolder[0] = true;
+                            }
+                        });
+                        if (!(hasYieldHolder[0] || hasThrowHolder[0])) {
+                            throw createParsingFailedException("`yield` 
statement is expected", ctx.blockStatements());
+                        }
+                    }
+
+                    Statement exprOrBlockStatement = statements.get(0);
+                    if (exprOrBlockStatement instanceof BlockStatement) {
+                        BlockStatement blockStatement = (BlockStatement) 
exprOrBlockStatement;
+                        List<Statement> branchStatementList = 
blockStatement.getStatements();
+                        if (1 == branchStatementList.size()) {
+                            exprOrBlockStatement = branchStatementList.get(0);
+                        }
+                    }
+
+                    if (exprOrBlockStatement instanceof ExpressionStatement) {
+                        statements.remove(exprOrBlockStatement);
+                        appendStatementsToBlockStatement(
+                                codeBlock,
+                                configureAST(
+                                        returnS(((ExpressionStatement) 
exprOrBlockStatement).getExpression()),
+                                        exprOrBlockStatement
+                                )
+                        );
+                    } else if (exprOrBlockStatement instanceof ReturnStatement 
|| exprOrBlockStatement instanceof ThrowStatement) {
+                        // do nothing
+                    } else {
+                        codeBlock = createBlockStatement(configureAST(
+                                returnS(callX(
+                                        configureAST(
+                                                closureX(
+                                                        null,
+                                                        exprOrBlockStatement
+                                                ),
+                                                exprOrBlockStatement
+                                        ),
+                                        "call"
+                                )),
+                                exprOrBlockStatement
+                        ));
+                    }
+
+                    switch (tuple.getV1().getType()) {
+                        case CASE: {
+                            if (!asBoolean(statementList)) {
+                                firstLabelHolder.add(tuple.getV1());
+                            }
+
+                            for (int i = 0, n = tuple.getV2().size(); i < n; 
i++) {
+                                Expression expr = tuple.getV2().get(i);
+
+                                statementList.add(
+                                        configureAST(
+                                                new CaseStatement(
+                                                        expr,
+
+                                                        // check whether 
processing the last label. if yes, block statement should be attached.
+                                                        (isLast && i == n - 1) 
? codeBlock
+                                                                : 
EmptyStatement.INSTANCE
+                                                ),
+                                                firstLabelHolder.get(0)));
+                            }
+
+                            break;
+                        }
+                        case DEFAULT: {
+                            codeBlock.putNodeMetaData(IS_SWITCH_DEFAULT, true);
+
+                            statementList.add(
+                                    // this.configureAST(codeBlock, 
tuple.getKey())
+                                    codeBlock
+                            );
+
+                            break;
+                        }
+                    }
+
+                    return statementList;
+                });
+    }
+
+    private void validateSwitchExpressionLabels(SwitchExpressionContext ctx) {
+        Map<String, List<SwitchExpressionLabelContext>> acMap =
+                ctx.switchBlockStatementExpressionGroup().stream()
+                        .flatMap(e -> e.switchExpressionLabel().stream())
+                        .collect(Collectors.groupingBy(e -> e.ac.getText()));
+        if (acMap.size() > 1) {
+            List<SwitchExpressionLabelContext> lastSelcList = 
acMap.values().stream().reduce((prev, next) -> next).orElse(null);
+            throw 
createParsingFailedException(acMap.keySet().stream().collect(Collectors.joining("`
 and `", "`", "`")) + " cannot be used together", lastSelcList.get(0).ac);
+        }
+    }
+
+    @Override
+    public Tuple3<Token, List<Expression>, Integer> 
visitSwitchExpressionLabel(SwitchExpressionLabelContext ctx) {
+        final Integer acType = ctx.ac.getType();
+        if (asBoolean(ctx.CASE())) {
+            return tuple(ctx.CASE().getSymbol(), 
this.visitExpressionList(ctx.expressionList()), acType);
+        } else if (asBoolean(ctx.DEFAULT())) {
+            return tuple(ctx.DEFAULT().getSymbol(), 
Collections.singletonList(EmptyExpression.INSTANCE), acType);
+        }
+
+        throw createParsingFailedException("Unsupported switch expression 
label: " + ctx.getText(), ctx);
+    }
+
+
     // } statement 
-------------------------------------------------------------
 
     @Override
@@ -3620,7 +3900,12 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
 
     @Override
     public LambdaExpression visitStandardLambdaExpression(final 
StandardLambdaExpressionContext ctx) {
-        return configureAST(this.createLambda(ctx.standardLambdaParameters(), 
ctx.lambdaBody()), ctx);
+        switchExpressionRuleContextStack.push(ctx);
+        try {
+            return 
configureAST(this.createLambda(ctx.standardLambdaParameters(), 
ctx.lambdaBody()), ctx);
+        } finally {
+            switchExpressionRuleContextStack.pop();
+        }
     }
 
     private LambdaExpression createLambda(final 
StandardLambdaParametersContext standardLambdaParametersContext, final 
LambdaBodyContext lambdaBodyContext) {
@@ -3657,22 +3942,27 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
 
     @Override
     public ClosureExpression visitClosure(final ClosureContext ctx) {
-        visitingClosureCount += 1;
+        switchExpressionRuleContextStack.push(ctx);
+        try {
+            visitingClosureCount += 1;
 
-        Parameter[] parameters = asBoolean(ctx.formalParameterList())
-                ? this.visitFormalParameterList(ctx.formalParameterList())
-                : null;
+            Parameter[] parameters = asBoolean(ctx.formalParameterList())
+                    ? this.visitFormalParameterList(ctx.formalParameterList())
+                    : null;
 
-        if (!asBoolean(ctx.ARROW())) {
-            parameters = Parameter.EMPTY_ARRAY;
-        }
+            if (!asBoolean(ctx.ARROW())) {
+                parameters = Parameter.EMPTY_ARRAY;
+            }
 
-        Statement code = 
this.visitBlockStatementsOpt(ctx.blockStatementsOpt());
-        ClosureExpression result = configureAST(new 
ClosureExpression(parameters, code), ctx);
+            Statement code = 
this.visitBlockStatementsOpt(ctx.blockStatementsOpt());
+            ClosureExpression result = configureAST(new 
ClosureExpression(parameters, code), ctx);
 
-        visitingClosureCount -= 1;
+            visitingClosureCount -= 1;
 
-        return result;
+            return result;
+        } finally {
+            switchExpressionRuleContextStack.pop();
+        }
     }
 
     @Override
@@ -4665,6 +4955,7 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
     private final List<ClassNode> classNodeList = new LinkedList<>();
     private final Deque<ClassNode> classNodeStack = new ArrayDeque<>();
     private final Deque<List<InnerClassNode>> 
anonymousInnerClassesDefinedInMethodStack = new ArrayDeque<>();
+    private final Deque<GroovyParserRuleContext> 
switchExpressionRuleContextStack = new ArrayDeque<>();
 
     private Tuple2<GroovyParserRuleContext, Exception> numberFormatError;
 
@@ -4726,4 +5017,5 @@ public class AstBuilder extends 
GroovyParserBaseVisitor<Object> {
     private static final String INTEGER_LITERAL_TEXT = "_INTEGER_LITERAL_TEXT";
     private static final String FLOATING_POINT_LITERAL_TEXT = 
"_FLOATING_POINT_LITERAL_TEXT";
     private static final String ENCLOSING_INSTANCE_EXPRESSION = 
"_ENCLOSING_INSTANCE_EXPRESSION";
+    private static final String IS_YIELD_STATEMENT = "_IS_YIELD_STATEMENT";
 }
diff --git 
a/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java 
b/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
index 78e5877..addfd47 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
@@ -42,6 +42,7 @@ import static 
org.apache.groovy.parser.antlr4.GroovyParser.PathExpressionContext
 import static 
org.apache.groovy.parser.antlr4.GroovyParser.PostfixExprAltContext;
 import static 
org.apache.groovy.parser.antlr4.GroovyParser.PostfixExpressionContext;
 import static org.apache.groovy.parser.antlr4.GroovyParser.StringLiteral;
+import static org.apache.groovy.parser.antlr4.GroovyParser.YIELD;
 import static org.apache.groovy.parser.antlr4.util.StringUtils.matches;
 
 /**
@@ -141,7 +142,7 @@ public class SemanticPredicates {
     public static boolean isInvalidMethodDeclaration(TokenStream ts) {
         int tokenType = ts.LT(1).getType();
 
-        return (Identifier == tokenType || CapitalizedIdentifier == tokenType 
|| StringLiteral == tokenType)
+        return (Identifier == tokenType || CapitalizedIdentifier == tokenType 
|| StringLiteral == tokenType || YIELD == tokenType)
                 && LPAREN == (ts.LT(2).getType());
     }
 
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_01x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_01x.groovy
index 3b288ca..448719e 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_01x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def result = switch(a) {
+    case 8 -> 'b'
+    default -> 'z'
+}
+assert 'z' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_02x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_02x.groovy
index 3b288ca..5574d94 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_02x.groovy
@@ -16,30 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> 'a'
+}
+assert 'a' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 9
+result = switch(a) {
+    case 6 -> 'a'
+}
+assert null == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_03x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_03x.groovy
index 3b288ca..ef46adb 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_03x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def result = switch(a) {
+    case 6, 8 -> 'b'
+    default -> 'z'
+}
+assert 'b' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_04x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_04x.groovy
index 3b288ca..8b773cb 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_04x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 9
+def result = switch(a) {
+    case 6, 8 -> 'b'
+    case 9 -> 'c'
+    default -> 'z'
+}
+assert 'c' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_05x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_05x.groovy
index 3b288ca..5a52c93 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_05x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def result = switch(a) {
+    case 6, 8 -> 1 + 2
+}
+assert 3 == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_06x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_06x.groovy
index 3b288ca..f864a24 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_06x.groovy
@@ -16,30 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6, 8 -> 1.plus 2
+}
+assert 3 == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 8
+result = switch(a) {
+    case 6, 8 -> 1.plus 2
+}
+assert 3 == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_07x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_07x.groovy
index 3b288ca..07e375b 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_07x.groovy
@@ -16,30 +16,24 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 9
+def result = switch(a) {
+    case 6, 8 -> 1.plus 2
+    default -> 1.plus 5
+}
+assert 6 == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
+a = 6
+result = switch(a) {
+    case 6, 8 -> 1.plus 2
+    default -> 1.plus 5
+}
+assert 3 == result
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 8
+result = switch(a) {
+    case 6, 8 -> 1.plus 2
+    default -> 1.plus 5
+}
+assert 3 == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_08x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_08x.groovy
index 3b288ca..0b171f2 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_08x.groovy
@@ -16,30 +16,27 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> { 'a' }
+}
+assert 'a' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
+a = 6
+result = switch(a) {
+    case 6 -> { yield 'a' }
+}
+assert 'a' == result
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 8
+result = switch(a) {
+    case 6, 8 -> { yield 'a' }
+}
+assert 'a' == result
+
+a = 9
+result = switch(a) {
+    case 6, 8 -> { yield 'a' }
+}
+assert null == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_09x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_09x.groovy
index 3b288ca..14e0dd0 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_09x.groovy
@@ -16,30 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 9
+def result = switch(a) {
+    case 6 -> { yield 'a' }
+    default -> { yield 'z' }
+}
+assert 'z' == result
+
+
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_10x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_10x.groovy
index 3b288ca..450fb24 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_10x.groovy
@@ -16,30 +16,44 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> {
+        def n = 1
+        yield 'a' + n
+    }
+    default -> { yield 'z' }
+}
+assert 'a1' == result
+
+a = 8
+result = switch(a) {
+    case 6, 8 -> {
+        def n = 1
+        yield 'a' + n
+    }
+    default -> { yield 'z' }
+}
+assert 'a1' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
+a = 9
+result = switch(a) {
+    case 6, 8 -> {
+        def n = 1
+        yield 'a' + n
     }
+    default -> { yield 'z' }
+}
+assert 'z' == result
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
+a = 9
+result = switch(a) {
+    case 6, 8 -> {
+        def n = 1
+        yield 'a' + n
     }
-}
\ No newline at end of file
+    default -> yield 'z'
+}
+assert 'z' == result
+
diff --git a/src/test-resources/core/SwitchExpression_11x.groovy 
b/src/test-resources/core/SwitchExpression_11x.groovy
new file mode 100644
index 0000000..b8d55f1
--- /dev/null
+++ b/src/test-resources/core/SwitchExpression_11x.groovy
@@ -0,0 +1,111 @@
+/*
+ *  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.
+ */
+
+try {
+    def a = 6
+    def result = switch(a) {
+        case 6 : throw new RuntimeException('a')
+    }
+} catch (e) {
+    assert 'a' == e.message
+}
+
+a = 6
+result = switch(a) {
+    case 6 : yield 'a'
+}
+assert 'a' == result
+
+a = 8
+result = switch(a) {
+    case 6 : yield 'a'
+    default: yield 'b'
+}
+assert 'b' == result
+
+a = 9
+result = switch(a) {
+    case 6, 9 : yield 'a'
+    default: yield 'b'
+}
+assert 'a' == result
+
+a = 7
+result = switch(a) {
+    case 7:
+    case 6, 9 : yield 'a'
+    default: yield 'b'
+}
+assert 'a' == result
+
+
+a = 10
+result = switch(a) {
+    case 7:
+    case 6, 9 : yield 'a'
+    case 10:
+    case 11: yield 'c'
+    default: yield 'b'
+}
+assert 'c' == result
+
+a = 10
+result = switch(a) {
+    case 7:
+    case 6, 9 : yield 'a'
+    case 10:
+    case 11: {
+            def x = 1
+            yield 'c' + x
+        }
+    default: yield 'b'
+}
+assert 'c1' == result
+
+
+a = 6
+result = switch(a) {
+    case 6 : yield 'a'
+}
+assert 'a' == result
+
+a = 6
+result = switch(a) {
+    default : yield 'b'
+}
+assert 'b' == result
+
+a = 6
+result = switch(a) {
+    case 6 : { yield 'a' }
+}
+assert 'a' == result
+
+a = 6
+result = switch(a) {
+    default : { yield 'b' }
+}
+assert 'b' == result
+
+a = 6
+result = switch(a) {
+    case 6  : yield 'a'
+    default : yield 'b'
+}
+assert 'a' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_12x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_12x.groovy
index 3b288ca..bbe8342 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_12x.groovy
@@ -16,30 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> 'a'
+    default-> yield 'b'
+}
+assert 'a' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 6
+result = switch(a) {
+    case 6 -> 'a'
+    default -> yield 'b'
+}
+assert 'a' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_13x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_13x.groovy
index 3b288ca..4a2a7c8 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_13x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def yield (String msg) { return msg }
+def yield () { return 'b' }
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def result = yield 'a'
+assert 'a' == result
+assert 'b'== yield()
diff --git a/src/test-resources/core/SwitchExpression_14x.groovy 
b/src/test-resources/core/SwitchExpression_14x.groovy
new file mode 100644
index 0000000..0a8a661
--- /dev/null
+++ b/src/test-resources/core/SwitchExpression_14x.groovy
@@ -0,0 +1,79 @@
+/*
+ *  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 test() {
+    def a = 2
+    def b = 1
+    def c = 0
+    def d = 99
+    def r = switch (a) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (b) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (c) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (d) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    }
+    assert 'cbaz' == r
+}
+test()
+
+@groovy.transform.CompileStatic
+def testCS() {
+    def a = 2
+    def b = 1
+    def c = 0
+    def d = 99
+    def r = switch (a) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (b) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (c) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (d) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    }
+    assert 'cbaz' == r
+}
+testCS()
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_15x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_15x.groovy
index 3b288ca..58b3a12 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_15x.groovy
@@ -16,30 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
+def a = 9
+def b = 8
+def result = switch(a) {
+    case 8 -> 'a'
+    case 9 -> switch(b) {
+        case 8 -> 'b'
+        default -> 'c'
     }
-}
\ No newline at end of file
+    default -> 'd'
+}
+assert 'b' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/core/SwitchExpression_16x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_16x.groovy
index 3b288ca..028d624 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_16x.groovy
@@ -16,30 +16,23 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
+def a = 6
+try {
+    switch(a) {
+        case 8 -> 'b'
+        default -> throw new RuntimeException('z')
     }
+} catch (e) {
+    assert 'z' == e.message
+}
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
+def r = switch(a) {
+    case 6 -> {
+        def x = 'a'
+        yield x
     }
-}
\ No newline at end of file
+    default -> throw new RuntimeException('z')
+}
+assert 'a' == r
+
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_01x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_01x.groovy
index 3b288ca..df57b27 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_01x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 8 ->
+    case 9 -> 'a'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_02x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_02x.groovy
index 3b288ca..8112793 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_02x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 8 ->
+    default -> 'b'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_03x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_03x.groovy
index 3b288ca..64ddad8 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_03x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 6 ->
+    case 8 ->
+    default -> 'b'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_04x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_04x.groovy
index 3b288ca..82d52da 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_04x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 6 -> 'a'
+    case 8 : yield 'b'
+    default -> 'c'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_05x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_05x.groovy
index 3b288ca..13fbb69 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_05x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def r = switch(a) {
+    case 6 : 'a'
+    default : 'c'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_06x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_06x.groovy
index 3b288ca..a799824 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_06x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def r = switch(a) {
+    case 6 : return 'a'
+    default : return 'c'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_07x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_07x.groovy
index 3b288ca..592051c 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_07x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
+def a = 7
+while (a-- > 0) {
+    def r = switch(a) {
+        case 6 : break
+        default : return 'c'
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test-resources/fail/SwitchExpression_08x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_08x.groovy
index 3b288ca..3c61cfd 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_08x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || 
msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
+def a = 7
+while (a-- > 0) {
+    def r = switch(a) {
+        case 6 : continue
+        default : return 'c'
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy 
b/src/test/groovy/MethodInBadPositionTest.groovy
index 3b288ca..453d75c 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test/groovy/MethodInBadPositionTest.groovy
@@ -40,6 +40,6 @@ class MethodInBadPositionTest extends CompilableTestSupport {
                 case 1: def say(){}
             }
         ''')
-        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('")
+        assert msg.contains('Method definition not expected here')  || 
msg.contains("Unexpected input: '('") || msg.contains("Unexpected input: 
'switch(1)")
     }
 }
\ No newline at end of file
diff --git a/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy 
b/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
index f7f0e59..6c73f99 100644
--- a/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -412,15 +412,34 @@ final class GroovyParserTest extends GroovyTestCase {
     }
 
     void "test groovy core - var"() {
-        doRunAndTestAntlr4('core/Var_01x.groovy');
+        doRunAndTestAntlr4('core/Var_01x.groovy')
     }
 
     void "test groovy core - String"() {
-        doRunAndTestAntlr4('core/String_01x.groovy');
+        doRunAndTestAntlr4('core/String_01x.groovy')
     }
 
     void "test groovy core - NonStaticClass"() {
-        doRunAndTestAntlr4('core/NonStaticClass_01x.groovy');
+        doRunAndTestAntlr4('core/NonStaticClass_01x.groovy')
+    }
+
+    void "test groovy core - SwitchExpression"() {
+        doRunAndTestAntlr4('core/SwitchExpression_01x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_02x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_03x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_04x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_05x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_06x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_07x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_08x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_09x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_10x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_11x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_12x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_13x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_14x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_15x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_16x.groovy')
     }
 
     void "test groovy core - BUG"() {
@@ -445,30 +464,30 @@ final class GroovyParserTest extends GroovyTestCase {
     }
 
     void "test groovy core - GROOVY-9427"() {
-        doTest('bugs/BUG-GROOVY-9427.groovy');
+        doTest('bugs/BUG-GROOVY-9427.groovy')
     }
 
     void "test groovy core - GROOVY-9433"() {
-        doTest('bugs/BUG-GROOVY-9433.groovy');
+        doTest('bugs/BUG-GROOVY-9433.groovy')
     }
 
     void "test groovy core - GROOVY-9449"() {
-        doTest('bugs/BUG-GROOVY-9449.groovy');
+        doTest('bugs/BUG-GROOVY-9449.groovy')
     }
 
     void "test groovy core - GROOVY-9511"() {
-        doTest('bugs/BUG-GROOVY-9511.groovy', [MethodNode]);
+        doTest('bugs/BUG-GROOVY-9511.groovy', [MethodNode])
     }
 
     void "test groovy core - GROOVY-9507"() {
-        doTest('bugs/BUG-GROOVY-9507.groovy');
+        doTest('bugs/BUG-GROOVY-9507.groovy')
     }
 
     void "test groovy core - GROOVY-9522"() {
-        doTest('bugs/BUG-GROOVY-9522.groovy');
+        doTest('bugs/BUG-GROOVY-9522.groovy')
     }
 
     void "test groovy core - GROOVY-9692"() {
-        doTest('bugs/BUG-GROOVY-9692.groovy');
+        doTest('bugs/BUG-GROOVY-9692.groovy')
     }
 }
diff --git a/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy 
b/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
index 4bbe12e..faefccf 100644
--- a/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
@@ -224,7 +224,7 @@ final class SyntaxErrorTest extends GroovyTestCase {
     }
 
     void 'test groovy core - AnnotationDeclaration 1'() {
-        TestUtils.doRunAndShouldFail('fail/AnnotationDeclaration_01x.groovy');
+        TestUtils.doRunAndShouldFail('fail/AnnotationDeclaration_01x.groovy')
     }
 
     void 'test groovy core - AnnotationDeclaration 2'() {
@@ -403,6 +403,17 @@ final class SyntaxErrorTest extends GroovyTestCase {
         TestUtils.doRunAndShouldFail('fail/Array_02x.groovy')
     }
 
+    void "test groovy core - SwitchExpression"() {
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_01x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_02x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_03x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_04x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_05x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_06x.groovy')
+               TestUtils.doRunAndShouldFail('fail/SwitchExpression_07x.groovy')
+               TestUtils.doRunAndShouldFail('fail/SwitchExpression_08x.groovy')
+    }
+
     @NotYetImplemented
     void 'test error alternative - Missing ")" 1'() {
         def err = expectParseError '''\
diff --git a/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy 
b/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy
index 3310447..c8aae4b 100644
--- a/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy
@@ -198,7 +198,7 @@ final class TestUtils {
     }
 
     static void doRunAndTestAntlr4(String path, CompilerConfiguration 
compilerConfiguration = CompilerConfiguration.DEFAULT) {
-        assert executeScript(createAntlr4Shell(compilerConfiguration), 
"$RESOURCES_PATH/$path")
+        assert executeScript(createAntlr4Shell(compilerConfiguration), path)
     }
 
     static void doRunAndTestAntlr2(String path, CompilerConfiguration 
compilerConfiguration = CompilerConfiguration.DEFAULT) {
@@ -255,7 +255,8 @@ final class TestUtils {
     }
 
     private static boolean executeScript(GroovyShell shell, String path) {
-        def file = new File(path)
+        File file = new File("$RESOURCES_PATH/$path")
+        assert file.exists() : "Test resource not found: $file.absolutePath"
         try {
             shell.evaluate(file.text)
             return true
diff --git 
a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy 
b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index 92bf5bc..66762d1 100644
--- 
a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
+++ 
b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -5886,6 +5886,20 @@ class GinqTest {
     }
 
     @Test
+    void "testGinq - switch - 1"() {
+        assertGinqScript '''
+            assert ['a', 'b', 'c', 'c'] == GQ {
+                from n in [1, 2, 3, 4]
+                select switch (n) {
+                    case 1 -> 'a'
+                    case 2 -> 'b'
+                    default -> 'c'
+                }
+            }.toList()
+        '''
+    }
+
+    @Test
     void "testGinq - shutdown - 0"() {
         assertScript '''
             import 
org.apache.groovy.ginq.provider.collection.runtime.QueryableHelper

Reply via email to