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