Chromium Code Reviews| 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 e6a5ad2572395649e938d7d11ce675f1b2724a20..5ed8bcc6ad19b246737c2142d83042a18d3c82f7 100644 |
| --- a/compiler/java/com/google/dart/compiler/parser/DartParser.java |
| +++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java |
| @@ -249,21 +249,34 @@ public class DartParser extends CompletionHooksParserBase { |
| parseDirectives(unit); |
| while (!EOS()) { |
| - DartNode node = null; |
| - beginTopLevelElement(); |
| - isParsingInterface = false; |
| - if (optionalPseudoKeyword(CLASS_KEYWORD)) { |
| - node = done(parseClass()); |
| - } else if (optionalPseudoKeyword(INTERFACE_KEYWORD)) { |
| - isParsingInterface = true; |
| - node = done(parseClass()); |
| - } else if (optionalPseudoKeyword(TYPEDEF_KEYWORD)) { |
| - node = done(parseFunctionTypeAlias()); |
| - } else { |
| - node = done(parseFieldOrMethod(false)); |
| - } |
| - if (node != null) { |
| - unit.addTopLevelNode(node); |
| + try { |
| + DartNode node = null; |
| + beginTopLevelElement(); |
| + isParsingInterface = false; |
| + if (optionalPseudoKeyword(CLASS_KEYWORD)) { |
| + node = done(parseClass()); |
| + } else if (optionalPseudoKeyword(INTERFACE_KEYWORD)) { |
| + isParsingInterface = true; |
| + node = done(parseClass()); |
| + } else if (optionalPseudoKeyword(TYPEDEF_KEYWORD)) { |
| + node = done(parseFunctionTypeAlias()); |
| + } else { |
| + node = done(parseFieldOrMethod(false)); |
| + } |
| + if (node != null) { |
| + unit.addTopLevelNode(node); |
| + } |
| + } catch (ParserException e) { |
| + Location beginLocation = ctx.getTokenLocation(); |
| + // Find known top level element to restart parsing. |
| + while (peek(0) != Token.EOS && !peekTopLevelKeyword(0)) { |
| + next(); |
| + } |
| + // Report skipped source. |
| + Location endLocation = ctx.getTokenLocation(); |
| + reportError(new DartCompilationError(ctx.getSource(), |
| + new Location(beginLocation.getBegin(), endLocation.getEnd()), |
| + ParserErrorCode.SKIPPED_SOURCE)); |
| } |
| } |
| expect(Token.EOS); |
| @@ -271,6 +284,16 @@ public class DartParser extends CompletionHooksParserBase { |
| } |
| /** |
| + * @return <code>true</code> if token at given position is keyword which can be used only on top |
| + * level. |
| + */ |
| + private boolean peekTopLevelKeyword(int n) { |
| + return peekPseudoKeyword(n, CLASS_KEYWORD) |
| + || peekPseudoKeyword(n, INTERFACE_KEYWORD) |
| + || peekPseudoKeyword(n, TYPEDEF_KEYWORD); |
| + } |
| + |
| + /** |
| * A version of the parser which only parses the directives of a library. |
| * |
| * TODO(jbrosenberg): consider parsing the whole file here, in order to avoid |
| @@ -435,18 +458,55 @@ public class DartParser extends CompletionHooksParserBase { |
| List<DartTypeParameter> types = new ArrayList<DartTypeParameter>(); |
| expect(Token.LT); |
| do { |
| - beginTypeParameter(); |
| - DartIdentifier name = parseIdentifier(); |
| - DartTypeNode bound = null; |
| - if (optionalPseudoKeyword(EXTENDS_KEYWORD)) { |
| - bound = parseTypeAnnotation(); |
| - } |
| - types.add(done(new DartTypeParameter(name, bound))); |
| + DartTypeParameter typeParameter = parseTypeParameter(); |
| + types.add(typeParameter); |
| } while (optional(Token.COMMA)); |
| expect(Token.GT); |
| return types; |
| } |
| + // XXX |
|
zundel
2011/11/18 18:04:33
spurious comment
|
| + /** |
| + * Parses single {@link DartTypeParameter} for {@link #parseTypeParameters()}. |
| + */ |
| + private DartTypeParameter parseTypeParameter() { |
| + beginTypeParameter(); |
| + DartIdentifier name = parseIdentifier(); |
| + // Try to parse bound. |
| + DartTypeNode bound = null; |
| + if (peek(0) != Token.EOS && peek(0) != Token.COMMA && peek(0) != Token.GT) { |
| + if (optionalPseudoKeyword(EXTENDS_KEYWORD)) { |
| + // OK, this is EXTENDS_KEYWORD, parse type. |
| + bound = parseTypeAnnotation(); |
| + } else if (peekTopLevelKeyword(0)) { |
| + // class Foo<T{cursor} class Bar {} |
| + // User is typing type parameters now, next is top level element. |
| + // Stop parsing of current top level element and restart from the next one. |
| + throw new ParserException(); |
| + } else if (peek(0) == Token.IDENTIFIER && (peek(1) == Token.COMMA || peek(1) == Token.GT)) { |
| + // <X exte{cursor}> |
| + // User tries to type "extends", but it is not finished yet. |
| + // Report problem and try to continue. |
| + reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_EXTENDS); |
|
zundel
2011/11/18 18:04:33
Using reportErrorWithoutAdvancing() and then calli
|
| + next(); |
| + } else if (peek(0) == Token.IDENTIFIER && peek(1) == Token.IDENTIFIER && (peek(2) == Token.COMMA || peek(2) == Token.GT)) { |
| + // <X somethingLikeExtends Type> |
| + // User mistyped word "extends" or it is not finished yet. |
| + // Report problem and try to continue. |
| + reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_EXTENDS); |
| + next(); |
| + bound = parseTypeAnnotation(); |
| + } else { |
| + // Something else, restart parsing from next top level element. |
| + reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_EXTENDS); |
| + next(); |
| + throw new ParserException(); |
| + } |
| + } |
| + // Ready to create DartTypeParameter. |
| + return done(new DartTypeParameter(name, bound)); |
| + } |
| + |
| private List<DartTypeParameter> parseTypeParametersOpt() { |
| return (peek(0) == Token.LT) |
| ? parseTypeParameters() |