Improve literal list recovery
Change-Id: Ie0e7934d139e84b96add2f0e56051295849ce1bc
Reviewed-on: https://dart-review.googlesource.com/58580
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
index d312b78..492f026 100644
--- a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
@@ -29,7 +29,6 @@
''');
}
- @failingTest
void test_missingComma() {
testRecovery('''
f() => [a, b c];
diff --git a/pkg/analyzer/test/src/fasta/recovery/paired_tokens_test.dart b/pkg/analyzer/test/src/fasta/recovery/paired_tokens_test.dart
index fdd1f54..edc6d29 100644
--- a/pkg/analyzer/test/src/fasta/recovery/paired_tokens_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/paired_tokens_test.dart
@@ -238,9 +238,7 @@
''');
}
- @failingTest
void test_listLiteral_inner_last() {
- // Parser crashes
testRecovery('''
var x = [[0], [1];
''', [ScannerErrorCode.EXPECTED_TOKEN], '''
@@ -248,13 +246,19 @@
''');
}
- @failingTest
void test_listLiteral_inner_notLast() {
- // Parser crashes
testRecovery('''
var x = [[0], [1, [2]];
''', [ScannerErrorCode.EXPECTED_TOKEN], '''
-var x = [[0], [1], [2]];
+var x = [[0], [1, [2]]];
+''');
+ }
+
+ void test_listLiteral_missing_comma() {
+ testRecovery('''
+var x = [0 1];
+''', [ParserErrorCode.EXPECTED_TOKEN], '''
+var x = [0, 1];
''');
}
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 24cce44..b1e9a0a 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -4279,25 +4279,55 @@
Token beginToken = token = token.next;
assert(optional('[', token) || optional('[]', token));
int count = 0;
- if (optional('[', token)) {
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- do {
- if (optional(']', token.next)) {
- token = token.next;
+ if (optional('[]', token)) {
+ token = rewriteSquareBrackets(beforeToken).next;
+ listener.handleLiteralList(0, token, constKeyword, token.next);
+ return token.next;
+ }
+ bool old = mayParseFunctionExpressions;
+ mayParseFunctionExpressions = true;
+ while (true) {
+ Token next = token.next;
+ if (optional(']', next)) {
+ token = next;
+ break;
+ }
+ token = parseExpression(token);
+ next = token.next;
+ ++count;
+ if (!optional(',', next)) {
+ if (optional(']', next)) {
+ token = next;
break;
}
- token = parseExpression(token).next;
- ++count;
- } while (optional(',', token));
- mayParseFunctionExpressions = old;
- listener.handleLiteralList(count, beginToken, constKeyword, token);
- expect(']', token);
- return token;
+
+ // Recovery
+ if (!isExpressionStartForRecovery(next)) {
+ if (beginToken.endGroup.isSynthetic) {
+ // The scanner has already reported an error,
+ // but inserted `]` in the wrong place.
+ token = rewriter.moveSynthetic(token, beginToken.endGroup);
+ } else {
+ // Report an error and jump to the end of the list.
+ reportRecoverableError(
+ next, fasta.templateExpectedButGot.withArguments(']'));
+ token = beginToken.endGroup;
+ }
+ break;
+ }
+ // This looks like the start of an expression.
+ // Report an error, insert the comma, and continue parsing.
+ next = rewriteAndRecover(
+ token,
+ fasta.templateExpectedButGot.withArguments(','),
+ new SyntheticToken(TokenType.COMMA, next.offset))
+ .next;
+ }
+ token = next;
}
- token = rewriteSquareBrackets(beforeToken).next;
- listener.handleLiteralList(0, token, constKeyword, token.next);
- return token.next;
+ mayParseFunctionExpressions = old;
+ listener.handleLiteralList(count, beginToken, constKeyword, token);
+ return token;
}
/// This method parses the portion of a map literal that starts with the left