Improve parse literal string recovery
This fixes another fasta parser exception
and improves recovery when parsing string literals.
Change-Id: I704b7fcb9dcb2cd01e75623a179f95e6097ccec4
Reviewed-on: https://dart-review.googlesource.com/63000
Commit-Queue: Dan Rubel <danrubel@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index fd94be1..2363720 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -1843,18 +1843,27 @@
}
Token parseStringPart(Token token) {
- token = token.next;
- while (token.kind != STRING_TOKEN) {
- if (token is ErrorToken) {
- reportErrorToken(token, true);
- } else {
- token = reportUnrecoverableErrorWithToken(
- token, fasta.templateExpectedString);
+ Token next = token.next;
+ if (next.kind != STRING_TOKEN) {
+ bool errorReported = false;
+ while (next is ErrorToken) {
+ errorReported = true;
+ reportErrorToken(next, true);
+ token = next;
+ next = token.next;
}
- token = token.next;
+ if (next.kind != STRING_TOKEN) {
+ if (!errorReported) {
+ reportRecoverableErrorWithToken(next, fasta.templateExpectedString);
+ }
+ next = rewriter
+ .insertTokenAfter(token,
+ new SyntheticStringToken(TokenType.STRING, '', next.charOffset))
+ .next;
+ }
}
- listener.handleStringPart(token);
- return token;
+ listener.handleStringPart(next);
+ return next;
}
/// Insert a synthetic identifier after the given [token] and create an error
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect b/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect
index d2f376d..3c4327b 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.direct.expect
@@ -1,8 +1,21 @@
library;
import self as self;
+import "dart:core" as core;
-static method #main() → dynamic {
- throw "pkg/front_end/testcases/regress/issue_29976.dart:8:3: Error: Expected a String, but got ')'.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_29976.dart:7:14: Error: The non-ASCII character '\u0233' (U+00E9) can't be used in identifiers, only in strings and comments.
+Try using an US-ASCII letter, a digit, '_' (an underscore), or '\$' (a dollar sign).
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:15: Error: String starting with ' must end with '.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:7: Error: Can't find '}' to match '\${'.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:10:1: Error: String starting with \" must end with \".", "pkg/front_end/testcases/regress/issue_29976.dart:10:1: Error: Expected a declaration, but got ''.", "pkg/front_end/testcases/regress/issue_29976.dart:7:14: Error: Expected '}' before this.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:8:3: Error: Expected a String, but got ')'.
)
- ^";
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:9:1: Error: Expected ';' before this.
+}
+^"]/* from null */;
+static method main() → void {
+ throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#f, 32, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>["x${(let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#x, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})))).*("'")}"]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
}
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect
index d2f376d..3c4327b 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.direct.transformed.expect
@@ -1,8 +1,21 @@
library;
import self as self;
+import "dart:core" as core;
-static method #main() → dynamic {
- throw "pkg/front_end/testcases/regress/issue_29976.dart:8:3: Error: Expected a String, but got ')'.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_29976.dart:7:14: Error: The non-ASCII character '\u0233' (U+00E9) can't be used in identifiers, only in strings and comments.
+Try using an US-ASCII letter, a digit, '_' (an underscore), or '\$' (a dollar sign).
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:15: Error: String starting with ' must end with '.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:7: Error: Can't find '}' to match '\${'.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:10:1: Error: String starting with \" must end with \".", "pkg/front_end/testcases/regress/issue_29976.dart:10:1: Error: Expected a declaration, but got ''.", "pkg/front_end/testcases/regress/issue_29976.dart:7:14: Error: Expected '}' before this.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:8:3: Error: Expected a String, but got ')'.
)
- ^";
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:9:1: Error: Expected ';' before this.
+}
+^"]/* from null */;
+static method main() → void {
+ throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#f, 32, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>["x${(let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#x, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})))).*("'")}"]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
}
diff --git a/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect b/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect
index d2f376d..75e88e2 100644
--- a/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_29976.dart.strong.expect
@@ -1,8 +1,25 @@
library;
import self as self;
+import "dart:core" as core;
-static method #main() → dynamic {
- throw "pkg/front_end/testcases/regress/issue_29976.dart:8:3: Error: Expected a String, but got ')'.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_29976.dart:7:14: Error: The non-ASCII character '\u0233' (U+00E9) can't be used in identifiers, only in strings and comments.
+Try using an US-ASCII letter, a digit, '_' (an underscore), or '\$' (a dollar sign).
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:15: Error: String starting with ' must end with '.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:7: Error: Can't find '}' to match '\${'.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:10:1: Error: String starting with \" must end with \".", "pkg/front_end/testcases/regress/issue_29976.dart:10:1: Error: Expected a declaration, but got ''.", "pkg/front_end/testcases/regress/issue_29976.dart:7:9: Error: Getter not found: 'x'.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:7:14: Error: Expected '}' before this.
+ \"x\${x*\"'\"\u0233'}x
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:8:3: Error: Expected a String, but got ')'.
)
- ^";
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:6:3: Error: Method not found: 'f'.
+ f(
+ ^", "pkg/front_end/testcases/regress/issue_29976.dart:9:1: Error: Expected ';' before this.
+}
+^"]/* from null */;
+static method main() → void {
+ throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#f, 32, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>["x${(let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#x, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})))).*("'")}"]), core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
}
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index d0d42f8..6c44f09 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -196,7 +196,7 @@
rasta/unsupported_platform_library: Fail
regress/issue_29975: Fail # Issue 29975.
-regress/issue_29976: RuntimeError # Issue 29976.
+regress/issue_29976: TypeCheckError # Issue 29976.
regress/issue_29982: Fail # Issue 29982.
regress/issue_30836: RuntimeError # Issue 30836.
regress/issue_31184: TypeCheckError