< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

Print this page
rev 51258 : imported patch switch.diff

@@ -26,10 +26,11 @@
 package com.sun.tools.javac.parser;
 
 import java.util.*;
 import java.util.stream.Collectors;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Source.Feature;

@@ -222,10 +223,11 @@
     protected static final int EXPR = 0x1;
     protected static final int TYPE = 0x2;
     protected static final int NOPARAMS = 0x4;
     protected static final int TYPEARG = 0x8;
     protected static final int DIAMOND = 0x10;
+    protected static final int NOLAMBDA = 0x20;
 
     /** The current mode.
      */
     protected int mode = 0;
 

@@ -1191,11 +1193,11 @@
                 t = insertAnnotationsToMostInner(expr, typeAnnos, false);
             }
             break;
         case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
             if (typeArgs != null) return illegal();
-            if ((mode & EXPR) != 0 && peekToken(ARROW)) {
+            if ((mode & EXPR) != 0 && (mode & NOLAMBDA) == 0 && peekToken(ARROW)) {
                 t = lambdaExpressionOrStatement(false, false, pos);
             } else {
                 t = toP(F.at(token.pos).Ident(ident()));
                 loop: while (true) {
                     pos = token.pos;

@@ -1354,16 +1356,86 @@
                 nextToken();
                 return ti;
                 //return illegal();
             }
             break;
+        case SWITCH:
+            checkSourceLevel(Feature.SWITCH_EXPRESSION);
+            int switchPos = token.pos;
+            nextToken();
+            JCExpression selector = parExpression();
+            accept(LBRACE);
+            ListBuffer<JCCase> cases = new ListBuffer<>();
+            while (true) {
+                pos = token.pos;
+                switch (token.kind) {
+                case CASE:
+                case DEFAULT:
+                    cases.appendList(switchExpressionStatementGroup());
+                    break;
+                case RBRACE: case EOF:
+                    JCSwitchExpression e = to(F.at(switchPos).SwitchExpression(selector,
+                                                                               cases.toList()));
+                    accept(RBRACE);
+                    return e;
+                default:
+                    nextToken(); // to ensure progress
+                    syntaxError(pos, Errors.Expected3(CASE, DEFAULT, RBRACE));
+                }
+            }
         default:
             return illegal();
         }
         return term3Rest(t, typeArgs);
     }
 
+    private List<JCCase> switchExpressionStatementGroup() {
+        ListBuffer<JCCase> caseExprs = new ListBuffer<>();
+        int casePos = token.pos;
+        ListBuffer<JCExpression> pats = new ListBuffer<>();
+
+        if (token.kind == DEFAULT) {
+            nextToken();
+        } else {
+            accept(CASE);
+            while (true) {
+                pats.append(term(EXPR | NOLAMBDA));
+                if (token.kind != COMMA) break;
+                checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
+                nextToken();
+            };
+        }
+        List<JCStatement> stats = null;
+        JCTree body = null;
+        @SuppressWarnings("removal")
+        CaseKind kind;
+        switch (token.kind) {
+            case ARROW:
+                checkSourceLevel(Feature.SWITCH_RULE);
+                nextToken();
+                if (token.kind == TokenKind.THROW || token.kind == TokenKind.LBRACE) {
+                    stats = List.of(parseStatement());
+                    body = stats.head;
+                    kind = JCCase.RULE;
+                } else {
+                    JCExpression value = parseExpression();
+                    stats = List.of(to(F.at(value).Break(value)));
+                    body = value;
+                    kind = JCCase.RULE;
+                    accept(SEMI);
+                }
+                break;
+            default:
+                accept(COLON);
+                stats = blockStatements();
+                kind = JCCase.STATEMENT;
+                break;
+        }
+        caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), stats, body)));
+        return caseExprs.toList();
+    }
+
     JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
         if (typeArgs != null) illegal();
         while (true) {
             int pos1 = token.pos;
             final List<JCAnnotation> annos = typeAnnotationsOpt();

@@ -2615,13 +2687,13 @@
             JCThrow t = toP(F.at(pos).Throw(exc));
             return t;
         }
         case BREAK: {
             nextToken();
-            Name label = LAX_IDENTIFIER.accepts(token.kind) ? ident() : null;
+            JCExpression value = token.kind == SEMI ? null : parseExpression();
             accept(SEMI);
-            JCBreak t = toP(F.at(pos).Break(label));
+            JCBreak t = toP(F.at(pos).Break(value));
             return t;
         }
         case CONTINUE: {
             nextToken();
             Name label = LAX_IDENTIFIER.accepts(token.kind) ? ident() : null;

@@ -2711,43 +2783,84 @@
         while (true) {
             int pos = token.pos;
             switch (token.kind) {
             case CASE:
             case DEFAULT:
-                cases.append(switchBlockStatementGroup());
+                cases.appendList(switchBlockStatementGroup());
                 break;
             case RBRACE: case EOF:
                 return cases.toList();
             default:
                 nextToken(); // to ensure progress
                 syntaxError(pos, Errors.Expected3(CASE, DEFAULT, RBRACE));
             }
         }
     }
 
-    protected JCCase switchBlockStatementGroup() {
+    protected List<JCCase> switchBlockStatementGroup() {
         int pos = token.pos;
         List<JCStatement> stats;
         JCCase c;
+        ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
         switch (token.kind) {
-        case CASE:
+        case CASE: {
+            nextToken();
+            ListBuffer<JCExpression> pats = new ListBuffer<>();
+            while (true) {
+                pats.append(term(EXPR | NOLAMBDA));
+                if (token.kind != COMMA) break;
             nextToken();
-            JCExpression pat = parseExpression();
+                checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
+            };
+            @SuppressWarnings("removal")
+            CaseKind caseKind;
+            JCTree body = null;
+            if (token.kind == ARROW) {
+                checkSourceLevel(Feature.SWITCH_RULE);
+                accept(ARROW);
+                caseKind = JCCase.RULE;
+                JCStatement statement = parseStatementAsBlock();
+                if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
+                    log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
+                }
+                stats = List.of(statement);
+                body = stats.head;
+            } else {
             accept(COLON);
+                caseKind = JCCase.STATEMENT;
             stats = blockStatements();
-            c = F.at(pos).Case(pat, stats);
+            }
+            c = F.at(pos).Case(caseKind, pats.toList(), stats, body);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
-            return c;
-        case DEFAULT:
+            return cases.append(c).toList();
+        }
+        case DEFAULT: {
             nextToken();
+            @SuppressWarnings("removal")
+            CaseKind caseKind;
+            JCTree body = null;
+            if (token.kind == COLON) {
             accept(COLON);
+                caseKind = JCCase.STATEMENT;
             stats = blockStatements();
-            c = F.at(pos).Case(null, stats);
+            } else {
+                checkSourceLevel(Feature.SWITCH_RULE);
+                accept(ARROW);
+                caseKind = JCCase.RULE;
+                JCStatement statement = parseStatementAsBlock();
+                if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
+                    log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
+                }
+                stats = List.of(statement);
+                body = stats.head;
+            }
+            c = F.at(pos).Case(caseKind, List.nil(), stats, body);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
-            return c;
+            return cases.append(c).toList();
+        }
         }
         throw new AssertionError("should not reach here");
     }
 
     /** MoreStatementExpressions = { COMMA StatementExpression }
< prev index next >