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

Unified Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 3001993002: improve fasta export directive recovery (Closed)
Patch Set: rebase and cleanup Created 3 years, 4 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: pkg/front_end/lib/src/fasta/parser/parser.dart
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index f7e2e1f90c1ca2e2ecc07d131512ef7aaa3a7661..ce2b9875cfce86f3b7346ef839e5e1f9d1e19db3 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -20,6 +20,8 @@ import '../../scanner/token.dart'
EQUALITY_PRECEDENCE,
POSTFIX_PRECEDENCE,
RELATIONAL_PRECEDENCE,
+ SyntheticStringToken,
+ SyntheticToken,
TokenType;
import '../scanner/token.dart' show isUserDefinableOperator;
@@ -68,6 +70,8 @@ import 'listener.dart' show Listener;
import 'member_kind.dart' show MemberKind;
+import 'token_stream_rewriter.dart';
+
import 'type_continuation.dart'
show TypeContinuation, typeContiunationFromFormalParameterKind;
@@ -208,6 +212,24 @@ class Parser {
/// external clients, for example, to parse an expression outside a function.
AsyncModifier asyncState = AsyncModifier.Sync;
+ /// The first token in the parse stream and used during parser recovery.
+ /// This is automatically set by the [parseUnit] method,
+ /// but must be manually set when any other parse method is called.
+ /// If not set, then the parser will call [handleUnrecoverableError]
+ /// rather than rewriting the token stream
+ /// and calling [handleRecoverableError].
+ Token firstToken;
+
+ /// A rewriter for inserting synthetic tokens.
+ /// Access using [rewriter] for lazy initialization.
+ TokenStreamRewriter cachedRewriter;
+
+ TokenStreamRewriter get rewriter {
+ assert(firstToken != null, 'firstToken must be set for parser recovery');
+ cachedRewriter ??= new TokenStreamRewriter(firstToken);
+ return cachedRewriter;
+ }
+
Parser(this.listener);
bool get inGenerator {
@@ -223,6 +245,7 @@ class Parser {
bool get inPlainSync => asyncState == AsyncModifier.Sync;
Token parseUnit(Token token) {
+ firstToken = token;
listener.beginCompilationUnit(token);
int count = 0;
while (!identical(token.kind, EOF_TOKEN)) {
@@ -230,6 +253,9 @@ class Parser {
count++;
}
listener.endCompilationUnit(count, token);
+ // Clear fields that could lead to memory leak.
+ firstToken = null;
+ cachedRewriter = null;
return token;
}
@@ -356,13 +382,12 @@ class Parser {
Token exportKeyword = token;
listener.beginExport(exportKeyword);
assert(optional('export', token));
- token = parseLiteralStringOrRecoverExpression(token.next);
+ token = ensureParseLiteralString(token.next);
token = parseConditionalUris(token);
token = parseCombinators(token);
- Token semicolon = token;
- token = expect(';', token);
+ Token semicolon = ensureSemicolon(token);
listener.endExport(exportKeyword, semicolon);
- return token;
+ return semicolon.next;
}
Token parseCombinators(Token token) {
@@ -904,6 +929,8 @@ class Parser {
}
Token expect(String string, Token token) {
+ // TODO(danrubel) update all uses of expect(';'...) to ensureSemicolon
+ // then add assert(!identical(';', string));
if (!identical(string, token.stringValue)) {
return reportUnrecoverableError(
token, fasta.templateExpectedButGot.withArguments(string))
@@ -1922,6 +1949,33 @@ class Parser {
return token;
}
+ Token ensureParseLiteralString(Token token) {
+ if (!identical(token.kind, STRING_TOKEN)) {
+ Message message = fasta.templateExpectedString.withArguments(token);
+ Token newToken =
+ new SyntheticStringToken(TokenType.STRING, '""', token.charOffset, 0);
+ token = rewriteAndRecover(token, message, newToken);
+ }
+ return parseLiteralString(token);
+ }
+
+ Token ensureSemicolon(Token token) {
+ // TODO(danrubel): Once all expect(';'...) call sites have been converted
+ // to use this method, remove similar semicolon recovery code
+ // from the handleError method in element_listener.dart.
+ if (optional(';', token)) return token;
+ Message message = fasta.templateExpectedButGot.withArguments(';');
+ Token newToken = new SyntheticToken(TokenType.SEMICOLON, token.charOffset);
+ return rewriteAndRecover(token, message, newToken);
+ }
+
+ Token rewriteAndRecover(Token token, Message message, Token newToken) {
+ if (firstToken == null) return reportUnrecoverableError(token, message);
+ reportRecoverableError(token, message);
+ token = rewriter.insertTokenBefore(newToken, token);
+ return token;
+ }
+
Token parseLiteralStringOrRecoverExpression(Token token) {
if (identical(token.kind, STRING_TOKEN)) {
return parseLiteralString(token);

Powered by Google App Engine
This is Rietveld 408576698