Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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:front_end/src/base/errors.dart'; | 5 import 'package:front_end/src/base/errors.dart'; |
| 6 import 'package:front_end/src/base/jenkins_smi_hash.dart'; | 6 import 'package:front_end/src/base/jenkins_smi_hash.dart'; |
| 7 import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta; | |
| 8 import 'package:front_end/src/fasta/scanner/keyword.dart' as fasta; | |
| 9 import 'package:front_end/src/fasta/scanner/string_scanner.dart' as fasta; | |
| 10 import 'package:front_end/src/fasta/scanner/token.dart' as fasta; | |
| 11 import 'package:front_end/src/fasta/scanner/token_constants.dart' as fasta; | |
| 7 import 'package:front_end/src/scanner/errors.dart'; | 12 import 'package:front_end/src/scanner/errors.dart'; |
| 8 import 'package:front_end/src/scanner/reader.dart'; | 13 import 'package:front_end/src/scanner/reader.dart'; |
| 9 import 'package:front_end/src/scanner/scanner.dart'; | 14 import 'package:front_end/src/scanner/scanner.dart'; |
| 10 import 'package:front_end/src/scanner/token.dart'; | 15 import 'package:front_end/src/scanner/token.dart'; |
| 11 import 'package:test/test.dart'; | 16 import 'package:test/test.dart'; |
| 12 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 17 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| 13 | 18 |
| 14 main() { | 19 main() { |
| 15 defineReflectiveSuite(() { | 20 defineReflectiveSuite(() { |
| 16 defineReflectiveTests(CharSequenceReaderTest); | 21 defineReflectiveTests(CharSequenceReaderTest); |
| 17 defineReflectiveTests(KeywordStateTest); | 22 defineReflectiveTests(KeywordStateTest); |
| 18 defineReflectiveTests(ScannerTest); | 23 defineReflectiveTests(ScannerTest); |
|
Paul Berry
2017/02/03 23:10:36
Note that this test file now tests both the analyz
| |
| 24 defineReflectiveTests(ScannerTest_Fasta); | |
| 19 defineReflectiveTests(TokenTypeTest); | 25 defineReflectiveTests(TokenTypeTest); |
| 20 }); | 26 }); |
| 21 } | 27 } |
| 22 | 28 |
| 23 @reflectiveTest | 29 @reflectiveTest |
| 24 class CharSequenceReaderTest { | 30 class CharSequenceReaderTest { |
| 25 void test_advance() { | 31 void test_advance() { |
| 26 CharSequenceReader reader = new CharSequenceReader("x"); | 32 CharSequenceReader reader = new CharSequenceReader("x"); |
| 27 expect(reader.advance(), 0x78); | 33 expect(reader.advance(), 0x78); |
| 28 expect(reader.advance(), -1); | 34 expect(reader.advance(), -1); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 expect(state, isNull); | 112 expect(state, isNull); |
| 107 } else { | 113 } else { |
| 108 // keyword.substring(0, keyword.length() - 1) | 114 // keyword.substring(0, keyword.length() - 1) |
| 109 expect(state, isNotNull); | 115 expect(state, isNotNull); |
| 110 } | 116 } |
| 111 } | 117 } |
| 112 } | 118 } |
| 113 } | 119 } |
| 114 | 120 |
| 115 @reflectiveTest | 121 @reflectiveTest |
| 116 class ScannerTest { | 122 class ScannerTest extends ScannerTestBase { |
| 123 @override | |
| 124 Token _scanWithListener(String source, _ErrorListener listener, | |
| 125 {bool genericMethodComments: false, | |
| 126 bool lazyAssignmentOperators: false}) { | |
| 127 Scanner scanner = | |
| 128 new _TestScanner(new CharSequenceReader(source), listener); | |
| 129 scanner.scanGenericMethodComments = genericMethodComments; | |
| 130 scanner.scanLazyAssignmentOperators = lazyAssignmentOperators; | |
| 131 return scanner.tokenize(); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 @reflectiveTest | |
| 136 class ScannerTest_Fasta extends ScannerTestBase { | |
| 137 final _keywordMap = { | |
| 138 "assert": Keyword.ASSERT, | |
| 139 "break": Keyword.BREAK, | |
| 140 "case": Keyword.CASE, | |
| 141 "catch": Keyword.CATCH, | |
| 142 "class": Keyword.CLASS, | |
| 143 "const": Keyword.CONST, | |
| 144 "continue": Keyword.CONTINUE, | |
| 145 "default": Keyword.DEFAULT, | |
| 146 "do": Keyword.DO, | |
| 147 "else": Keyword.ELSE, | |
| 148 "enum": Keyword.ENUM, | |
| 149 "extends": Keyword.EXTENDS, | |
| 150 "false": Keyword.FALSE, | |
| 151 "final": Keyword.FINAL, | |
| 152 "finally": Keyword.FINALLY, | |
| 153 "for": Keyword.FOR, | |
| 154 "if": Keyword.IF, | |
| 155 "in": Keyword.IN, | |
| 156 "new": Keyword.NEW, | |
| 157 "null": Keyword.NULL, | |
| 158 "rethrow": Keyword.RETHROW, | |
| 159 "return": Keyword.RETURN, | |
| 160 "super": Keyword.SUPER, | |
| 161 "switch": Keyword.SWITCH, | |
| 162 "this": Keyword.THIS, | |
| 163 "throw": Keyword.THROW, | |
| 164 "true": Keyword.TRUE, | |
| 165 "try": Keyword.TRY, | |
| 166 "var": Keyword.VAR, | |
| 167 "void": Keyword.VOID, | |
| 168 "while": Keyword.WHILE, | |
| 169 "with": Keyword.WITH, | |
| 170 "is": Keyword.IS, | |
| 171 "abstract": Keyword.ABSTRACT, | |
| 172 "as": Keyword.AS, | |
| 173 "covariant": Keyword.COVARIANT, | |
| 174 "dynamic": Keyword.DYNAMIC, | |
| 175 "export": Keyword.EXPORT, | |
| 176 "external": Keyword.EXTERNAL, | |
| 177 "factory": Keyword.FACTORY, | |
| 178 "get": Keyword.GET, | |
| 179 "implements": Keyword.IMPLEMENTS, | |
| 180 "import": Keyword.IMPORT, | |
| 181 "library": Keyword.LIBRARY, | |
| 182 "operator": Keyword.OPERATOR, | |
| 183 "part": Keyword.PART, | |
| 184 "set": Keyword.SET, | |
| 185 "static": Keyword.STATIC, | |
| 186 "typedef": Keyword.TYPEDEF, | |
| 187 "deferred": Keyword.DEFERRED, | |
| 188 }; | |
| 189 | |
| 190 @override | |
| 191 @failingTest | |
|
Paul Berry
2017/02/03 23:10:36
Note: these overrides indicate to the test_reflect
| |
| 192 void test_ampersand_ampersand_eq() { | |
| 193 // TODO(paulberry,ahe): Fasta doesn't support `&&=` yet | |
| 194 super.test_ampersand_ampersand_eq(); | |
| 195 } | |
| 196 | |
| 197 @override | |
| 198 @failingTest | |
| 199 void test_bar_bar_eq() { | |
| 200 // TODO(paulberry,ahe): Fasta doesn't support `||=` yet | |
| 201 super.test_bar_bar_eq(); | |
| 202 } | |
| 203 | |
| 204 @override | |
| 205 @failingTest | |
| 206 void test_comment_generic_method_type_assign() { | |
| 207 // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax. | |
|
ahe
2017/02/06 11:01:20
Do you think that would be necessary to support in
Paul Berry
2017/02/06 13:46:54
It's not clear at this point. I asked Dan Grove a
| |
| 208 super.test_comment_generic_method_type_assign(); | |
| 209 } | |
| 210 | |
| 211 @override | |
| 212 @failingTest | |
| 213 void test_comment_generic_method_type_list() { | |
| 214 // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax. | |
| 215 super.test_comment_generic_method_type_list(); | |
| 216 } | |
| 217 | |
| 218 @override | |
| 219 @failingTest | |
| 220 void test_comment_multi_unterminated() { | |
| 221 // TODO(paulberry,ahe): see UnimplementedError("distinguish unterminated err ors") | |
|
ahe
2017/02/06 11:01:20
Long line here and a few below.
Paul Berry
2017/02/06 13:46:54
Done.
| |
| 222 super.test_comment_multi_unterminated(); | |
| 223 } | |
| 224 | |
| 225 @override | |
| 226 @failingTest | |
| 227 void test_comment_single() { | |
| 228 // TODO(paulberry,ahe): See TODO comment below in _translateTokenInfoKind(). | |
| 229 super.test_comment_single(); | |
| 230 } | |
| 231 | |
| 232 @override | |
| 233 @failingTest | |
| 234 void test_double_missingDigitInExponent() { | |
| 235 // TODO(paulberry,ahe): see UnimplementedError("distinguish unterminated err ors") | |
| 236 super.test_double_missingDigitInExponent(); | |
| 237 } | |
| 238 | |
| 239 @override | |
| 240 @failingTest | |
| 241 void test_hexidecimal_missingDigit() { | |
| 242 // TODO(paulberry,ahe): see UnimplementedError("distinguish unterminated err ors") | |
| 243 super.test_hexidecimal_missingDigit(); | |
| 244 } | |
| 245 | |
| 246 @override | |
| 247 @failingTest | |
| 248 void test_index() { | |
| 249 // TODO(paulberry,ahe): "[]" should be parsed as a single token. | |
|
ahe
2017/02/04 09:48:19
Note: [] and []= are tokenized as a single token o
Paul Berry
2017/02/04 14:57:55
Interesting. The behavior of the analyzer scanner
ahe
2017/02/06 11:01:20
I agree. A corner case with the dart2js/fasta appr
Paul Berry
2017/02/06 13:46:54
SGTM.
Siggi Cherem (dart-lang)
2017/02/06 23:51:29
A small question: could we annotate somehow these
Paul Berry
2017/02/07 13:56:11
I've filed an issue: https://github.com/dart-lang/
| |
| 250 super.test_index(); | |
| 251 } | |
| 252 | |
| 253 @override | |
| 254 @failingTest | |
| 255 void test_index_eq() { | |
| 256 // TODO(paulberry,ahe): "[]=" should be parsed as a single token. | |
| 257 super.test_index_eq(); | |
| 258 } | |
| 259 | |
| 260 @override | |
| 261 @failingTest | |
| 262 void test_scriptTag_withArgs() { | |
| 263 // TODO(paulberry,ahe): script tags are needed by analyzer. | |
| 264 super.test_scriptTag_withArgs(); | |
| 265 } | |
| 266 | |
| 267 @override | |
| 268 @failingTest | |
| 269 void test_scriptTag_withoutSpace() { | |
| 270 // TODO(paulberry,ahe): script tags are needed by analyzer. | |
| 271 super.test_scriptTag_withoutSpace(); | |
| 272 } | |
| 273 | |
| 274 @override | |
| 275 @failingTest | |
| 276 void test_scriptTag_withSpace() { | |
| 277 // TODO(paulberry,ahe): script tags are needed by analyzer. | |
| 278 super.test_scriptTag_withSpace(); | |
| 279 } | |
| 280 | |
| 281 @override | |
| 282 @failingTest | |
| 283 void test_string_multi_unterminated() { | |
| 284 // TODO(paulberry,ahe): bad error recovery. | |
| 285 super.test_string_multi_unterminated(); | |
| 286 } | |
| 287 | |
| 288 @override | |
| 289 @failingTest | |
| 290 void test_string_multi_unterminated_interpolation_block() { | |
| 291 // TODO(paulberry,ahe): bad error recovery. | |
| 292 super.test_string_multi_unterminated_interpolation_block(); | |
| 293 } | |
| 294 | |
| 295 @override | |
| 296 @failingTest | |
| 297 void test_string_multi_unterminated_interpolation_identifier() { | |
| 298 // TODO(paulberry,ahe): bad error recovery. | |
| 299 super.test_string_multi_unterminated_interpolation_identifier(); | |
| 300 } | |
| 301 | |
| 302 @override | |
| 303 @failingTest | |
| 304 void test_string_raw_multi_unterminated() { | |
| 305 // TODO(paulberry,ahe): bad error recovery. | |
| 306 super.test_string_raw_multi_unterminated(); | |
| 307 } | |
| 308 | |
| 309 @override | |
| 310 @failingTest | |
| 311 void test_string_raw_simple_unterminated_eof() { | |
| 312 // TODO(paulberry,ahe): bad error recovery. | |
| 313 super.test_string_raw_simple_unterminated_eof(); | |
| 314 } | |
| 315 | |
| 316 @override | |
| 317 @failingTest | |
| 318 void test_string_raw_simple_unterminated_eol() { | |
| 319 // TODO(paulberry,ahe): bad error recovery. | |
| 320 super.test_string_raw_simple_unterminated_eol(); | |
| 321 } | |
| 322 | |
| 323 @override | |
| 324 @failingTest | |
| 325 void test_string_simple_interpolation_missingIdentifier() { | |
| 326 // TODO(paulberry,ahe): bad error recovery. | |
| 327 super.test_string_simple_interpolation_missingIdentifier(); | |
| 328 } | |
| 329 | |
| 330 @override | |
| 331 @failingTest | |
| 332 void test_string_simple_interpolation_nonIdentifier() { | |
| 333 // TODO(paulberry,ahe): bad error recovery. | |
| 334 super.test_string_simple_interpolation_nonIdentifier(); | |
| 335 } | |
| 336 | |
| 337 @override | |
| 338 @failingTest | |
| 339 void test_string_simple_unterminated_eof() { | |
| 340 // TODO(paulberry,ahe): bad error recovery. | |
| 341 super.test_string_simple_unterminated_eof(); | |
| 342 } | |
| 343 | |
| 344 @override | |
| 345 @failingTest | |
| 346 void test_string_simple_unterminated_eol() { | |
| 347 // TODO(paulberry,ahe): bad error recovery. | |
| 348 super.test_string_simple_unterminated_eol(); | |
| 349 } | |
| 350 | |
| 351 @override | |
| 352 @failingTest | |
| 353 void test_string_simple_unterminated_interpolation_block() { | |
| 354 // TODO(paulberry,ahe): bad error recovery. | |
| 355 super.test_string_simple_unterminated_interpolation_block(); | |
| 356 } | |
| 357 | |
| 358 @override | |
| 359 @failingTest | |
| 360 void test_string_simple_unterminated_interpolation_identifier() { | |
| 361 // TODO(paulberry,ahe): bad error recovery. | |
| 362 super.test_string_simple_unterminated_interpolation_identifier(); | |
| 363 } | |
| 364 | |
| 365 @override | |
| 366 Token _scanWithListener(String source, _ErrorListener listener, | |
| 367 {bool genericMethodComments: false, | |
| 368 bool lazyAssignmentOperators: false}) { | |
| 369 if (genericMethodComments) { | |
| 370 // Fasta doesn't support generic method comments. | |
| 371 // TODO(paulberry): once the analyzer toolchain no longer needs generic | |
| 372 // method comments, remove tests that exercise them. | |
| 373 fail('No generic method comment support in Fasta'); | |
| 374 } | |
| 375 // Note: Fasta always supports lazy assignment operators (`&&=` and `||=`), | |
| 376 // so we can ignore the `lazyAssignmentOperators` flag. | |
| 377 // TODO(paulberry): once lazyAssignmentOperators are fully supported by | |
| 378 // Dart, remove this flag. | |
| 379 var scanner = new fasta.StringScanner(source, includeComments: true); | |
| 380 var token = scanner.tokenize(); | |
| 381 var analyzerTokenHead = new Token(null, 0); | |
| 382 analyzerTokenHead.previous = analyzerTokenHead; | |
| 383 var analyzerTokenTail = analyzerTokenHead; | |
| 384 // TODO(paulberry,ahe): Fasta includes comments directly in the token | |
| 385 // stream, rather than pointing to them via a "precedingComment" pointer, as | |
| 386 // analyzer does. This seems like it will complicate parsing and other | |
| 387 // operations. | |
| 388 CommentToken currentCommentHead; | |
| 389 CommentToken currentCommentTail; | |
| 390 while (true) { | |
| 391 if (token is fasta.ErrorToken) { | |
| 392 var error = _translateErrorToken(token, source.length); | |
| 393 if (error != null) { | |
| 394 listener.errors.add(error); | |
| 395 } | |
| 396 } else if (token is fasta.StringToken && | |
| 397 token.info.kind == fasta.COMMENT_TOKEN) { | |
| 398 var translatedToken = _translateToken(token, null) as CommentToken; | |
| 399 if (currentCommentHead == null) { | |
| 400 currentCommentHead = currentCommentTail = translatedToken; | |
| 401 } else { | |
| 402 currentCommentTail.setNext(translatedToken); | |
| 403 currentCommentTail = translatedToken; | |
| 404 } | |
| 405 } else { | |
| 406 var translatedToken = _translateToken(token, currentCommentHead); | |
| 407 translatedToken.setNext(translatedToken); | |
| 408 currentCommentHead = currentCommentTail = null; | |
| 409 analyzerTokenTail.setNext(translatedToken); | |
| 410 translatedToken.previous = analyzerTokenTail; | |
| 411 analyzerTokenTail = translatedToken; | |
| 412 } | |
| 413 if (token.isEof) { | |
| 414 return analyzerTokenHead.next; | |
| 415 } | |
| 416 token = token.next; | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 _TestError _translateErrorToken(fasta.ErrorToken token, int inputLength) { | |
| 421 int charOffset = token.charOffset; | |
| 422 // TODO(paulberry,ahe): why is endOffset sometimes null? | |
| 423 int endOffset = token.endOffset ?? charOffset; | |
| 424 _TestError _makeError(ScannerErrorCode errorCode, List<Object> arguments) { | |
| 425 int errorLength = endOffset - charOffset; | |
| 426 if (charOffset == inputLength) { | |
| 427 // Analyzer never generates an error message past the end of the input, | |
| 428 // since such an error would not be visible in an editor. | |
| 429 // TODO(paulberry,ahe): would it make sense to replicate this behavior | |
| 430 // in fasta, or move it elsewhere in analyzer? | |
| 431 charOffset--; | |
| 432 } | |
| 433 if (errorLength == 0) { | |
| 434 // Analyzer never generates an error message of length zero, | |
| 435 // since such an error would not be visible in an editor. | |
| 436 // TODO(paulberry,ahe): would it make sense to replicate this behavior | |
| 437 // in fasta, or move it elsewhere in analyzer? | |
| 438 errorLength = 1; | |
| 439 } | |
| 440 return new _TestError(charOffset, errorLength, errorCode, arguments); | |
| 441 } | |
| 442 | |
| 443 if (token is fasta.UnterminatedToken) { | |
| 444 // TODO(paulberry,ahe): How to tell what kind of error to | |
| 445 // report? It could be ScannerErrorCode.UNTERMINATED_STRING_LITERAL, | |
| 446 // ScannerErrorCode.MISSING_HEX_DIGIT, or | |
| 447 // ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT | |
|
ahe
2017/02/04 09:48:19
Absolutely. Just this week, I was thinking about c
Paul Berry
2017/02/04 14:57:55
Aha, thank you. I failed to notice the presence o
ahe
2017/02/06 11:01:20
We should be careful about polymorphism, but in th
Paul Berry
2017/02/06 13:46:54
Aha, nice. When I do my rework of this code (whic
| |
| 448 return _makeError( | |
| 449 throw new UnimplementedError("distinguish unterminated errors"), | |
| 450 null); | |
| 451 } else if (token is fasta.UnmatchedToken) { | |
| 452 return null; | |
| 453 } else if (token is fasta.NonAsciiIdentifierToken) { | |
| 454 return _makeError(ScannerErrorCode.ILLEGAL_CHARACTER, [token.character]); | |
| 455 } else if (token is fasta.NonAsciiWhitespaceToken) { | |
| 456 return _makeError(ScannerErrorCode.ILLEGAL_CHARACTER, [token.character]); | |
| 457 } | |
| 458 throw new UnimplementedError('${token.runtimeType}'); | |
| 459 } | |
| 460 | |
| 461 Keyword _translateKeyword(String syntax) => | |
| 462 _keywordMap[syntax] ?? (throw new UnimplementedError('$syntax')); | |
| 463 | |
| 464 Token _translateToken(fasta.Token token, CommentToken comment) { | |
| 465 var type = _translateTokenInfoKind(token.info.kind); | |
| 466 int offset = token.charOffset; | |
| 467 Token makeStringToken(String value) { | |
| 468 if (comment == null) { | |
| 469 return new StringToken(type, value, offset); | |
| 470 } else { | |
| 471 return new StringTokenWithComment(type, value, offset, comment); | |
| 472 } | |
| 473 } | |
| 474 | |
| 475 Token makeKeywordToken(Keyword keyword) { | |
| 476 if (comment == null) { | |
| 477 return new KeywordToken(keyword, offset); | |
| 478 } else { | |
| 479 return new KeywordTokenWithComment(keyword, offset, comment); | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 Token makeBeginToken() { | |
| 484 if (comment == null) { | |
| 485 return new BeginToken(type, offset); | |
| 486 } else { | |
| 487 return new BeginTokenWithComment(type, offset, comment); | |
| 488 } | |
| 489 } | |
| 490 | |
| 491 Token makeCommentToken() { | |
| 492 return new CommentToken(type, token.value, offset); | |
| 493 } | |
| 494 | |
| 495 if (token is fasta.StringToken) { | |
| 496 if (token.info.kind == fasta.COMMENT_TOKEN) { | |
| 497 return makeCommentToken(); | |
| 498 } else { | |
| 499 return makeStringToken(token.value); | |
| 500 } | |
| 501 } else if (token is fasta.KeywordToken) { | |
| 502 return makeKeywordToken(_translateKeyword(token.keyword.syntax)); | |
| 503 } else if (token is fasta.SymbolToken) { | |
| 504 if (token is fasta.BeginGroupToken) { | |
| 505 if (type == TokenType.LT) { | |
| 506 return makeStringToken(token.value); | |
| 507 } else { | |
| 508 return makeBeginToken(); | |
| 509 } | |
| 510 } else { | |
| 511 return makeStringToken(token.value); | |
| 512 } | |
| 513 } | |
| 514 throw new UnimplementedError('${token.runtimeType}'); | |
| 515 } | |
| 516 | |
| 517 TokenType _translateTokenInfoKind(int kind) { | |
| 518 switch (kind) { | |
| 519 case fasta.EOF_TOKEN: | |
| 520 return TokenType.EOF; | |
| 521 case fasta.KEYWORD_TOKEN: | |
| 522 return TokenType.KEYWORD; | |
| 523 case fasta.IDENTIFIER_TOKEN: | |
| 524 return TokenType.IDENTIFIER; | |
| 525 case fasta.BAD_INPUT_TOKEN: | |
| 526 return TokenType.STRING; | |
| 527 case fasta.DOUBLE_TOKEN: | |
| 528 return TokenType.DOUBLE; | |
| 529 case fasta.INT_TOKEN: | |
| 530 return TokenType.INT; | |
| 531 case fasta.HEXADECIMAL_TOKEN: | |
| 532 return TokenType.HEXADECIMAL; | |
| 533 case fasta.STRING_TOKEN: | |
| 534 return TokenType.STRING; | |
| 535 case fasta.AMPERSAND_TOKEN: | |
| 536 return TokenType.AMPERSAND; | |
| 537 case fasta.BACKPING_TOKEN: | |
| 538 return TokenType.BACKPING; | |
| 539 case fasta.BACKSLASH_TOKEN: | |
| 540 return TokenType.BACKSLASH; | |
| 541 case fasta.BANG_TOKEN: | |
| 542 return TokenType.BANG; | |
| 543 case fasta.BAR_TOKEN: | |
| 544 return TokenType.BAR; | |
| 545 case fasta.COLON_TOKEN: | |
| 546 return TokenType.COLON; | |
| 547 case fasta.COMMA_TOKEN: | |
| 548 return TokenType.COMMA; | |
| 549 case fasta.EQ_TOKEN: | |
| 550 return TokenType.EQ; | |
| 551 case fasta.GT_TOKEN: | |
| 552 return TokenType.GT; | |
| 553 case fasta.HASH_TOKEN: | |
| 554 return TokenType.HASH; | |
| 555 case fasta.OPEN_CURLY_BRACKET_TOKEN: | |
| 556 return TokenType.OPEN_CURLY_BRACKET; | |
| 557 case fasta.OPEN_SQUARE_BRACKET_TOKEN: | |
| 558 return TokenType.OPEN_SQUARE_BRACKET; | |
| 559 case fasta.OPEN_PAREN_TOKEN: | |
| 560 return TokenType.OPEN_PAREN; | |
| 561 case fasta.LT_TOKEN: | |
| 562 return TokenType.LT; | |
| 563 case fasta.MINUS_TOKEN: | |
| 564 return TokenType.MINUS; | |
| 565 case fasta.PERIOD_TOKEN: | |
| 566 return TokenType.PERIOD; | |
| 567 case fasta.PLUS_TOKEN: | |
| 568 return TokenType.PLUS; | |
| 569 case fasta.QUESTION_TOKEN: | |
| 570 return TokenType.QUESTION; | |
| 571 case fasta.AT_TOKEN: | |
| 572 return TokenType.AT; | |
| 573 case fasta.CLOSE_CURLY_BRACKET_TOKEN: | |
| 574 return TokenType.CLOSE_CURLY_BRACKET; | |
| 575 case fasta.CLOSE_SQUARE_BRACKET_TOKEN: | |
| 576 return TokenType.CLOSE_SQUARE_BRACKET; | |
| 577 case fasta.CLOSE_PAREN_TOKEN: | |
| 578 return TokenType.CLOSE_PAREN; | |
| 579 case fasta.SEMICOLON_TOKEN: | |
| 580 return TokenType.SEMICOLON; | |
| 581 case fasta.SLASH_TOKEN: | |
| 582 return TokenType.SLASH; | |
| 583 case fasta.TILDE_TOKEN: | |
| 584 return TokenType.TILDE; | |
| 585 case fasta.STAR_TOKEN: | |
| 586 return TokenType.STAR; | |
| 587 case fasta.PERCENT_TOKEN: | |
| 588 return TokenType.PERCENT; | |
| 589 case fasta.CARET_TOKEN: | |
| 590 return TokenType.CARET; | |
| 591 case fasta.STRING_INTERPOLATION_TOKEN: | |
| 592 return TokenType.STRING_INTERPOLATION_EXPRESSION; | |
| 593 case fasta.LT_EQ_TOKEN: | |
| 594 return TokenType.LT_EQ; | |
| 595 case fasta.FUNCTION_TOKEN: | |
| 596 return TokenType.FUNCTION; | |
| 597 case fasta.SLASH_EQ_TOKEN: | |
| 598 return TokenType.SLASH_EQ; | |
| 599 case fasta.PERIOD_PERIOD_PERIOD_TOKEN: | |
| 600 return TokenType.PERIOD_PERIOD_PERIOD; | |
| 601 case fasta.PERIOD_PERIOD_TOKEN: | |
| 602 return TokenType.PERIOD_PERIOD; | |
| 603 case fasta.EQ_EQ_EQ_TOKEN: | |
| 604 // TODO(paulberry,ahe): what is this? | |
| 605 throw new UnimplementedError(); | |
| 606 case fasta.EQ_EQ_TOKEN: | |
| 607 return TokenType.EQ_EQ; | |
| 608 case fasta.LT_LT_EQ_TOKEN: | |
| 609 return TokenType.LT_LT_EQ; | |
| 610 case fasta.LT_LT_TOKEN: | |
| 611 return TokenType.LT_LT; | |
| 612 case fasta.GT_EQ_TOKEN: | |
| 613 return TokenType.GT_EQ; | |
| 614 case fasta.GT_GT_EQ_TOKEN: | |
| 615 return TokenType.GT_GT_EQ; | |
| 616 case fasta.INDEX_EQ_TOKEN: | |
| 617 return TokenType.INDEX_EQ; | |
| 618 case fasta.INDEX_TOKEN: | |
| 619 return TokenType.INDEX; | |
| 620 case fasta.BANG_EQ_EQ_TOKEN: | |
| 621 // TODO(paulberry,ahe): what is this? | |
| 622 throw new UnimplementedError(); | |
| 623 case fasta.BANG_EQ_TOKEN: | |
| 624 return TokenType.BANG_EQ; | |
| 625 case fasta.AMPERSAND_AMPERSAND_TOKEN: | |
| 626 return TokenType.AMPERSAND_AMPERSAND; | |
| 627 case fasta.AMPERSAND_EQ_TOKEN: | |
| 628 return TokenType.AMPERSAND_EQ; | |
| 629 case fasta.BAR_BAR_TOKEN: | |
| 630 return TokenType.BAR_BAR; | |
| 631 case fasta.BAR_EQ_TOKEN: | |
| 632 return TokenType.BAR_EQ; | |
| 633 case fasta.STAR_EQ_TOKEN: | |
| 634 return TokenType.STAR_EQ; | |
| 635 case fasta.PLUS_PLUS_TOKEN: | |
| 636 return TokenType.PLUS_PLUS; | |
| 637 case fasta.PLUS_EQ_TOKEN: | |
| 638 return TokenType.PLUS_EQ; | |
| 639 case fasta.MINUS_MINUS_TOKEN: | |
| 640 return TokenType.MINUS_MINUS; | |
| 641 case fasta.MINUS_EQ_TOKEN: | |
| 642 return TokenType.MINUS_EQ; | |
| 643 case fasta.TILDE_SLASH_EQ_TOKEN: | |
| 644 return TokenType.TILDE_SLASH_EQ; | |
| 645 case fasta.TILDE_SLASH_TOKEN: | |
| 646 return TokenType.TILDE_SLASH; | |
| 647 case fasta.PERCENT_EQ_TOKEN: | |
| 648 return TokenType.PERCENT_EQ; | |
| 649 case fasta.GT_GT_TOKEN: | |
| 650 return TokenType.GT_GT; | |
| 651 case fasta.CARET_EQ_TOKEN: | |
| 652 return TokenType.CARET_EQ; | |
| 653 case fasta.COMMENT_TOKEN: | |
| 654 // TODO(paulberry,ahe): how to distinguish multi-line from | |
| 655 // single-line comments? Causes a failure in test_comment_single(). | |
|
ahe
2017/02/06 11:01:20
I'd just look at the first two characters of the c
Paul Berry
2017/02/06 13:46:54
Ok. I'll make a follow-up CL that adjusts this co
| |
| 656 return TokenType.MULTI_LINE_COMMENT; | |
| 657 case fasta.STRING_INTERPOLATION_IDENTIFIER_TOKEN: | |
| 658 return TokenType.STRING_INTERPOLATION_IDENTIFIER; | |
| 659 case fasta.QUESTION_PERIOD_TOKEN: | |
| 660 return TokenType.QUESTION_PERIOD; | |
| 661 case fasta.QUESTION_QUESTION_TOKEN: | |
| 662 return TokenType.QUESTION_QUESTION; | |
| 663 case fasta.QUESTION_QUESTION_EQ_TOKEN: | |
| 664 return TokenType.QUESTION_QUESTION_EQ; | |
| 665 default: | |
| 666 throw new UnimplementedError('$kind'); | |
| 667 } | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 abstract class ScannerTestBase { | |
| 117 void fail_incomplete_string_interpolation() { | 672 void fail_incomplete_string_interpolation() { |
| 118 // https://code.google.com/p/dart/issues/detail?id=18073 | 673 // https://code.google.com/p/dart/issues/detail?id=18073 |
| 119 _assertErrorAndTokens( | 674 _assertErrorAndTokens( |
| 120 ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [ | 675 ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [ |
| 121 new StringToken(TokenType.STRING, "\"foo ", 0), | 676 new StringToken(TokenType.STRING, "\"foo ", 0), |
| 122 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5), | 677 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5), |
| 123 new StringToken(TokenType.IDENTIFIER, "bar", 7) | 678 new StringToken(TokenType.IDENTIFIER, "bar", 7) |
| 124 ]); | 679 ]); |
| 125 } | 680 } |
| 126 | 681 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 void test_comment_generic_method_type_list() { | 778 void test_comment_generic_method_type_list() { |
| 224 _assertComment(TokenType.MULTI_LINE_COMMENT, "/*<comment>*/"); | 779 _assertComment(TokenType.MULTI_LINE_COMMENT, "/*<comment>*/"); |
| 225 _assertComment(TokenType.GENERIC_METHOD_TYPE_LIST, "/*<comment>*/", | 780 _assertComment(TokenType.GENERIC_METHOD_TYPE_LIST, "/*<comment>*/", |
| 226 genericMethodComments: true); | 781 genericMethodComments: true); |
| 227 } | 782 } |
| 228 | 783 |
| 229 void test_comment_multi() { | 784 void test_comment_multi() { |
| 230 _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */"); | 785 _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */"); |
| 231 } | 786 } |
| 232 | 787 |
| 788 void test_comment_multi_consecutive_2() { | |
|
Paul Berry
2017/02/03 23:10:36
Note: during this process I discovered that consec
| |
| 789 Token token = _scan("/* x */ /* y */ z"); | |
| 790 expect(token.type, TokenType.IDENTIFIER); | |
| 791 expect(token.precedingComments, isNotNull); | |
| 792 expect(token.precedingComments.value(), "/* x */"); | |
| 793 expect(token.precedingComments.previous, isNull); | |
| 794 expect(token.precedingComments.next, isNotNull); | |
| 795 expect(token.precedingComments.next.value(), "/* y */"); | |
| 796 expect( | |
| 797 token.precedingComments.next.previous, same(token.precedingComments)); | |
| 798 expect(token.precedingComments.next.next, isNull); | |
| 799 } | |
| 800 | |
| 801 void test_comment_multi_consecutive_3() { | |
| 802 Token token = _scan("/* x */ /* y */ /* z */ a"); | |
| 803 expect(token.type, TokenType.IDENTIFIER); | |
| 804 expect(token.precedingComments, isNotNull); | |
| 805 expect(token.precedingComments.value(), "/* x */"); | |
| 806 expect(token.precedingComments.previous, isNull); | |
| 807 expect(token.precedingComments.next, isNotNull); | |
| 808 expect(token.precedingComments.next.value(), "/* y */"); | |
| 809 expect( | |
| 810 token.precedingComments.next.previous, same(token.precedingComments)); | |
| 811 expect(token.precedingComments.next.next, isNotNull); | |
| 812 expect(token.precedingComments.next.next.value(), "/* z */"); | |
| 813 expect(token.precedingComments.next.next.previous, | |
| 814 same(token.precedingComments.next)); | |
| 815 expect(token.precedingComments.next.next.next, isNull); | |
| 816 } | |
| 817 | |
| 233 void test_comment_multi_lineEnds() { | 818 void test_comment_multi_lineEnds() { |
| 234 String code = r''' | 819 String code = r''' |
| 235 /** | 820 /** |
| 236 * aa | 821 * aa |
| 237 * bbb | 822 * bbb |
| 238 * c | 823 * c |
| 239 */'''; | 824 */'''; |
| 240 _ErrorListener listener = new _ErrorListener(); | 825 _ErrorListener listener = new _ErrorListener(); |
| 241 Scanner scanner = new _TestScanner(new CharSequenceReader(code), listener); | 826 Scanner scanner = new _TestScanner(new CharSequenceReader(code), listener); |
| 242 scanner.tokenize(); | 827 scanner.tokenize(); |
| (...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1142 bool lazyAssignmentOperators: false}) { | 1727 bool lazyAssignmentOperators: false}) { |
| 1143 _ErrorListener listener = new _ErrorListener(); | 1728 _ErrorListener listener = new _ErrorListener(); |
| 1144 Token token = _scanWithListener(source, listener, | 1729 Token token = _scanWithListener(source, listener, |
| 1145 genericMethodComments: genericMethodComments, | 1730 genericMethodComments: genericMethodComments, |
| 1146 lazyAssignmentOperators: lazyAssignmentOperators); | 1731 lazyAssignmentOperators: lazyAssignmentOperators); |
| 1147 listener.assertNoErrors(); | 1732 listener.assertNoErrors(); |
| 1148 return token; | 1733 return token; |
| 1149 } | 1734 } |
| 1150 | 1735 |
| 1151 Token _scanWithListener(String source, _ErrorListener listener, | 1736 Token _scanWithListener(String source, _ErrorListener listener, |
| 1152 {bool genericMethodComments: false, | 1737 {bool genericMethodComments: false, bool lazyAssignmentOperators: false}); |
| 1153 bool lazyAssignmentOperators: false}) { | |
| 1154 Scanner scanner = | |
| 1155 new _TestScanner(new CharSequenceReader(source), listener); | |
| 1156 scanner.scanGenericMethodComments = genericMethodComments; | |
| 1157 scanner.scanLazyAssignmentOperators = lazyAssignmentOperators; | |
| 1158 return scanner.tokenize(); | |
| 1159 } | |
| 1160 } | 1738 } |
| 1161 | 1739 |
| 1162 @reflectiveTest | 1740 @reflectiveTest |
| 1163 class TokenTypeTest { | 1741 class TokenTypeTest { |
| 1164 void test_isOperator() { | 1742 void test_isOperator() { |
| 1165 expect(TokenType.AMPERSAND.isOperator, isTrue); | 1743 expect(TokenType.AMPERSAND.isOperator, isTrue); |
| 1166 expect(TokenType.AMPERSAND_AMPERSAND.isOperator, isTrue); | 1744 expect(TokenType.AMPERSAND_AMPERSAND.isOperator, isTrue); |
| 1167 expect(TokenType.AMPERSAND_EQ.isOperator, isTrue); | 1745 expect(TokenType.AMPERSAND_EQ.isOperator, isTrue); |
| 1168 expect(TokenType.BANG.isOperator, isTrue); | 1746 expect(TokenType.BANG.isOperator, isTrue); |
| 1169 expect(TokenType.BANG_EQ.isOperator, isTrue); | 1747 expect(TokenType.BANG_EQ.isOperator, isTrue); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1289 _TestScanner(CharacterReader reader, [this.listener]) : super(reader); | 1867 _TestScanner(CharacterReader reader, [this.listener]) : super(reader); |
| 1290 | 1868 |
| 1291 @override | 1869 @override |
| 1292 void reportError( | 1870 void reportError( |
| 1293 ScannerErrorCode errorCode, int offset, List<Object> arguments) { | 1871 ScannerErrorCode errorCode, int offset, List<Object> arguments) { |
| 1294 if (listener != null) { | 1872 if (listener != null) { |
| 1295 listener.errors.add(new _TestError(offset, 1, errorCode, arguments)); | 1873 listener.errors.add(new _TestError(offset, 1, errorCode, arguments)); |
| 1296 } | 1874 } |
| 1297 } | 1875 } |
| 1298 } | 1876 } |
| OLD | NEW |