You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/06/27 14:21:50 UTC

[groovy] branch GROOVY-9272 updated (24fcf32 -> c572c4b)

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

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


 discard 24fcf32  GROOVY-9272: Support switch expression
     new c572c4b  GROOVY-9272: Support switch expression

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (24fcf32)
            \
             N -- N -- N   refs/heads/GROOVY-9272 (c572c4b)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/antlr/GroovyParser.g4                          |  2 +-
 .../SwitchExpression_22x.groovy}                   | 14 ++++++++-
 .../core/SwitchExpression_23x.groovy}              | 31 ++++++++++----------
 .../core/SwitchExpression_24x.groovy               | 34 +++++++++++++++-------
 .../groovy/parser/antlr4/GroovyParserTest.groovy   |  3 ++
 5 files changed, 56 insertions(+), 28 deletions(-)
 copy src/test-resources/{fail/Number_04x.groovy => core/SwitchExpression_22x.groovy} (68%)
 copy src/{test/groovy/bugs/Groovy8797Bug.groovy => test-resources/core/SwitchExpression_23x.groovy} (66%)
 copy subprojects/groovy-macro/build.gradle => src/test-resources/core/SwitchExpression_24x.groovy (63%)

[groovy] 01/01: GROOVY-9272: Support switch expression

Posted by su...@apache.org.
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 c572c4bc57610670c13dc603b302879840c80cc4
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Jun 27 22:21:32 2021 +0800

    GROOVY-9272: Support switch expression
---
 src/antlr/GroovyLexer.g4                           |   1 +
 src/antlr/GroovyParser.g4                          |  34 ++-
 .../apache/groovy/parser/antlr4/AstBuilder.java    | 309 ++++++++++++++++++++-
 .../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 ++-
 .../core/SwitchExpression_17x.groovy}              |  37 +--
 .../core/SwitchExpression_18x.groovy}              |  33 +--
 .../core/SwitchExpression_19x.groovy}              |  33 +--
 .../core/SwitchExpression_20x.groovy}              |  39 ++-
 .../core/SwitchExpression_21x.groovy}              |  39 ++-
 .../core/SwitchExpression_22x.groovy}              |  36 +--
 .../core/SwitchExpression_23x.groovy}              |  40 ++-
 .../core/SwitchExpression_24x.groovy}              |  49 ++--
 .../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   |  47 +++-
 .../groovy/parser/antlr4/SyntaxErrorTest.groovy    |  13 +-
 .../apache/groovy/parser/antlr4/TestUtils.groovy   |   5 +-
 .../console/ui/text/SmartDocumentFilter.java       |   3 +-
 .../groovy-ginq/src/spec/doc/ginq-userguide.adoc   |   7 +
 .../test/org/apache/groovy/ginq/GinqTest.groovy    |  16 ++
 43 files changed, 925 insertions(+), 777 deletions(-)

diff --git a/src/antlr/GroovyLexer.g4 b/src/antlr/GroovyLexer.g4
index 53532b1..2c58768 100644
--- a/src/antlr/GroovyLexer.g4
+++ b/src/antlr/GroovyLexer.g4
@@ -417,6 +417,7 @@ fragment
 BOOLEAN       : 'boolean';
 
 BREAK         : 'break';
+YIELD         : 'yield';
 
 fragment
 BYTE          : 'byte';
diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index 07f1fae..3faf7ad 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
@@ -717,7 +725,7 @@ expressionInPar
     ;
 
 expressionList[boolean canSpread]
-    :   expressionListElement[$canSpread] (COMMA expressionListElement[$canSpread])*
+    :   expressionListElement[$canSpread] (COMMA nls expressionListElement[$canSpread])*
     ;
 
 expressionListElement[boolean canSpread]
@@ -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 3505867..eea1e49 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,238 @@ 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);
+
+            MethodCallExpression callClosure = callX(
+                    configureAST(
+                            closureX(null, createBlockStatement(switchStatement)),
+                            ctx
+                    ), "call");
+            callClosure.setImplicitThis(false);
+
+            return configureAST(callClosure, 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` 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` or `throw` 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 ReturnStatement || exprOrBlockStatement instanceof ThrowStatement)) {
+                        MethodCallExpression callClosure = callX(
+                                configureAST(
+                                        closureX(null, exprOrBlockStatement),
+                                        exprOrBlockStatement
+                                ), "call");
+                        callClosure.setImplicitThis(false);
+
+                        codeBlock = configureAST(
+                                createBlockStatement(configureAST(
+                                        returnS(
+                                                exprOrBlockStatement instanceof ExpressionStatement
+                                                        ? ((ExpressionStatement) exprOrBlockStatement).getExpression()
+                                                        : callClosure
+                                        ),
+                                        exprOrBlockStatement
+                                )),
+                                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
@@ -3619,7 +3888,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) {
@@ -3656,22 +3930,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
@@ -4664,6 +4943,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;
 
@@ -4725,4 +5005,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/core/SwitchExpression_17x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_17x.groovy
index 3b288ca..aff965b 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_17x.groovy
@@ -16,30 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = '123'
+def r = switch (a) {
+    case String -> 1
+    default -> 2
+}
+assert 1 == r
 
-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 = 123
+r = switch (a) {
+    case String -> 1
+    default -> 2
+}
+assert 2 == r
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_18x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_18x.groovy
index 3b288ca..ba57d6b 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_18x.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
+cnt = 0
+void prt() { cnt++ }
+def a = '123'
+switch (a) {
+    case String -> { prt() }
+}
+assert 1 == cnt
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_19x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_19x.groovy
index 3b288ca..f65840e 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_19x.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
+cnt = 0
+void prt() { cnt++ }
+def a = '123'
+switch (a) {
+    case String -> prt()
+}
+assert 1 == cnt
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_20x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_20x.groovy
index 3b288ca..f0eec8d 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_20x.groovy
@@ -16,30 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
 
-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: '('")
-    }
+@CompileStatic
+String same(String s) { s }
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
+@CompileStatic
+def meth() {
+    def a = 1
+    def r = switch (a) {
+        case 1 -> {
+            if (true) {
+                same 'a'
+            } else {
+                same 'b'
             }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+        }
     }
-}
\ No newline at end of file
+    r + 'z'
+}
+
+assert 'az' == meth()
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_21x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_21x.groovy
index 3b288ca..55bac5a 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_21x.groovy
@@ -16,30 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
 
-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: '('")
-    }
+@CompileStatic
+String same(String s) { s }
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
+@CompileStatic
+def meth() {
+    def a = 1
+    def r = switch (a) {
+        case 1 -> {
+            if (2 == 2) {
+                yield 'hello'
             }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+            yield 'hi'
+        }
+        case 2 -> 'Hello'
     }
-}
\ No newline at end of file
+    r + ', Daniel'
+}
+
+assert 'hello, Daniel' == meth()
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_22x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_22x.groovy
index 3b288ca..ae410da 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_22x.groovy
@@ -16,30 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import java.time.Month
+import static java.time.Month.*
 
-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
+Month month = JUNE
+String quarter = switch (month) {
+    case JANUARY, FEBRUARY, MARCH -> "First Quarter"
+    case APRIL, MAY, JUNE -> "Second Quarter"
+    case JULY, AUGUST, SEPTEMBER -> "Third Quarter"
+    case OCTOBER, NOVEMBER, DECEMBER -> "Forth Quarter"
+    default -> "Unknown Quarter"
+}
+assert 'Second Quarter' == quarter
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_23x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_23x.groovy
index 3b288ca..31b5a14 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_23x.groovy
@@ -16,30 +16,24 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import java.time.Month
+import static java.time.Month.*
 
-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: '('")
+Month month = JUNE
+String quarter = switch (month) {
+    case JANUARY,
+        FEBRUARY,
+        MARCH -> {
+            yield "First Quarter"
+        }
+    case APRIL, MAY, JUNE -> {
+        yield "Second Quarter"
     }
-
-    /** 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: '('")
+    case JULY, AUGUST, SEPTEMBER -> "Third Quarter"
+    case OCTOBER, NOVEMBER, DECEMBER -> {
+        yield "Forth Quarter"
     }
-}
\ No newline at end of file
+    default -> "Unknown Quarter"
+}
+assert 'Second Quarter' == quarter
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_24x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_24x.groovy
index 3b288ca..785008e 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_24x.groovy
@@ -16,30 +16,29 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import java.time.Month
+import static java.time.Month.*
 
-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
+Month month = JUNE
+String quarter = switch (month) {
+    case JANUARY:
+    case FEBRUARY:
+    case MARCH:
+        yield "First Quarter"
+    case APRIL:
+    case MAY:
+    case JUNE:
+        yield "Second Quarter"
+    case JULY:
+    case AUGUST:
+    case SEPTEMBER:
+        yield "Third Quarter"
+    case OCTOBER:
+    case NOVEMBER:
+    case DECEMBER:
+        yield "Forth Quarter"
+    default:
+        yield "Unknown Quarter"
+}
+assert 'Second Quarter' == quarter
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..506d6c0 100644
--- a/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -412,15 +412,42 @@ 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')
+        doRunAndTestAntlr4('core/SwitchExpression_17x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_18x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_19x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_20x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_21x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_22x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_23x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_24x.groovy')
     }
 
     void "test groovy core - BUG"() {
@@ -445,30 +472,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 3b993f7..e5ecbae 100644
--- a/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
@@ -241,7 +241,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'() {
@@ -420,6 +420,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-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java
index 4496873..cdf55b2 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java
@@ -108,6 +108,7 @@ import static org.apache.groovy.parser.antlr4.GroovyLexer.VAR;
 import static org.apache.groovy.parser.antlr4.GroovyLexer.VOID;
 import static org.apache.groovy.parser.antlr4.GroovyLexer.VOLATILE;
 import static org.apache.groovy.parser.antlr4.GroovyLexer.WHILE;
+import static org.apache.groovy.parser.antlr4.GroovyLexer.YIELD;
 
 
 /**
@@ -378,7 +379,7 @@ public class SmartDocumentFilter extends DocumentFilter {
                 VAR, BuiltInPrimitiveType, ABSTRACT, ASSERT, BREAK, CASE, CATCH, CLASS, CONST, CONTINUE, DEFAULT, DO,
                 ELSE, ENUM, EXTENDS, FINAL, FINALLY, FOR, IF, GOTO, IMPLEMENTS, IMPORT, INSTANCEOF, INTERFACE,
                 NATIVE, NEW, PACKAGE, PRIVATE, PROTECTED, PUBLIC, RETURN, STATIC, STRICTFP, SUPER, SWITCH, SYNCHRONIZED,
-                THIS, THROW, THROWS, TRANSIENT, TRY, VOID, VOLATILE, WHILE, NullLiteral, BooleanLiteral)) {
+                THIS, THROW, THROWS, TRANSIENT, TRY, VOID, VOLATILE, WHILE, YIELD, NullLiteral, BooleanLiteral)) {
             Style style = createDefaultStyleByTokenType(t);
             StyleConstants.setBold(style, true);
             StyleConstants.setForeground(style, Color.BLUE.darker().darker());
diff --git a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
index 51dedae..fae4474 100644
--- a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
+++ b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
@@ -912,6 +912,13 @@ GINQ does not support `with` clause for now. We could define a temporary variabl
 include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_12,indent=0]
 ----
 
+==== Alternative for `case-when`
+`case-when` of SQL could be replaced with switch expression:
+[source, groovy]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_13,indent=0]
+----
+
 ==== Query JSON
 [source, groovy]
 ----
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..18182f1 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,22 @@ class GinqTest {
     }
 
     @Test
+    void "testGinq - switch - 1"() {
+        assertGinqScript '''
+// tag::ginq_tips_13[]
+            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()
+// end::ginq_tips_13[]
+        '''
+    }
+
+    @Test
     void "testGinq - shutdown - 0"() {
         assertScript '''
             import org.apache.groovy.ginq.provider.collection.runtime.QueryableHelper