Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Unified Diff: compiler/java/com/google/dart/compiler/parser/DartParser.java

Issue 10534065: In analyzer, catch use of continue and break in inappropriate places (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Refactored a bit, handle break inside function definition Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 f9cd10098f342f64d33ff83e7b40b21dba40514a..a2baad4b027f1abca0c830f31569008df6842669 100644
--- a/compiler/java/com/google/dart/compiler/parser/DartParser.java
+++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java
@@ -221,6 +221,15 @@ public class DartParser extends CompletionHooksParserBase {
* {@link #setAllowFunctionExpression(boolean)}.
*/
private boolean allowFunctionExpression = true;
+
+ /**
+ * 'break' (with no labels) and 'continue' stmts are not valid
+ * just anywhere, they must be inside a loop or a case stmt.
+ *
+ * A break with a label may be valid and is allowed through and
+ * checked in the resolver.
+ */
+ private boolean inLoopOrCaseStatement = false;
/**
* Set the {@link #allowFunctionExpression} flag indicating whether function expressions are
@@ -3072,39 +3081,13 @@ public class DartParser extends CompletionHooksParserBase {
* @return {@link DartBlock} instance containing function body
*/
private DartBlock parseFunctionStatementBody(boolean requireSemicolonForArrow) {
+ // A break inside a function body should have nothing to do with a loop in
+ // the code surrounding the definition.
+ boolean oldInLoopOrCaseStatement = inLoopOrCaseStatement;
+ inLoopOrCaseStatement = false;
+ DartBlock result;
if (isDietParse) {
- DartBlock emptyBlock = new DartBlock(new ArrayList<DartStatement>());
- if (optional(Token.ARROW)) {
- while (true) {
- Token token = next();
- if (token == Token.SEMICOLON) {
- break;
- }
- }
- } else {
- if (!peek(0).equals(Token.LBRACE) && looksLikeTopLevelKeyword()) {
- // Allow recovery back to the top level.
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- return done(emptyBlock);
- }
- expect(Token.LBRACE);
- int nesting = 1;
- while (nesting > 0) {
- Token token = next();
- switch (token) {
- case LBRACE:
- ++nesting;
- break;
- case RBRACE:
- --nesting;
- break;
- case EOS:
- return emptyBlock;
- }
- }
- }
- // Return an empty block so we don't generate unparseable code.
- return emptyBlock;
+ result = dietParseFunctionStatementBody();
} else {
beginFunctionStatementBody();
if (optional(Token.ARROW)) {
@@ -3115,11 +3098,48 @@ public class DartParser extends CompletionHooksParserBase {
if (requireSemicolonForArrow) {
expect(Token.SEMICOLON);
}
- return done(makeReturnBlock(expr));
+ result = done(makeReturnBlock(expr));
} else {
- return done(parseBlock());
+ result = done(parseBlock());
}
}
+ inLoopOrCaseStatement = oldInLoopOrCaseStatement;
+ return result;
+ }
+
+ private DartBlock dietParseFunctionStatementBody() {
+ DartBlock emptyBlock = new DartBlock(new ArrayList<DartStatement>());
+ if (optional(Token.ARROW)) {
+ while (true) {
+ Token token = next();
+ if (token == Token.SEMICOLON) {
+ break;
+ }
+ }
+ } else {
+ if (!peek(0).equals(Token.LBRACE) && looksLikeTopLevelKeyword()) {
+ // Allow recovery back to the top level.
+ reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
+ return done(emptyBlock);
+ }
+ expect(Token.LBRACE);
+ int nesting = 1;
+ while (nesting > 0) {
+ Token token = next();
+ switch (token) {
+ case LBRACE:
+ ++nesting;
+ break;
+ case RBRACE:
+ --nesting;
+ break;
+ case EOS:
+ return emptyBlock;
+ }
+ }
+ }
+ // Return an empty block so we don't generate unparseable code.
+ return emptyBlock;
}
/**
@@ -3181,6 +3201,9 @@ public class DartParser extends CompletionHooksParserBase {
DartIdentifier label = null;
if (match(Token.IDENTIFIER)) {
label = parseIdentifier();
+ } else if (!inLoopOrCaseStatement) {
+ // The validation of matching of labels to break statements is done later.
+ reportErrorWithoutAdvancing(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP);
}
expectStatmentTerminator();
return done(new DartBreakStatement(label));
@@ -3190,6 +3213,9 @@ public class DartParser extends CompletionHooksParserBase {
beginContinueStatement();
expect(Token.CONTINUE);
DartIdentifier label = null;
+ if (!inLoopOrCaseStatement) {
+ reportErrorWithoutAdvancing(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP);
+ }
if (peek(0) == Token.IDENTIFIER) {
label = parseIdentifier();
}
@@ -3653,7 +3679,7 @@ public class DartParser extends CompletionHooksParserBase {
expect(Token.LPAREN);
DartExpression condition = parseExpression();
expectCloseParen();
- DartStatement body = parseStatement();
+ DartStatement body = parseLoopOrCaseStatement();
return done(new DartWhileStatement(condition, body));
}
@@ -3669,7 +3695,7 @@ public class DartParser extends CompletionHooksParserBase {
private DartDoWhileStatement parseDoWhileStatement() {
beginDoStatement();
expect(Token.DO);
- DartStatement body = parseStatement();
+ DartStatement body = parseLoopOrCaseStatement();
expect(Token.WHILE);
expect(Token.LPAREN);
DartExpression condition = parseExpression();
@@ -3679,6 +3705,20 @@ public class DartParser extends CompletionHooksParserBase {
}
/**
+ * Use this wrapper to parse the body of a loop or case statement.
+ *
+ * Sets up flag variables to make sure continue and break are properly
+ * marked as errors when in wrong context.
+ */
+ private DartStatement parseLoopOrCaseStatement() {
+ boolean oldInBreakable = inLoopOrCaseStatement;
+ inLoopOrCaseStatement = true;
+ DartStatement stmt = parseStatement();
+ inLoopOrCaseStatement = oldInBreakable;
+ return stmt;
+ }
+
+ /**
* <pre>
* iterationStatement
* : WHILE '(' expression ')' statement
@@ -3745,7 +3785,7 @@ public class DartParser extends CompletionHooksParserBase {
DartExpression iterable = parseExpression();
expectCloseParen();
- DartStatement body = parseStatement();
+ DartStatement body = parseLoopOrCaseStatement();
return done(new DartForInStatement(setup, iterable, body));
} else if (optional(Token.SEMICOLON)) {
@@ -3764,7 +3804,7 @@ public class DartParser extends CompletionHooksParserBase {
}
expectCloseParen();
- DartStatement body = parseStatement();
+ DartStatement body = parseLoopOrCaseStatement();
return done(new DartForStatement(setup, condition, next, body));
} else {
reportUnexpectedToken(position(), null, peek(0));
@@ -3812,7 +3852,7 @@ public class DartParser extends CompletionHooksParserBase {
case EOS:
return statements;
default:
- if ((statement = parseStatement()) == null) {
+ if ((statement = parseLoopOrCaseStatement()) == null) {
return statements;
}
statements.add(statement);

Powered by Google App Engine
This is Rietveld 408576698