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

Unified Diff: pkg/front_end/test/scanner_replacement_test.dart

Issue 2777153002: move synthetic fasta closers into the token stream (Closed)
Patch Set: rebase Created 3 years, 9 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/test/scanner_fasta_test.dart ('k') | pkg/front_end/test/scanner_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/front_end/test/scanner_replacement_test.dart
diff --git a/pkg/front_end/test/scanner_replacement_test.dart b/pkg/front_end/test/scanner_replacement_test.dart
index 171d943906d6aaf0ec019bb2d50ead2b5641ff37..63ea94f6bcfd3a64785afcd084da010d82f24886 100644
--- a/pkg/front_end/test/scanner_replacement_test.dart
+++ b/pkg/front_end/test/scanner_replacement_test.dart
@@ -9,6 +9,8 @@ import 'package:front_end/src/fasta/scanner/precedence.dart'
import 'package:front_end/src/fasta/scanner/recover.dart'
show defaultRecoveryStrategy;
import 'package:front_end/src/fasta/scanner.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/token.dart' as fasta;
+import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta;
import 'package:front_end/src/scanner/token.dart' as analyzer;
import 'package:front_end/src/scanner/errors.dart'
show ScannerErrorCode, translateErrorToken;
@@ -54,10 +56,11 @@ class ScannerTest_Replacement extends ScannerTest {
}));
fasta.Token tokens = result.tokens;
assertValidTokenStream(tokens);
+ assertValidBeginTokens(tokens);
if (result.hasErrors) {
List<int> bytes = UTF8.encode(source);
tokens = defaultRecoveryStrategy(bytes, tokens, result.lineStarts);
- assertValidTokenStream(tokens);
+ assertValidTokenStream(tokens, errorsFirst: true);
}
return extractErrors(tokens, listener);
}
@@ -94,25 +97,126 @@ class ScannerTest_Replacement extends ScannerTest {
super.test_comment_generic_method_type_list();
}
+ void _assertOpenClosePair(String source) {
+ fasta.BeginGroupToken open = _scan(source);
+ fasta.Token close = open.next;
+ expect(close.next.isEof, isTrue);
+ expect(open.endGroup, close);
+ expect(open.isSynthetic, isFalse);
+ expect(close.isSynthetic, isFalse);
+ }
+
+ void _assertOpenOnly(String source) {
+ fasta.BeginGroupToken open = _scan(source);
+ fasta.Token close = open.next;
+ expect(close.next.isEof, isTrue);
+ expect(open.endGroup, close);
+ expect(open.isSynthetic, isFalse);
+ expect(close.isSynthetic, isTrue);
+ }
+
+ void test_lt() {
+ // fasta does not automatically insert a closer for '<'
+ // because it could be part of an expression rather than an opener
+ fasta.BeginGroupToken lt = _scan('<');
+ expect(lt.next.isEof, isTrue);
+ expect(lt.isSynthetic, isFalse);
+ }
+
+ void test_lt_gt() {
+ _assertOpenClosePair('< >');
+ }
+
+ @override
+ void test_open_curly_bracket() {
+ _assertOpenOnly('{');
+ }
+
+ void test_open_curly_bracket_with_close() {
+ _assertOpenClosePair('{ }');
+ }
+
+ void test_open_paren() {
+ _assertOpenOnly('(');
+ }
+
+ void test_open_paren_with_close() {
+ _assertOpenClosePair('( )');
+ }
+
+ void test_open_square_bracket() {
+ _assertOpenOnly('[');
+ }
+
+ void test_open_square_bracket_with_close() {
+ _assertOpenClosePair('[ ]');
+ }
+
@override
- @failingTest
void test_mismatched_closer() {
- // TODO(danrubel): investigate and fix
- super.test_mismatched_closer();
+ // When openers and closers are mismatched,
+ // fasta favors considering the opener to be mismatched,
+ // and inserts synthetic closers as needed.
+ // `(])` is parsed as `()])` where the first `)` is synthetic
+ // and the trailing `])` are unmatched.
+ fasta.BeginGroupToken openParen = _scan('(])');
+ fasta.Token closeParen = openParen.next;
+ fasta.Token closeBracket = closeParen.next;
+ fasta.Token closeParen2 = closeBracket.next;
+ fasta.Token eof = closeParen2.next;
+
+ expect(openParen.endToken, same(closeParen));
+ expect(closeParen.isSynthetic, isTrue);
+ expect(eof.isEof, isTrue);
}
@override
- @failingTest
void test_mismatched_opener() {
- // TODO(danrubel): investigate and fix
- super.test_mismatched_opener();
+ // When openers and closers are mismatched,
+ // fasta favors considering the opener to be mismatched
+ // and inserts synthetic closers as needed.
+ // `([)` is parsed as `([])` where `]` is synthetic.
+ fasta.BeginGroupToken openParen = _scan('([)');
+ fasta.BeginGroupToken openBracket = openParen.next;
+ fasta.Token closeBracket = openBracket.next; // <-- synthetic
+ fasta.Token closeParen = closeBracket.next;
+ fasta.Token eof = closeParen.next;
+
+ expect(openParen.endToken, same(closeParen));
+ expect(closeParen.isSynthetic, isFalse);
+ expect(openBracket.endToken, same(closeBracket));
+ expect(closeBracket.isSynthetic, isTrue);
+ expect(eof.isEof, isTrue);
}
@override
- @failingTest
void test_mismatched_opener_in_interpolation() {
- // TODO(danrubel): investigate and fix
- super.test_mismatched_opener_in_interpolation();
+ // When openers and closers are mismatched,
+ // fasta favors considering the opener to be mismatched
+ // and inserts synthetic closers as needed.
+ // r'"${({(}}"' is parsed as r'"${({()})}"'
+ // where both ')' are synthetic
+ var stringStart = _scan(r'"${({(}}"');
+ var interpolationStart = stringStart.next as fasta.BeginGroupToken;
+ var openParen1 = interpolationStart.next as fasta.BeginGroupToken;
+ var openBrace = openParen1.next as fasta.BeginGroupToken;
+ var openParen2 = openBrace.next as fasta.BeginGroupToken;
+ var closeParen2 = openParen2.next;
+ var closeBrace = closeParen2.next;
+ var closeParen1 = closeBrace.next;
+ var interpolationEnd = closeParen1.next;
+ var stringEnd = interpolationEnd.next;
+ var eof = stringEnd.next;
+
+ expect(interpolationStart.endToken, same(interpolationEnd));
+ expect(interpolationEnd.isSynthetic, isFalse);
+ expect(openParen1.endToken, same(closeParen1));
+ expect(closeParen1.isSynthetic, isTrue);
+ expect(openBrace.endToken, same(closeBrace));
+ expect(closeBrace.isSynthetic, isFalse);
+ expect(openParen2.endToken, same(closeParen2));
+ expect(closeParen2.isSynthetic, isTrue);
+ expect(eof.isEof, isTrue);
}
@override
@@ -199,24 +303,22 @@ class ScannerTest_Replacement extends ScannerTest {
super.test_string_simple_unterminated_interpolation_identifier();
}
- @failingTest
@override
void test_unmatched_openers() {
- // fasta recovery inserts closers
- var openBrace = _scan('{[(<') as analyzer.BeginToken;
- var openBracket = openBrace.next as analyzer.BeginToken;
- var openParen = openBracket.next as analyzer.BeginToken;
- var openLT = openParen.next as analyzer.BeginToken;
- var closeGT = openLT.next;
- var closeParen = closeGT.next;
+ // fasta inserts missing closers except for '<'
+ var openBrace = _scan('{[(<') as fasta.BeginGroupToken;
+ var openBracket = openBrace.next as fasta.BeginGroupToken;
+ var openParen = openBracket.next as fasta.BeginGroupToken;
+ var openLT = openParen.next as fasta.BeginGroupToken;
+ var closeParen = openLT.next;
var closeBracket = closeParen.next;
var closeBrace = closeBracket.next;
- expect(closeBrace.next.type, analyzer.TokenType.EOF);
+ var eof = closeBrace.next;
- expect(openBrace.endToken, closeBrace);
- expect(openBracket.endToken, closeBracket);
- expect(openParen.endToken, closeParen);
- expect(openLT.endToken, closeGT);
+ expect(openBrace.endGroup, same(closeBrace));
+ expect(openBracket.endGroup, same(closeBracket));
+ expect(openParen.endGroup, same(closeParen));
+ expect(eof.isEof, true);
}
analyzer.Token _scan(String source,
@@ -250,13 +352,21 @@ class ScannerTest_Replacement extends ScannerTest {
}
/// Assert that the tokens in the stream are correctly connected prev/next.
- void assertValidTokenStream(fasta.Token firstToken) {
+ void assertValidTokenStream(fasta.Token firstToken,
+ {bool errorsFirst: false}) {
fasta.Token token = firstToken;
fasta.Token previous = token.previousToken;
expect(previous.isEof, isTrue, reason: 'Missing leading EOF');
expect(previous.next, token, reason: 'Invalid leading EOF');
expect(previous.previous, previous, reason: 'Invalid leading EOF');
+ if (errorsFirst) {
+ while (!token.isEof && token is fasta.ErrorToken) {
+ token = token.next;
+ }
+ }
+ var isNotErrorToken = isNot(new isInstanceOf<fasta.ErrorToken>());
while (!token.isEof) {
+ if (errorsFirst) expect(token, isNotErrorToken);
previous = token;
token = token.next;
expect(token, isNotNull, reason: previous.toString());
@@ -264,4 +374,29 @@ class ScannerTest_Replacement extends ScannerTest {
}
expect(token.next, token, reason: 'Invalid trailing EOF');
}
+
+ /// Assert that all [fasta.BeginGroupToken] has a valid `endGroup`
+ /// that is in the stream.
+ void assertValidBeginTokens(fasta.Token firstToken) {
+ var openerStack = <fasta.BeginGroupToken>[];
+ fasta.BeginGroupToken lastClosedGroup;
+ fasta.Token token = firstToken;
+ while (!token.isEof) {
+ if (token is fasta.BeginGroupToken) {
+ if (token.lexeme != '<')
+ expect(token.endGroup, isNotNull, reason: token.lexeme);
+ if (token.endGroup != null) openerStack.add(token);
+ } else if (openerStack.isNotEmpty && openerStack.last.endGroup == token) {
+ lastClosedGroup = openerStack.removeLast();
+ expect(token.isSynthetic, token.next is fasta.UnmatchedToken,
+ reason: 'Expect synthetic closer then error token');
+ } else if (token is fasta.UnmatchedToken) {
+ expect(lastClosedGroup?.endGroup?.next, same(token),
+ reason: 'Unexpected error token for group: $lastClosedGroup');
+ expect(token.begin, lastClosedGroup);
+ }
+ token = token.next;
+ }
+ expect(openerStack, isEmpty, reason: 'Missing closers');
+ }
}
« no previous file with comments | « pkg/front_end/test/scanner_fasta_test.dart ('k') | pkg/front_end/test/scanner_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698