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

Side by Side Diff: pkg/front_end/test/scanner_fasta_test.dart

Issue 2912693002: improve fasta unterminated string recovery (Closed)
Patch Set: Created 3 years, 6 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'package:analyzer/src/fasta/token_utils.dart'; 5 import 'package:analyzer/src/fasta/token_utils.dart';
6 import 'package:front_end/src/fasta/fasta_codes.dart'; 6 import 'package:front_end/src/fasta/fasta_codes.dart';
7 import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta; 7 import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta;
8 import 'package:front_end/src/fasta/scanner/string_scanner.dart' as fasta; 8 import 'package:front_end/src/fasta/scanner/string_scanner.dart' as fasta;
9 import 'package:front_end/src/fasta/scanner/token.dart' as fasta; 9 import 'package:front_end/src/fasta/scanner/token.dart' as fasta;
10 import 'package:front_end/src/fasta/scanner/token_constants.dart' as fasta; 10 import 'package:front_end/src/fasta/scanner/token_constants.dart' as fasta;
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 expect(commentToken.next.previous, commentToken); 234 expect(commentToken.next.previous, commentToken);
235 } 235 }
236 commentToken = commentToken.next; 236 commentToken = commentToken.next;
237 } 237 }
238 token = token.next; 238 token = token.next;
239 } 239 }
240 } 240 }
241 241
242 @override 242 @override
243 @failingTest 243 @failingTest
244 void test_string_multi_unterminated() {
245 // TODO(paulberry,ahe): bad error recovery.
246 super.test_string_multi_unterminated();
247 }
248
249 @override
250 @failingTest
251 void test_string_multi_unterminated_interpolation_block() { 244 void test_string_multi_unterminated_interpolation_block() {
252 // TODO(paulberry,ahe): bad error recovery. 245 // TODO(paulberry,ahe): bad error recovery.
253 super.test_string_multi_unterminated_interpolation_block(); 246 super.test_string_multi_unterminated_interpolation_block();
254 } 247 }
255 248
256 @override 249 @override
257 @failingTest 250 @failingTest
258 void test_string_multi_unterminated_interpolation_identifier() { 251 void test_string_multi_unterminated_interpolation_identifier() {
259 // TODO(paulberry,ahe): bad error recovery. 252 // TODO(paulberry,ahe): bad error recovery.
260 super.test_string_multi_unterminated_interpolation_identifier(); 253 super.test_string_multi_unterminated_interpolation_identifier();
261 } 254 }
262 255
263 @override 256 @override
264 @failingTest 257 @failingTest
265 void test_string_raw_multi_unterminated() {
266 // TODO(paulberry,ahe): bad error recovery.
267 super.test_string_raw_multi_unterminated();
268 }
269
270 @override
271 @failingTest
272 void test_string_raw_simple_unterminated_eof() {
273 // TODO(paulberry,ahe): bad error recovery.
274 super.test_string_raw_simple_unterminated_eof();
275 }
276
277 @override
278 @failingTest
279 void test_string_raw_simple_unterminated_eol() {
280 // TODO(paulberry,ahe): bad error recovery.
281 super.test_string_raw_simple_unterminated_eol();
282 }
283
284 @override
285 @failingTest
286 void test_string_simple_unterminated_eof() {
287 // TODO(paulberry,ahe): bad error recovery.
288 super.test_string_simple_unterminated_eof();
289 }
290
291 @override
292 @failingTest
293 void test_string_simple_unterminated_eol() {
294 // TODO(paulberry,ahe): bad error recovery.
295 super.test_string_simple_unterminated_eol();
296 }
297
298 @override
299 @failingTest
300 void test_string_simple_unterminated_interpolation_block() { 258 void test_string_simple_unterminated_interpolation_block() {
301 // TODO(paulberry,ahe): bad error recovery. 259 // TODO(paulberry,ahe): bad error recovery.
302 super.test_string_simple_unterminated_interpolation_block(); 260 super.test_string_simple_unterminated_interpolation_block();
303 } 261 }
304 262
305 @override 263 @override
306 @failingTest 264 @failingTest
307 void test_string_simple_unterminated_interpolation_identifier() { 265 void test_string_simple_unterminated_interpolation_identifier() {
308 // TODO(paulberry,ahe): bad error recovery. 266 // TODO(paulberry,ahe): bad error recovery.
309 super.test_string_simple_unterminated_interpolation_identifier(); 267 super.test_string_simple_unterminated_interpolation_identifier();
(...skipping 22 matching lines...) Expand all
332 lazyAssignmentOperators: lazyAssignmentOperators); 290 lazyAssignmentOperators: lazyAssignmentOperators);
333 listener.assertNoErrors(); 291 listener.assertNoErrors();
334 return token; 292 return token;
335 } 293 }
336 } 294 }
337 295
338 /// Base class for scanner tests that examine the token stream in Fasta format. 296 /// Base class for scanner tests that examine the token stream in Fasta format.
339 abstract class ScannerTest_Fasta_Base { 297 abstract class ScannerTest_Fasta_Base {
340 Token scan(String source); 298 Token scan(String source);
341 299
300 expectToken(Token token, TokenType type, int offset, int length,
301 {bool isSynthetic: false, String lexeme}) {
302 String description = '${token.type} $token';
303 expect(token.type, type, reason: description);
304 expect(token.offset, offset, reason: description);
305 expect(token.length, length, reason: description);
306 expect(token.isSynthetic, isSynthetic, reason: description);
307 if (lexeme != null) {
308 expect(token.lexeme, lexeme, reason: description);
309 }
310 }
311
312 void test_incomplete_string_interpolation() {
313 Token token = scan(r'"foo ${bar');
314 expectToken(token, TokenType.STRING, 0, 5, lexeme: '"foo ');
315
316 token = token.next;
317 expectToken(token, TokenType.STRING_INTERPOLATION_EXPRESSION, 5, 2);
318 BeginToken interpolationStart = token;
319
320 token = token.next;
321 expectToken(token, TokenType.IDENTIFIER, 7, 3, lexeme: 'bar');
322
323 // Expect interpolation to be terminated before string is closed
324 token = token.next;
325 expectToken(token, TokenType.CLOSE_CURLY_BRACKET, 10, 0,
326 isSynthetic: true, lexeme: '}');
327 expect(interpolationStart.endToken, same(token));
328
329 token = token.next;
330 expect((token as fasta.ErrorToken).errorCode, same(codeUnmatchedToken));
331 expect((token as fasta.UnmatchedToken).begin, same(interpolationStart));
332
333 token = token.next;
334 expectToken(token, TokenType.STRING, 10, 0, isSynthetic: true, lexeme: '"');
335
336 token = token.next;
337 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
338 }
339
340 void test_string_multi_unterminated() {
341 Token token = scan("'''string");
342 expectToken(token, TokenType.STRING, 0, 9, lexeme: "'''string");
343
344 token = token.next;
345 expectToken(token, TokenType.STRING, 9, 0,
346 isSynthetic: true, lexeme: "'''");
347
348 token = token.next;
349 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
350 expect((token as fasta.ErrorToken).start, "'''");
351 }
352
353 void test_string_raw_multi_unterminated() {
354 Token token = scan("r'''string");
355 expectToken(token, TokenType.STRING, 0, 10, lexeme: "r'''string");
356
357 token = token.next;
358 expectToken(token, TokenType.STRING, 10, 0,
359 isSynthetic: true, lexeme: "'''");
360
361 token = token.next;
362 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
363 expect((token as fasta.ErrorToken).start, "r'''");
364 }
365
366 void test_string_raw_simple_unterminated_eof() {
367 Token token = scan("r'string");
368 expectToken(token, TokenType.STRING, 0, 8, lexeme: "r'string");
369
370 token = token.next;
371 expectToken(token, TokenType.STRING, 8, 0, isSynthetic: true, lexeme: "'");
372
373 token = token.next;
374 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
375 expect((token as fasta.ErrorToken).start, "r'");
376 }
377
378 void test_string_raw_simple_unterminated_eol() {
379 Token token = scan("r'string\n");
380 expectToken(token, TokenType.STRING, 0, 8, lexeme: "r'string");
381
382 token = token.next;
383 expectToken(token, TokenType.STRING, 8, 0, isSynthetic: true, lexeme: "'");
384
385 token = token.next;
386 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
387 expect((token as fasta.ErrorToken).start, "r'");
388 }
389
390 void test_string_simple_unterminated_eof() {
391 Token token = scan("'string");
392 expectToken(token, TokenType.STRING, 0, 7, lexeme: "'string");
393
394 token = token.next;
395 expectToken(token, TokenType.STRING, 7, 0, isSynthetic: true, lexeme: "'");
396
397 token = token.next;
398 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
399 expect((token as fasta.ErrorToken).start, "'");
400 }
401
402 void test_string_simple_unterminated_eol() {
403 Token token = scan("'string\n");
404 expectToken(token, TokenType.STRING, 0, 7, lexeme: "'string");
405
406 token = token.next;
407 expectToken(token, TokenType.STRING, 7, 0, isSynthetic: true, lexeme: "'");
408
409 token = token.next;
410 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
411 expect((token as fasta.ErrorToken).start, "'");
412 }
413
342 void test_match_angle_brackets() { 414 void test_match_angle_brackets() {
343 var x = scan('x<y>'); 415 var x = scan('x<y>');
344 var lessThan = x.next as BeginToken; 416 var lessThan = x.next as BeginToken;
345 var y = lessThan.next; 417 var y = lessThan.next;
346 var greaterThan = y.next; 418 var greaterThan = y.next;
347 expect(greaterThan.next.isEof, isTrue); 419 expect(greaterThan.next.isEof, isTrue);
348 expect(lessThan.endGroup, same(greaterThan)); 420 expect(lessThan.endGroup, same(greaterThan));
349 } 421 }
350 422
351 void test_match_angle_brackets_gt_gt() { 423 void test_match_angle_brackets_gt_gt() {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 } 565 }
494 566
495 /// Scanner tests that exercise the Fasta scanner directly. 567 /// Scanner tests that exercise the Fasta scanner directly.
496 @reflectiveTest 568 @reflectiveTest
497 class ScannerTest_Fasta_Direct extends ScannerTest_Fasta_Base { 569 class ScannerTest_Fasta_Direct extends ScannerTest_Fasta_Base {
498 @override 570 @override
499 Token scan(String source) { 571 Token scan(String source) {
500 var scanner = new fasta.StringScanner(source, includeComments: true); 572 var scanner = new fasta.StringScanner(source, includeComments: true);
501 return scanner.tokenize(); 573 return scanner.tokenize();
502 } 574 }
503
504 test_unterminated_string_with_unterminated_interpolation() {
505 Token token = scan(r'"foo ${bar');
506 BeginToken interpolationStart = token.next;
507
508 Token previous;
509 while (token.kind != fasta.BAD_INPUT_TOKEN) {
510 expect(token.isEof, isFalse);
511 previous = token;
512 token = token.next;
513 }
514
515 // Expect interpolation to be terminated before string is closed
516
517 token = previous;
518 expect(token.isSynthetic, isTrue);
519 expect(token.length, 0);
520 expect(token.stringValue, '}');
521
522 token = token.next;
523 expect((token as fasta.ErrorToken).errorCode, same(codeUnmatchedToken));
524 expect((token as fasta.UnmatchedToken).begin, same(interpolationStart));
525
526 token = token.next;
527 expect((token as fasta.ErrorToken).errorCode, same(codeUnterminatedString));
528 }
529 } 575 }
530 576
531 /// Override of [ToAnalyzerTokenStreamConverter] that verifies that there are no 577 /// Override of [ToAnalyzerTokenStreamConverter] that verifies that there are no
532 /// errors. 578 /// errors.
533 class ToAnalyzerTokenStreamConverter_NoErrors 579 class ToAnalyzerTokenStreamConverter_NoErrors
534 extends ToAnalyzerTokenStreamConverter { 580 extends ToAnalyzerTokenStreamConverter {
535 @override 581 @override
536 void reportError( 582 void reportError(
537 ScannerErrorCode errorCode, int offset, List<Object> arguments) { 583 ScannerErrorCode errorCode, int offset, List<Object> arguments) {
538 fail('Unexpected error: $errorCode, $offset, $arguments'); 584 fail('Unexpected error: $errorCode, $offset, $arguments');
539 } 585 }
540 } 586 }
541 587
542 /// Override of [ToAnalyzerTokenStreamConverter] that records errors in an 588 /// Override of [ToAnalyzerTokenStreamConverter] that records errors in an
543 /// [ErrorListener]. 589 /// [ErrorListener].
544 class ToAnalyzerTokenStreamConverter_WithListener 590 class ToAnalyzerTokenStreamConverter_WithListener
545 extends ToAnalyzerTokenStreamConverter { 591 extends ToAnalyzerTokenStreamConverter {
546 final ErrorListener _listener; 592 final ErrorListener _listener;
547 593
548 ToAnalyzerTokenStreamConverter_WithListener(this._listener); 594 ToAnalyzerTokenStreamConverter_WithListener(this._listener);
549 595
550 @override 596 @override
551 void reportError( 597 void reportError(
552 ScannerErrorCode errorCode, int offset, List<Object> arguments) { 598 ScannerErrorCode errorCode, int offset, List<Object> arguments) {
553 _listener.errors.add(new TestError(offset, errorCode, arguments)); 599 _listener.errors.add(new TestError(offset, errorCode, arguments));
554 } 600 }
555 } 601 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698