| 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 fb429e3d58656ab743066b751dd334f82fdcfd39..5547edac69f3c4f074543925ab9d51a53e86f3c2 100644
|
| --- a/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| +++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| @@ -911,6 +911,7 @@ public class DartParser extends CompletionHooksParserBase {
|
| * @param allowStatic true if the static modifier is allowed
|
| * @return a {@link DartNode} representing the grammar fragment above
|
| */
|
| + @Terminals(tokens={Token.SEMICOLON})
|
| private DartNode parseFieldOrMethod(boolean allowStatic) {
|
| beginClassMember();
|
| Modifiers modifiers = Modifiers.NONE;
|
| @@ -1050,6 +1051,7 @@ public class DartParser extends CompletionHooksParserBase {
|
| break;
|
| }
|
|
|
| + case SEMICOLON:
|
| default: {
|
| done(null);
|
| reportUnexpectedToken(position(), null, next());
|
| @@ -1593,7 +1595,7 @@ public class DartParser extends CompletionHooksParserBase {
|
| * ;
|
| * </pre>
|
| */
|
| - @Terminals(tokens = {Token.RBRACK, Token.COMMA, Token.RPAREN})
|
| + @Terminals(tokens = {Token.COMMA, Token.RPAREN})
|
| private List<DartParameter> parseFormalParameterList() {
|
| beginFormalParameterList();
|
| List<DartParameter> params = new ArrayList<DartParameter>();
|
| @@ -1608,19 +1610,17 @@ public class DartParser extends CompletionHooksParserBase {
|
| DartParameter param = parseFormalParameter(isNamed);
|
| params.add(param);
|
|
|
| - // Must keep in sync with @Terminals above
|
| - done = optional(Token.RBRACK);
|
| - if (done) {
|
| + if (isNamed && optional(Token.RBRACK)) {
|
| expectCloseParen();
|
| - } else {
|
| - // Must keep in sync with @Terminals above
|
| - done = optional(Token.RPAREN);
|
| + break;
|
| }
|
|
|
| - if (!done) {
|
| - // Ensure termination if token is anything other than COMMA.
|
| - // Must keep in sync with @Terminals above
|
| - done = !expect(Token.COMMA);
|
| + // Ensure termination if token is anything other than COMMA.
|
| + // Must keep Token.COMMA in sync with @Terminals above
|
| + if (!optional(Token.COMMA)) {
|
| + // Must keep Token.RPAREN in sync with @Terminals above
|
| + expectCloseParen();
|
| + done = true;
|
| }
|
| }
|
|
|
| @@ -3013,15 +3013,26 @@ public class DartParser extends CompletionHooksParserBase {
|
| beginBlock();
|
| List<DartStatement> statements = new ArrayList<DartStatement>();
|
| boolean foundOpenBrace = expect(Token.LBRACE);
|
| +
|
| while (!match(Token.RBRACE) && !EOS()) {
|
| if (looksLikeTopLevelKeyword()) {
|
| reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
|
| break;
|
| }
|
| + int startPosition = position().getPos();
|
| DartStatement newStatement = parseStatement();
|
| if (newStatement == null) {
|
| break;
|
| }
|
| + if (startPosition == position().getPos()) {
|
| + // The parser is not making progress.
|
| + Set<Token> terminals = this.collectTerminalAnnotations();
|
| + if (terminals.contains(peek(0))) {
|
| + // bail out of the block
|
| + break;
|
| + }
|
| + reportUnexpectedToken(position(), null, next());
|
| + }
|
| statements.add(newStatement);
|
| }
|
| expectCloseBrace(foundOpenBrace);
|
| @@ -3233,6 +3244,11 @@ public class DartParser extends CompletionHooksParserBase {
|
| * ;
|
| * </pre>
|
| */
|
| + // TODO(zundel): Possibly we could use Token.IDENTIFIER too, but it is used
|
| + // in so many places, it might make recovery worse rather than better.
|
| + @Terminals(tokens={Token.IF, Token.SWITCH, Token.WHILE, Token.DO, Token.FOR,
|
| + Token.VAR, Token.FINAL, Token.CONTINUE, Token.BREAK, Token.RETURN, Token.THROW,
|
| + Token.TRY, Token.SEMICOLON })
|
| private DartStatement parseNonLabelledStatement() {
|
| // Try to parse as function declaration.
|
| if (looksLikeFunctionDeclarationOrExpression()) {
|
| @@ -3304,14 +3320,6 @@ public class DartParser extends CompletionHooksParserBase {
|
| consume(Token.SEMICOLON);
|
| return done(new DartEmptyStatement());
|
|
|
| - // Things that we know can't be valid statements get a synthetic error statement
|
| - case RBRACE:
|
| - case CLASS:
|
| - // no need to create a separate parser event as the AST node is enough
|
| - beginEmptyStatement();
|
| - // TODO(jat): other tokens that should be caught here?
|
| - return done(parseErrorStatement());
|
| -
|
| case IDENTIFIER:
|
| // We have already eliminated function declarations earlier, so check for:
|
| // a) variable declarations;
|
| @@ -3577,60 +3585,32 @@ public class DartParser extends CompletionHooksParserBase {
|
| * for error recovery.
|
| */
|
| protected void expectStatmentTerminator() {
|
| - if (looksLikeTopLevelKeyword()) {
|
| - reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_SEMICOLON);
|
| - return;
|
| - }
|
| Token token = peek(0);
|
| int braceCount = 1;
|
| - switch (token) {
|
| - case SEMICOLON:
|
| - expect(Token.SEMICOLON);
|
| - return;
|
| -
|
| - case EOS:
|
| - case RBRACE:
|
| - reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_SEMICOLON);
|
| - return;
|
| + if (expect(Token.SEMICOLON)) {
|
| + return;
|
| + }
|
| + Set<Token> terminals = collectTerminalAnnotations();
|
| + assert(terminals.contains(Token.SEMICOLON));
|
|
|
| + switch (token) {
|
| case LBRACE:
|
| - ++braceCount;
|
| - //$FALL-THROUGH$
|
| - default:
|
| - // give error message
|
| - expect(Token.SEMICOLON);
|
| - break;
|
| + braceCount++;
|
| + break;
|
| + }
|
| + if (peek(0) == token) {
|
| + reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_SEMICOLON);
|
| + } else {
|
| + reportError(position(), ParserErrorCode.EXPECTED_SEMICOLON);
|
| + token = peek(0);
|
| }
|
|
|
| - while (true) {
|
| - if (looksLikeTopLevelKeyword()) {
|
| + // Consume tokens until we see something that could terminate or start a new statement
|
| + while (token != Token.SEMICOLON) {
|
| + if (looksLikeTopLevelKeyword() || terminals.contains(token)) {
|
| return;
|
| }
|
| - switch (peek(0)) {
|
| - case EOS:
|
| - return;
|
| -
|
| - case SEMICOLON:
|
| - if (braceCount < 2) {
|
| - // if we have seen open braces while skipping, keep looking
|
| - return;
|
| - }
|
| - next();
|
| - break;
|
| -
|
| - case RBRACE:
|
| - if (--braceCount == 0) {
|
| - return;
|
| - }
|
| - break;
|
| -
|
| - case LBRACE:
|
| - ++braceCount;
|
| - //$FALL-THROUGH$
|
| - default:
|
| - next();
|
| - break;
|
| - }
|
| + token = next();
|
| }
|
| }
|
|
|
| @@ -3971,10 +3951,12 @@ public class DartParser extends CompletionHooksParserBase {
|
| beginTryStatement();
|
| // Try.
|
| expect(Token.TRY);
|
| + // TODO(zundel): It would be nice here to setup 'CATCH' and 'FINALLY' as tokens for recovery
|
| DartBlock tryBlock = parseBlock();
|
|
|
| List<DartCatchBlock> catches = new ArrayList<DartCatchBlock>();
|
| while (optional(Token.CATCH)) {
|
| + // TODO(zundel): It would be nice here to setup 'FINALLY' as token for recovery
|
| beginCatchClause();
|
| expect(Token.LPAREN);
|
| DartParameter exception = parseCatchParameter();
|
| @@ -4169,7 +4151,7 @@ public class DartParser extends CompletionHooksParserBase {
|
| return done(new DartSyntheticErrorIdentifier());
|
| }
|
| DartIdentifier identifier;
|
| - if (expect(Token.IDENTIFIER)) {
|
| + if (expect(Token.IDENTIFIER) && ctx.getTokenString() != null) {
|
| identifier = new DartIdentifier(ctx.getTokenString());
|
| } else {
|
| identifier = new DartSyntheticErrorIdentifier();
|
|
|