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

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

Issue 8576007: Expect 'extends' in type parameters declaration and recover, issue 341 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Better recovering, more tests. Created 9 years, 1 month 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 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()

Powered by Google App Engine
This is Rietveld 408576698