| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 library fasta.scanner.token; | 5 library fasta.scanner.token; |
| 6 | 6 |
| 7 import '../../scanner/token.dart' as analyzer; | 7 import '../../scanner/token.dart' as analyzer; |
| 8 import '../../scanner/token.dart' show TokenType; |
| 8 | 9 |
| 9 import 'precedence.dart' | 10 import 'precedence.dart' |
| 10 show | 11 show AS_INFO, BAD_INPUT_INFO, EOF_INFO, IS_INFO, KEYWORD_INFO; |
| 11 AS_INFO, | |
| 12 BAD_INPUT_INFO, | |
| 13 EOF_INFO, | |
| 14 IS_INFO, | |
| 15 KEYWORD_INFO, | |
| 16 PrecedenceInfo; | |
| 17 | 12 |
| 18 import 'token_constants.dart' show IDENTIFIER_TOKEN; | 13 import 'token_constants.dart' show IDENTIFIER_TOKEN; |
| 19 | 14 |
| 20 import 'string_canonicalizer.dart'; | 15 import 'string_canonicalizer.dart'; |
| 21 | 16 |
| 22 /** | 17 /** |
| 23 * A token that doubles as a linked list. | 18 * A token that doubles as a linked list. |
| 24 */ | 19 */ |
| 25 abstract class Token implements analyzer.TokenWithComment { | 20 abstract class Token implements analyzer.TokenWithComment { |
| 26 /** | 21 /** |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 void set precedingComments(analyzer.CommentToken token) { | 54 void set precedingComments(analyzer.CommentToken token) { |
| 60 precedingCommentTokens = token; | 55 precedingCommentTokens = token; |
| 61 } | 56 } |
| 62 | 57 |
| 63 /** | 58 /** |
| 64 * The precedence info for this token. [info] determines the kind and the | 59 * The precedence info for this token. [info] determines the kind and the |
| 65 * precedence level of this token. | 60 * precedence level of this token. |
| 66 * | 61 * |
| 67 * Defined as getter to save a field in the [KeywordToken] subclass. | 62 * Defined as getter to save a field in the [KeywordToken] subclass. |
| 68 */ | 63 */ |
| 69 PrecedenceInfo get info; | 64 TokenType get info; |
| 70 | 65 |
| 71 /** | 66 /** |
| 72 * The string represented by this token, a substring of the source code. | 67 * The string represented by this token, a substring of the source code. |
| 73 * | 68 * |
| 74 * For [StringToken]s the [lexeme] includes the quotes, explicit escapes, etc. | 69 * For [StringToken]s the [lexeme] includes the quotes, explicit escapes, etc. |
| 75 */ | 70 */ |
| 76 String get lexeme; | 71 String get lexeme; |
| 77 | 72 |
| 78 /** | 73 /** |
| 79 * For symbol and keyword tokens, returns the string value represented by this | 74 * For symbol and keyword tokens, returns the string value represented by this |
| 80 * token. For [StringToken]s this method returns [:null:]. | 75 * token. For [StringToken]s this method returns [:null:]. |
| 81 * | 76 * |
| 82 * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time | 77 * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time |
| 83 * constant originating in the [PrecedenceInfo] or in the [Keyword] instance. | 78 * constant originating in the [TokenType] or in the [Keyword] instance. |
| 84 * This allows testing for keywords and symbols using [:identical:], e.g., | 79 * This allows testing for keywords and symbols using [:identical:], e.g., |
| 85 * [:identical('class', token.value):]. | 80 * [:identical('class', token.value):]. |
| 86 * | 81 * |
| 87 * Note that returning [:null:] for string tokens is important to identify | 82 * Note that returning [:null:] for string tokens is important to identify |
| 88 * symbols and keywords, we cannot use [lexeme] instead. The string literal | 83 * symbols and keywords, we cannot use [lexeme] instead. The string literal |
| 89 * "$a($b" | 84 * "$a($b" |
| 90 * produces ..., SymbolToken($), StringToken(a), StringToken((), ... | 85 * produces ..., SymbolToken($), StringToken(a), StringToken((), ... |
| 91 * | 86 * |
| 92 * After parsing the identifier 'a', the parser tests for a function | 87 * After parsing the identifier 'a', the parser tests for a function |
| 93 * declaration using [:identical(next.stringValue, '('):], which (rightfully) | 88 * declaration using [:identical(next.stringValue, '('):], which (rightfully) |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 | 237 |
| 243 @override | 238 @override |
| 244 Object value() => lexeme; | 239 Object value() => lexeme; |
| 245 } | 240 } |
| 246 | 241 |
| 247 /** | 242 /** |
| 248 * A [SymbolToken] represents the symbol in its precedence info. | 243 * A [SymbolToken] represents the symbol in its precedence info. |
| 249 * Also used for end of file with EOF_INFO. | 244 * Also used for end of file with EOF_INFO. |
| 250 */ | 245 */ |
| 251 class SymbolToken extends Token { | 246 class SymbolToken extends Token { |
| 252 final PrecedenceInfo info; | 247 final TokenType info; |
| 253 | 248 |
| 254 SymbolToken(this.info, int charOffset) : super(charOffset); | 249 SymbolToken(this.info, int charOffset) : super(charOffset); |
| 255 | 250 |
| 256 factory SymbolToken.eof(int charOffset) { | 251 factory SymbolToken.eof(int charOffset) { |
| 257 var eof = new SyntheticSymbolToken(EOF_INFO, charOffset); | 252 var eof = new SyntheticSymbolToken(EOF_INFO, charOffset); |
| 258 // EOF points to itself so there's always infinite look-ahead. | 253 // EOF points to itself so there's always infinite look-ahead. |
| 259 eof.previousToken = eof; | 254 eof.previousToken = eof; |
| 260 eof.next = eof; | 255 eof.next = eof; |
| 261 return eof; | 256 return eof; |
| 262 } | 257 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 282 : new SymbolToken(info, charOffset); | 277 : new SymbolToken(info, charOffset); |
| 283 } | 278 } |
| 284 | 279 |
| 285 /** | 280 /** |
| 286 * A [SyntheticSymbolToken] represents the symbol in its precedence info | 281 * A [SyntheticSymbolToken] represents the symbol in its precedence info |
| 287 * which does not exist in the original source. | 282 * which does not exist in the original source. |
| 288 * For example, if the scanner finds '(' missing a ')' | 283 * For example, if the scanner finds '(' missing a ')' |
| 289 * then it will insert an synthetic ')'. | 284 * then it will insert an synthetic ')'. |
| 290 */ | 285 */ |
| 291 class SyntheticSymbolToken extends SymbolToken { | 286 class SyntheticSymbolToken extends SymbolToken { |
| 292 SyntheticSymbolToken(PrecedenceInfo info, int charOffset) | 287 SyntheticSymbolToken(TokenType info, int charOffset) |
| 293 : super(info, charOffset); | 288 : super(info, charOffset); |
| 294 | 289 |
| 295 @override | 290 @override |
| 296 int get charCount => 0; | 291 int get charCount => 0; |
| 297 | 292 |
| 298 @override | 293 @override |
| 299 bool get isSynthetic => true; | 294 bool get isSynthetic => true; |
| 300 | 295 |
| 301 @override | 296 @override |
| 302 Token copyWithoutComments() => isEof | 297 Token copyWithoutComments() => isEof |
| 303 ? new SymbolToken.eof(charOffset) | 298 ? new SymbolToken.eof(charOffset) |
| 304 : new SyntheticSymbolToken(info, charOffset); | 299 : new SyntheticSymbolToken(info, charOffset); |
| 305 } | 300 } |
| 306 | 301 |
| 307 /** | 302 /** |
| 308 * A [BeginGroupToken] represents a symbol that may be the beginning of | 303 * A [BeginGroupToken] represents a symbol that may be the beginning of |
| 309 * a pair of brackets, i.e., ( { [ < or ${ | 304 * a pair of brackets, i.e., ( { [ < or ${ |
| 310 * The [endGroup] token points to the matching closing bracked in case | 305 * The [endGroup] token points to the matching closing bracked in case |
| 311 * it can be identified during scanning. | 306 * it can be identified during scanning. |
| 312 */ | 307 */ |
| 313 class BeginGroupToken extends SymbolToken | 308 class BeginGroupToken extends SymbolToken |
| 314 implements analyzer.BeginTokenWithComment { | 309 implements analyzer.BeginTokenWithComment { |
| 315 Token endGroup; | 310 Token endGroup; |
| 316 | 311 |
| 317 BeginGroupToken(PrecedenceInfo info, int charOffset) | 312 BeginGroupToken(TokenType info, int charOffset) : super(info, charOffset); |
| 318 : super(info, charOffset); | |
| 319 | 313 |
| 320 @override | 314 @override |
| 321 analyzer.Token get endToken => endGroup; | 315 analyzer.Token get endToken => endGroup; |
| 322 | 316 |
| 323 @override | 317 @override |
| 324 void set endToken(analyzer.Token token) { | 318 void set endToken(analyzer.Token token) { |
| 325 endGroup = token; | 319 endGroup = token; |
| 326 } | 320 } |
| 327 | 321 |
| 328 @override | 322 @override |
| 329 Token copyWithoutComments() => new BeginGroupToken(info, charOffset); | 323 Token copyWithoutComments() => new BeginGroupToken(info, charOffset); |
| 330 } | 324 } |
| 331 | 325 |
| 332 /** | 326 /** |
| 333 * A keyword token. | 327 * A keyword token. |
| 334 */ | 328 */ |
| 335 class KeywordToken extends Token implements analyzer.KeywordTokenWithComment { | 329 class KeywordToken extends Token implements analyzer.KeywordTokenWithComment { |
| 336 final analyzer.Keyword keyword; | 330 final analyzer.Keyword keyword; |
| 337 | 331 |
| 338 KeywordToken(this.keyword, int charOffset) : super(charOffset); | 332 KeywordToken(this.keyword, int charOffset) : super(charOffset); |
| 339 | 333 |
| 340 PrecedenceInfo get info => keyword.info; | 334 TokenType get info => keyword.info; |
| 341 | 335 |
| 342 String get lexeme => keyword.syntax; | 336 String get lexeme => keyword.syntax; |
| 343 | 337 |
| 344 String get stringValue => keyword.syntax; | 338 String get stringValue => keyword.syntax; |
| 345 | 339 |
| 346 bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn; | 340 bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn; |
| 347 | 341 |
| 348 bool get isPseudo => keyword.isPseudo; | 342 bool get isPseudo => keyword.isPseudo; |
| 349 | 343 |
| 350 bool get isBuiltInIdentifier => keyword.isBuiltIn; | 344 bool get isBuiltInIdentifier => keyword.isBuiltIn; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 * | 388 * |
| 395 * For string tokens that are substrings of the program source, the actual | 389 * For string tokens that are substrings of the program source, the actual |
| 396 * substring extraction is performed lazily. This is beneficial because | 390 * substring extraction is performed lazily. This is beneficial because |
| 397 * not all scanned code is actually used. For unused parts, the substrings | 391 * not all scanned code is actually used. For unused parts, the substrings |
| 398 * are never computed and allocated. | 392 * are never computed and allocated. |
| 399 */ | 393 */ |
| 400 static const int LAZY_THRESHOLD = 4; | 394 static const int LAZY_THRESHOLD = 4; |
| 401 | 395 |
| 402 var /* String | LazySubtring */ valueOrLazySubstring; | 396 var /* String | LazySubtring */ valueOrLazySubstring; |
| 403 | 397 |
| 404 final PrecedenceInfo info; | 398 final TokenType info; |
| 405 | 399 |
| 406 /** | 400 /** |
| 407 * Creates a non-lazy string token. If [canonicalize] is true, the string | 401 * Creates a non-lazy string token. If [canonicalize] is true, the string |
| 408 * is canonicalized before the token is created. | 402 * is canonicalized before the token is created. |
| 409 */ | 403 */ |
| 410 StringToken.fromString(this.info, String value, int charOffset, | 404 StringToken.fromString(this.info, String value, int charOffset, |
| 411 {bool canonicalize: false}) | 405 {bool canonicalize: false}) |
| 412 : valueOrLazySubstring = | 406 : valueOrLazySubstring = |
| 413 canonicalizedString(value, 0, value.length, canonicalize), | 407 canonicalizedString(value, 0, value.length, canonicalize), |
| 414 super(charOffset); | 408 super(charOffset); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 | 487 |
| 494 @override | 488 @override |
| 495 String value() => lexeme; | 489 String value() => lexeme; |
| 496 } | 490 } |
| 497 | 491 |
| 498 /** | 492 /** |
| 499 * A String-valued token that does not exist in the original source. | 493 * A String-valued token that does not exist in the original source. |
| 500 */ | 494 */ |
| 501 class SyntheticStringToken extends StringToken | 495 class SyntheticStringToken extends StringToken |
| 502 implements analyzer.SyntheticStringToken { | 496 implements analyzer.SyntheticStringToken { |
| 503 SyntheticStringToken(PrecedenceInfo info, String value, int offset) | 497 SyntheticStringToken(TokenType info, String value, int offset) |
| 504 : super._(info, value, offset); | 498 : super._(info, value, offset); |
| 505 | 499 |
| 506 @override | 500 @override |
| 507 bool get isSynthetic => true; | 501 bool get isSynthetic => true; |
| 508 | 502 |
| 509 @override | 503 @override |
| 510 int get length => 0; | 504 int get length => 0; |
| 511 | 505 |
| 512 @override | 506 @override |
| 513 Token copyWithoutComments() => | 507 Token copyWithoutComments() => |
| 514 new SyntheticStringToken(info, valueOrLazySubstring, offset); | 508 new SyntheticStringToken(info, valueOrLazySubstring, offset); |
| 515 } | 509 } |
| 516 | 510 |
| 517 class CommentToken extends StringToken implements analyzer.CommentToken { | 511 class CommentToken extends StringToken implements analyzer.CommentToken { |
| 518 @override | 512 @override |
| 519 analyzer.TokenWithComment parent; | 513 analyzer.TokenWithComment parent; |
| 520 | 514 |
| 521 /** | 515 /** |
| 522 * Creates a lazy comment token. If [canonicalize] is true, the string | 516 * Creates a lazy comment token. If [canonicalize] is true, the string |
| 523 * is canonicalized before the token is created. | 517 * is canonicalized before the token is created. |
| 524 */ | 518 */ |
| 525 CommentToken.fromSubstring( | 519 CommentToken.fromSubstring( |
| 526 PrecedenceInfo info, String data, int start, int end, int charOffset, | 520 TokenType info, String data, int start, int end, int charOffset, |
| 527 {bool canonicalize: false}) | 521 {bool canonicalize: false}) |
| 528 : super.fromSubstring(info, data, start, end, charOffset, | 522 : super.fromSubstring(info, data, start, end, charOffset, |
| 529 canonicalize: canonicalize); | 523 canonicalize: canonicalize); |
| 530 | 524 |
| 531 /** | 525 /** |
| 532 * Creates a non-lazy comment token. | 526 * Creates a non-lazy comment token. |
| 533 */ | 527 */ |
| 534 CommentToken.fromString(PrecedenceInfo info, String lexeme, int charOffset) | 528 CommentToken.fromString(TokenType info, String lexeme, int charOffset) |
| 535 : super.fromString(info, lexeme, charOffset); | 529 : super.fromString(info, lexeme, charOffset); |
| 536 | 530 |
| 537 /** | 531 /** |
| 538 * Creates a lazy string token. If [asciiOnly] is false, the byte array | 532 * Creates a lazy string token. If [asciiOnly] is false, the byte array |
| 539 * is passed through a UTF-8 decoder. | 533 * is passed through a UTF-8 decoder. |
| 540 */ | 534 */ |
| 541 CommentToken.fromUtf8Bytes(PrecedenceInfo info, List<int> data, int start, | 535 CommentToken.fromUtf8Bytes(TokenType info, List<int> data, int start, int end, |
| 542 int end, bool asciiOnly, int charOffset) | 536 bool asciiOnly, int charOffset) |
| 543 : super.fromUtf8Bytes(info, data, start, end, asciiOnly, charOffset); | 537 : super.fromUtf8Bytes(info, data, start, end, asciiOnly, charOffset); |
| 544 | 538 |
| 545 CommentToken._(PrecedenceInfo info, valueOrLazySubstring, int charOffset) | 539 CommentToken._(TokenType info, valueOrLazySubstring, int charOffset) |
| 546 : super._(info, valueOrLazySubstring, charOffset); | 540 : super._(info, valueOrLazySubstring, charOffset); |
| 547 | 541 |
| 548 @override | 542 @override |
| 549 CommentToken copy() => | 543 CommentToken copy() => |
| 550 new CommentToken._(info, valueOrLazySubstring, charOffset); | 544 new CommentToken._(info, valueOrLazySubstring, charOffset); |
| 551 | 545 |
| 552 @override | 546 @override |
| 553 void remove() { | 547 void remove() { |
| 554 if (previous != null) { | 548 if (previous != null) { |
| 555 previous.setNextWithoutSettingPrevious(next); | 549 previous.setNextWithoutSettingPrevious(next); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 568 * This list will be empty unless this is a documentation comment that has | 562 * This list will be empty unless this is a documentation comment that has |
| 569 * references embedded within it. | 563 * references embedded within it. |
| 570 */ | 564 */ |
| 571 final List<Token> references = <Token>[]; | 565 final List<Token> references = <Token>[]; |
| 572 | 566 |
| 573 /** | 567 /** |
| 574 * Creates a lazy comment token. If [canonicalize] is true, the string | 568 * Creates a lazy comment token. If [canonicalize] is true, the string |
| 575 * is canonicalized before the token is created. | 569 * is canonicalized before the token is created. |
| 576 */ | 570 */ |
| 577 DartDocToken.fromSubstring( | 571 DartDocToken.fromSubstring( |
| 578 PrecedenceInfo info, String data, int start, int end, int charOffset, | 572 TokenType info, String data, int start, int end, int charOffset, |
| 579 {bool canonicalize: false}) | 573 {bool canonicalize: false}) |
| 580 : super.fromSubstring(info, data, start, end, charOffset, | 574 : super.fromSubstring(info, data, start, end, charOffset, |
| 581 canonicalize: canonicalize); | 575 canonicalize: canonicalize); |
| 582 | 576 |
| 583 /** | 577 /** |
| 584 * Creates a lazy string token. If [asciiOnly] is false, the byte array | 578 * Creates a lazy string token. If [asciiOnly] is false, the byte array |
| 585 * is passed through a UTF-8 decoder. | 579 * is passed through a UTF-8 decoder. |
| 586 */ | 580 */ |
| 587 DartDocToken.fromUtf8Bytes(PrecedenceInfo info, List<int> data, int start, | 581 DartDocToken.fromUtf8Bytes(TokenType info, List<int> data, int start, int end, |
| 588 int end, bool asciiOnly, int charOffset) | 582 bool asciiOnly, int charOffset) |
| 589 : super.fromUtf8Bytes(info, data, start, end, asciiOnly, charOffset); | 583 : super.fromUtf8Bytes(info, data, start, end, asciiOnly, charOffset); |
| 590 | 584 |
| 591 DartDocToken._(PrecedenceInfo info, valueOrLazySubstring, int charOffset) | 585 DartDocToken._(TokenType info, valueOrLazySubstring, int charOffset) |
| 592 : super._(info, valueOrLazySubstring, charOffset); | 586 : super._(info, valueOrLazySubstring, charOffset); |
| 593 | 587 |
| 594 @override | 588 @override |
| 595 DartDocToken copy() { | 589 DartDocToken copy() { |
| 596 DartDocToken copy = | 590 DartDocToken copy = |
| 597 new DartDocToken._(info, valueOrLazySubstring, charOffset); | 591 new DartDocToken._(info, valueOrLazySubstring, charOffset); |
| 598 references.forEach((ref) => copy.references.add(ref.copy())); | 592 references.forEach((ref) => copy.references.add(ref.copy())); |
| 599 return copy; | 593 return copy; |
| 600 } | 594 } |
| 601 } | 595 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 identical(value, "<=") || | 683 identical(value, "<=") || |
| 690 identical(value, "<") || | 684 identical(value, "<") || |
| 691 identical(value, "&") || | 685 identical(value, "&") || |
| 692 identical(value, "^") || | 686 identical(value, "^") || |
| 693 identical(value, "|"); | 687 identical(value, "|"); |
| 694 } | 688 } |
| 695 | 689 |
| 696 bool isTernaryOperator(String value) => identical(value, "[]="); | 690 bool isTernaryOperator(String value) => identical(value, "[]="); |
| 697 | 691 |
| 698 bool isMinusOperator(String value) => identical(value, "-"); | 692 bool isMinusOperator(String value) => identical(value, "-"); |
| OLD | NEW |