| Index: compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| diff --git a/compiler/java/com/google/dart/compiler/parser/DartParser.java b/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| index ee69b4128fad2b6b2026f0c1f1edea9424460fb8..d1d6c65d03226c4b12340581df6ca46d97d173df 100644
|
| --- a/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| +++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| @@ -3182,27 +3182,30 @@ public class DartParser extends CompletionHooksParserBase {
|
| boolean oldInLoopStatement = inLoopStatement;
|
| boolean oldInCaseStatement = inCaseStatement;
|
| inLoopStatement = inCaseStatement = false;
|
| - DartBlock result;
|
| - if (isDietParse) {
|
| - result = dietParseFunctionStatementBody();
|
| - } else {
|
| - beginFunctionStatementBody();
|
| - if (optional(Token.ARROW)) {
|
| - DartExpression expr = parseExpression();
|
| - if (expr == null) {
|
| - expr = new DartSyntheticErrorExpression();
|
| - }
|
| - if (requireSemicolonForArrow) {
|
| - expect(Token.SEMICOLON);
|
| - }
|
| - result = done(makeReturnBlock(expr));
|
| + try {
|
| + DartBlock result;
|
| + if (isDietParse) {
|
| + result = dietParseFunctionStatementBody();
|
| } else {
|
| - result = done(parseBlock());
|
| + beginFunctionStatementBody();
|
| + if (optional(Token.ARROW)) {
|
| + DartExpression expr = parseExpression();
|
| + if (expr == null) {
|
| + expr = new DartSyntheticErrorExpression();
|
| + }
|
| + if (requireSemicolonForArrow) {
|
| + expect(Token.SEMICOLON);
|
| + }
|
| + result = done(makeReturnBlock(expr));
|
| + } else {
|
| + result = done(parseBlock());
|
| + }
|
| }
|
| + return result;
|
| + } finally {
|
| + inLoopStatement = oldInLoopStatement;
|
| + inCaseStatement = oldInCaseStatement;
|
| }
|
| - inLoopStatement = oldInLoopStatement;
|
| - inCaseStatement = oldInCaseStatement;
|
| - return result;
|
| }
|
|
|
| private DartBlock dietParseFunctionStatementBody() {
|
| @@ -3816,9 +3819,11 @@ public class DartParser extends CompletionHooksParserBase {
|
| private DartStatement parseLoopStatement() {
|
| boolean oldInLoop = inLoopStatement;
|
| inLoopStatement = true;
|
| - DartStatement stmt = parseStatement();
|
| - inLoopStatement = oldInLoop;
|
| - return stmt;
|
| + try {
|
| + return parseStatement();
|
| + } finally {
|
| + inLoopStatement = oldInLoop;
|
| + }
|
| }
|
|
|
| /**
|
| @@ -3947,6 +3952,8 @@ public class DartParser extends CompletionHooksParserBase {
|
| private List<DartStatement> parseCaseStatements() {
|
| List<DartStatement> statements = new ArrayList<DartStatement>();
|
| DartStatement statement = null;
|
| + boolean endOfCaseFound = false;
|
| + boolean warnedUnreachable = false;
|
| while (true) {
|
| switch (peek(0)) {
|
| case CASE:
|
| @@ -3955,27 +3962,33 @@ public class DartParser extends CompletionHooksParserBase {
|
| case EOS:
|
| return statements;
|
| case IDENTIFIER:
|
| - // Handle consecutively labelled case statements
|
| - if (peek(1).equals(Token.COLON) && peek(2).equals(Token.CASE)) {
|
| + // Handle consecutively labeled case statements
|
| + if (peek(1).equals(Token.COLON)
|
| + && (peek(2).equals(Token.CASE) || peek(2).equals(Token.DEFAULT))) {
|
| return statements;
|
| }
|
| default:
|
| boolean oldInCaseStatement = inCaseStatement;
|
| inCaseStatement = true;
|
| - statement = parseStatement();
|
| - inCaseStatement = oldInCaseStatement;
|
| + try {
|
| + if (endOfCaseFound && !warnedUnreachable) {
|
| + reportErrorWithoutAdvancing(ParserErrorCode.UNREACHABLE_CODE_IN_CASE);
|
| + warnedUnreachable = true;
|
| + }
|
| + statement = parseStatement();
|
| + } finally {
|
| + inCaseStatement = oldInCaseStatement;
|
| + }
|
| if (statement == null) {
|
| return statements;
|
| }
|
|
|
| - statements.add(statement);
|
| - if (statement.isAbruptCompletingStatement()) {
|
| - /*
|
| - * TODO(jat): is this correct? It seems like we would get better
|
| - * error messages if we parsed dead code as part of this case block
|
| - * and gave an error for unreachable code
|
| - */
|
| - return statements;
|
| + // Don't add unreachable code to the list of statements.
|
| + if (!endOfCaseFound) {
|
| + statements.add(statement);
|
| + if (statement.isAbruptCompletingStatement()) {
|
| + endOfCaseFound = true;
|
| + }
|
| }
|
| }
|
| }
|
| @@ -4041,8 +4054,12 @@ public class DartParser extends CompletionHooksParserBase {
|
| DartIdentifier identifier = parseIdentifier();
|
| expect(Token.COLON);
|
| label = done(new DartLabel(identifier, null));
|
| + if (peek(0) == Token.RBRACE) {
|
| + reportError(position(), ParserErrorCode.LABEL_NOT_FOLLOWED_BY_CASE_OR_DEFAULT);
|
| + expectCloseBrace(foundOpenBrace);
|
| + break;
|
| + }
|
| }
|
| -
|
| if (peek(0) == Token.CASE) {
|
| members.add(parseCaseMember(label));
|
| } else if (optional(Token.RBRACE)) {
|
| @@ -4062,7 +4079,39 @@ public class DartParser extends CompletionHooksParserBase {
|
| return done(new DartSwitchStatement(expr, members));
|
| }
|
|
|
| - /**
|
| + private void parseDeadSwitchCode() {
|
| + boolean done = false;
|
| + boolean warned = false;
|
| + boolean oldInCaseStatement = inCaseStatement;
|
| + inCaseStatement = true;
|
| + try {
|
| + while (!done) {
|
| + if (peek(0) == Token.IDENTIFIER && peek(1) == Token.COLON) {
|
| + beginLabel();
|
| + DartIdentifier identifier = parseIdentifier();
|
| + expect(Token.COLON);
|
| + done(new DartLabel(identifier, null));
|
| +
|
| + }
|
| +
|
| + Token nextToken = peek(0);
|
| + switch(nextToken) {
|
| + case CASE:
|
| + case DEFAULT:
|
| + case EOS:
|
| + case RBRACE:
|
| + return;
|
| + default:
|
| + warned = true;
|
| + parseStatement();
|
| + }
|
| + }
|
| + } finally {
|
| + inCaseStatement = oldInCaseStatement;
|
| + }
|
| + }
|
| +
|
| + /**
|
| * <pre>
|
| * catchParameter
|
| * : FINAL type? identifier
|
|
|