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

Unified Diff: pkg/front_end/lib/src/fasta/scanner/recover.dart

Issue 2664593002: Port parser and scanner fixes from rasta branch. (Closed)
Patch Set: Rebased on ef8ec26cf36d1f07b4fdf5d605003210826ae1c2. Created 3 years, 11 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
« no previous file with comments | « pkg/front_end/lib/src/fasta/scanner/keyword.dart ('k') | pkg/front_end/lib/src/fasta/scanner/token.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/front_end/lib/src/fasta/scanner/recover.dart
diff --git a/pkg/front_end/lib/src/fasta/scanner/recover.dart b/pkg/front_end/lib/src/fasta/scanner/recover.dart
index de124f3cb05f8b1f8afd4133fac5001ac5659a07..5d3f5e91d27bfe6f0a7820911f1157345c6cbfd9 100644
--- a/pkg/front_end/lib/src/fasta/scanner/recover.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/recover.dart
@@ -5,8 +5,19 @@
library fasta.scanner.recover;
import 'token.dart' show
+ StringToken,
Token;
+import 'error_token.dart' show
+ NonAsciiIdentifierToken,
+ ErrorKind,
+ ErrorToken;
+
+import 'precedence.dart' as Precedence;
+
+import 'precedence.dart' show
+ PrecedenceInfo;
+
/// Recover from errors in [tokens]. The original sources are provided as
/// [bytes]. [lineStarts] are the beginning character offsets of lines, and
/// must be updated if recovery is performed rewriting the original source
@@ -25,5 +36,206 @@ Token defaultRecoveryStrategy(
// [ArrayBasedScanner.discardBeginGroupUntil](array_based_scanner.dart). For
// more details on brace grouping see
// [AbstractScanner.unmatchedBeginGroup](abstract_scanner.dart).
- return tokens;
+
+ /// Tokens with errors.
+ ErrorToken error;
+ /// Used for appending to [error].
+ ErrorToken errorTail;
+
+ /// Tokens without errors.
+ Token good;
+ /// Used for appending to [good].
+ Token goodTail;
+
+ /// The previous token appended to [good]. Since tokens are single linked
+ /// lists, this allows us to rewrite the current token without scanning all
+ /// of [good]. This is supposed to be the token immediately before
+ /// [goodTail], that is, `beforeGoodTail.next == goodTail`.
+ Token beforeGoodTail;
+
+ recoverIdentifier(NonAsciiIdentifierToken first) {
+ List codeUnits = <int>[];
+
+ // True if the previous good token is an identifier and ends right where
+ // [first] starts. This is the case for input like `blåbærgrød`. In this
+ // case, the scanner produces this sequence of tokens:
+ //
+ // [
+ // StringToken("bl"),
+ // NonAsciiIdentifierToken("å"),
+ // StringToken("b"),
+ // NonAsciiIdentifierToken("æ"),
+ // StringToken("rgr"),
+ // NonAsciiIdentifierToken("ø"),
+ // StringToken("d"),
+ // EOF,
+ // ]
+ bool prepend = false;
+
+ // True if following token is also an identifier that starts right where
+ // [errorTail] ends. This is the case for "b" above.
+ bool append = false;
+ if (goodTail != null) {
+ if (goodTail.info == Precedence.IDENTIFIER_INFO &&
+ goodTail.charEnd == first.charOffset) {
+ prepend = true;
+ }
+ }
+ Token next = errorTail.next;
+ if (next.info == Precedence.IDENTIFIER_INFO &&
+ errorTail.charOffset + 1 == next.charOffset) {
+ append = true;
+ }
+ if (prepend) {
+ codeUnits.addAll(goodTail.value.codeUnits);
+ }
+ NonAsciiIdentifierToken current = first;
+ while (current != errorTail) {
+ codeUnits.add(current.character);
+ current = current.next;
+ }
+ codeUnits.add(errorTail.character);
+ int charOffset = first.charOffset;
+ if (prepend) {
+ charOffset = goodTail.charOffset;
+ if (beforeGoodTail == null) {
+ // We're prepending the first good token, so the new token will become
+ // the first good token.
+ good = null;
+ goodTail = null;
+ beforeGoodTail = null;
+ } else {
+ goodTail = beforeGoodTail;
+ }
+ }
+ if (append) {
+ codeUnits.addAll(next.value.codeUnits);
+ next = next.next;
+ }
+ String value = new String.fromCharCodes(codeUnits);
+ Token recovered = synthesizeToken(
+ charOffset, value, Precedence.IDENTIFIER_INFO);
+ recovered.next = next;
+ return recovered;
+ }
+
+ recoverExponent() {
+ return synthesizeToken(errorTail.charOffset, "NaN", Precedence.DOUBLE_INFO);
+ }
+
+ recoverString() {
+ // TODO(ahe): Improve this.
+ return skipToEof(errorTail);
+ }
+
+ recoverHexDigit() {
+ return synthesizeToken(errorTail.charOffset, "-1", Precedence.INT_INFO);
+ }
+
+ recoverStringInterpolation() {
+ // TODO(ahe): Improve this.
+ return skipToEof(errorTail);
+ }
+
+ recoverComment() {
+ // TODO(ahe): Improve this.
+ return skipToEof(errorTail);
+ }
+
+ recoverUnmatched() {
+ // TODO(ahe): Try to use top-level keywords (such as `class`, `typedef`,
+ // and `enum`) and identation to recover.
+ return errorTail;
+ }
+
+ for (Token current = tokens; !current.isEof; current = current.next) {
+ if (current is ErrorToken) {
+ ErrorToken first = current;
+ Token next = current;
+ bool treatAsWhitespace = false;
+ do {
+ current = next;
+ if (errorTail == null) {
+ error = next;
+ } else {
+ errorTail.next = next;
+ }
+ errorTail = next;
+ next = next.next;
+ } while (next is ErrorToken && first.errorCode == next.errorCode);
+
+ switch (first.errorCode) {
+ case ErrorKind.Encoding:
+ case ErrorKind.NonAsciiWhitespace:
+ case ErrorKind.AsciiControlCharacter:
+ treatAsWhitespace = true;
+ break;
+
+ case ErrorKind.NonAsciiIdentifier:
+ current = recoverIdentifier(first);
+ break;
+
+ case ErrorKind.MissingExponent:
+ current = recoverExponent();
+ break;
+
+ case ErrorKind.UnterminatedString:
+ current = recoverString();
+ break;
+
+ case ErrorKind.ExpectedHexDigit:
+ current = recoverHexDigit();
+ break;
+
+ case ErrorKind.UnexpectedDollarInString:
+ current = recoverStringInterpolation();
+ break;
+
+ case ErrorKind.UnterminatedComment:
+ current = recoverComment();
+ break;
+
+ case ErrorKind.UnmatchedToken:
+ current = recoverUnmatched();
+ break;
+
+ case ErrorKind.UnterminatedToken: // TODO(ahe): Can this happen?
+ default:
+ treatAsWhitespace = true;
+ break;
+ }
+ if (treatAsWhitespace) continue;
+ }
+ if (goodTail == null) {
+ good = current;
+ } else {
+ goodTail.next = current;
+ }
+ beforeGoodTail = goodTail;
+ goodTail = current;
+ }
+
+ errorTail.next = good;
+ return error;
+}
+
+Token synthesizeToken(int charOffset, String value, PrecedenceInfo info) {
+ return new StringToken.fromString(info, value, charOffset);
+}
+
+Token skipToEof(Token token) {
+ while (!token.isEof) {
+ token = token.next;
+ }
+ return token;
+}
+
+String closeBraceFor(String openBrace) {
+ return const {
+ '(': ')',
+ '[': ']',
+ '{': '}',
+ '<': '>',
+ r'${': '}',
+ }[openBrace];
}
« no previous file with comments | « pkg/front_end/lib/src/fasta/scanner/keyword.dart ('k') | pkg/front_end/lib/src/fasta/scanner/token.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698