| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 analyzer.src.generated.scanner; | 5 library analyzer.src.generated.scanner; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'package:analyzer/dart/ast/token.dart'; |
| 8 | 8 import 'package:analyzer/src/dart/ast/token.dart'; |
| 9 import 'package:analyzer/src/generated/error.dart'; | 9 import 'package:analyzer/src/generated/error.dart'; |
| 10 import 'package:analyzer/src/generated/java_engine.dart'; | 10 import 'package:analyzer/src/generated/java_engine.dart'; |
| 11 import 'package:analyzer/src/generated/source.dart'; | 11 import 'package:analyzer/src/generated/source.dart'; |
| 12 | 12 |
| 13 /** | 13 export 'package:analyzer/dart/ast/token.dart'; |
| 14 * The opening half of a grouping pair of tokens. This is used for curly | 14 export 'package:analyzer/src/dart/ast/token.dart' hide SimpleToken; |
| 15 * brackets ('{'), parentheses ('('), and square brackets ('['). | |
| 16 */ | |
| 17 class BeginToken extends Token { | |
| 18 /** | |
| 19 * The token that corresponds to this token. | |
| 20 */ | |
| 21 Token endToken; | |
| 22 | |
| 23 /** | |
| 24 * Initialize a newly created token to have the given [type] at the given | |
| 25 * [offset]. | |
| 26 */ | |
| 27 BeginToken(TokenType type, int offset) : super(type, offset) { | |
| 28 assert(type == TokenType.OPEN_CURLY_BRACKET || | |
| 29 type == TokenType.OPEN_PAREN || | |
| 30 type == TokenType.OPEN_SQUARE_BRACKET || | |
| 31 type == TokenType.STRING_INTERPOLATION_EXPRESSION); | |
| 32 } | |
| 33 | |
| 34 @override | |
| 35 Token copy() => new BeginToken(type, offset); | |
| 36 } | |
| 37 | |
| 38 /** | |
| 39 * A begin token that is preceded by comments. | |
| 40 */ | |
| 41 class BeginTokenWithComment extends BeginToken { | |
| 42 /** | |
| 43 * The first comment in the list of comments that precede this token. | |
| 44 */ | |
| 45 CommentToken _precedingComment; | |
| 46 | |
| 47 /** | |
| 48 * Initialize a newly created token to have the given [type] at the given | |
| 49 * [offset] and to be preceded by the comments reachable from the given | |
| 50 * [comment]. | |
| 51 */ | |
| 52 BeginTokenWithComment(TokenType type, int offset, this._precedingComment) | |
| 53 : super(type, offset) { | |
| 54 _setCommentParent(_precedingComment); | |
| 55 } | |
| 56 | |
| 57 CommentToken get precedingComments => _precedingComment; | |
| 58 | |
| 59 void set precedingComments(CommentToken comment) { | |
| 60 _precedingComment = comment; | |
| 61 _setCommentParent(_precedingComment); | |
| 62 } | |
| 63 | |
| 64 @override | |
| 65 void applyDelta(int delta) { | |
| 66 super.applyDelta(delta); | |
| 67 Token token = precedingComments; | |
| 68 while (token != null) { | |
| 69 token.applyDelta(delta); | |
| 70 token = token.next; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 @override | |
| 75 Token copy() => | |
| 76 new BeginTokenWithComment(type, offset, copyComments(precedingComments)); | |
| 77 } | |
| 78 | 15 |
| 79 /** | 16 /** |
| 80 * A [CharacterReader] that reads a range of characters from another character | 17 * A [CharacterReader] that reads a range of characters from another character |
| 81 * reader. | 18 * reader. |
| 82 */ | 19 */ |
| 83 class CharacterRangeReader extends CharacterReader { | 20 class CharacterRangeReader extends CharacterReader { |
| 84 /** | 21 /** |
| 85 * The reader from which the characters are actually being read. | 22 * The reader from which the characters are actually being read. |
| 86 */ | 23 */ |
| 87 final CharacterReader baseReader; | 24 final CharacterReader baseReader; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 @override | 157 @override |
| 221 int peek() { | 158 int peek() { |
| 222 if (_charOffset + 1 >= _stringLength) { | 159 if (_charOffset + 1 >= _stringLength) { |
| 223 return -1; | 160 return -1; |
| 224 } | 161 } |
| 225 return _sequence.codeUnitAt(_charOffset + 1); | 162 return _sequence.codeUnitAt(_charOffset + 1); |
| 226 } | 163 } |
| 227 } | 164 } |
| 228 | 165 |
| 229 /** | 166 /** |
| 230 * A token representing a comment. | |
| 231 */ | |
| 232 class CommentToken extends StringToken { | |
| 233 /** | |
| 234 * The [Token] that contains this comment. | |
| 235 */ | |
| 236 Token parent; | |
| 237 | |
| 238 /** | |
| 239 * Initialize a newly created token to represent a token of the given [type] | |
| 240 * with the given [value] at the given [offset]. | |
| 241 */ | |
| 242 CommentToken(TokenType type, String value, int offset) | |
| 243 : super(type, value, offset); | |
| 244 | |
| 245 @override | |
| 246 CommentToken copy() => new CommentToken(type, _value, offset); | |
| 247 } | |
| 248 | |
| 249 /** | |
| 250 * A documentation comment token. | |
| 251 */ | |
| 252 class DocumentationCommentToken extends CommentToken { | |
| 253 /** | |
| 254 * The references embedded within the documentation comment. | |
| 255 * This list will be empty unless this is a documentation comment that has | |
| 256 * references embedded within it. | |
| 257 */ | |
| 258 final List<Token> references = <Token>[]; | |
| 259 | |
| 260 /** | |
| 261 * Initialize a newly created token to represent a token of the given [type] | |
| 262 * with the given [value] at the given [offset]. | |
| 263 */ | |
| 264 DocumentationCommentToken(TokenType type, String value, int offset) | |
| 265 : super(type, value, offset); | |
| 266 | |
| 267 @override | |
| 268 CommentToken copy() { | |
| 269 DocumentationCommentToken copy = | |
| 270 new DocumentationCommentToken(type, _value, offset); | |
| 271 references.forEach((ref) => copy.references.add(ref.copy())); | |
| 272 return copy; | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 /** | |
| 277 * The keywords in the Dart programming language. | |
| 278 */ | |
| 279 class Keyword { | |
| 280 static const Keyword ASSERT = const Keyword('ASSERT', "assert"); | |
| 281 | |
| 282 static const Keyword BREAK = const Keyword('BREAK', "break"); | |
| 283 | |
| 284 static const Keyword CASE = const Keyword('CASE', "case"); | |
| 285 | |
| 286 static const Keyword CATCH = const Keyword('CATCH', "catch"); | |
| 287 | |
| 288 static const Keyword CLASS = const Keyword('CLASS', "class"); | |
| 289 | |
| 290 static const Keyword CONST = const Keyword('CONST', "const"); | |
| 291 | |
| 292 static const Keyword CONTINUE = const Keyword('CONTINUE', "continue"); | |
| 293 | |
| 294 static const Keyword DEFAULT = const Keyword('DEFAULT', "default"); | |
| 295 | |
| 296 static const Keyword DO = const Keyword('DO', "do"); | |
| 297 | |
| 298 static const Keyword ELSE = const Keyword('ELSE', "else"); | |
| 299 | |
| 300 static const Keyword ENUM = const Keyword('ENUM', "enum"); | |
| 301 | |
| 302 static const Keyword EXTENDS = const Keyword('EXTENDS', "extends"); | |
| 303 | |
| 304 static const Keyword FALSE = const Keyword('FALSE', "false"); | |
| 305 | |
| 306 static const Keyword FINAL = const Keyword('FINAL', "final"); | |
| 307 | |
| 308 static const Keyword FINALLY = const Keyword('FINALLY', "finally"); | |
| 309 | |
| 310 static const Keyword FOR = const Keyword('FOR', "for"); | |
| 311 | |
| 312 static const Keyword IF = const Keyword('IF', "if"); | |
| 313 | |
| 314 static const Keyword IN = const Keyword('IN', "in"); | |
| 315 | |
| 316 static const Keyword IS = const Keyword('IS', "is"); | |
| 317 | |
| 318 static const Keyword NEW = const Keyword('NEW', "new"); | |
| 319 | |
| 320 static const Keyword NULL = const Keyword('NULL', "null"); | |
| 321 | |
| 322 static const Keyword RETHROW = const Keyword('RETHROW', "rethrow"); | |
| 323 | |
| 324 static const Keyword RETURN = const Keyword('RETURN', "return"); | |
| 325 | |
| 326 static const Keyword SUPER = const Keyword('SUPER', "super"); | |
| 327 | |
| 328 static const Keyword SWITCH = const Keyword('SWITCH', "switch"); | |
| 329 | |
| 330 static const Keyword THIS = const Keyword('THIS', "this"); | |
| 331 | |
| 332 static const Keyword THROW = const Keyword('THROW', "throw"); | |
| 333 | |
| 334 static const Keyword TRUE = const Keyword('TRUE', "true"); | |
| 335 | |
| 336 static const Keyword TRY = const Keyword('TRY', "try"); | |
| 337 | |
| 338 static const Keyword VAR = const Keyword('VAR', "var"); | |
| 339 | |
| 340 static const Keyword VOID = const Keyword('VOID', "void"); | |
| 341 | |
| 342 static const Keyword WHILE = const Keyword('WHILE', "while"); | |
| 343 | |
| 344 static const Keyword WITH = const Keyword('WITH', "with"); | |
| 345 | |
| 346 static const Keyword ABSTRACT = const Keyword('ABSTRACT', "abstract", true); | |
| 347 | |
| 348 static const Keyword AS = const Keyword('AS', "as", true); | |
| 349 | |
| 350 static const Keyword DEFERRED = const Keyword('DEFERRED', "deferred", true); | |
| 351 | |
| 352 static const Keyword DYNAMIC = const Keyword('DYNAMIC', "dynamic", true); | |
| 353 | |
| 354 static const Keyword EXPORT = const Keyword('EXPORT', "export", true); | |
| 355 | |
| 356 static const Keyword EXTERNAL = const Keyword('EXTERNAL', "external", true); | |
| 357 | |
| 358 static const Keyword FACTORY = const Keyword('FACTORY', "factory", true); | |
| 359 | |
| 360 static const Keyword GET = const Keyword('GET', "get", true); | |
| 361 | |
| 362 static const Keyword IMPLEMENTS = | |
| 363 const Keyword('IMPLEMENTS', "implements", true); | |
| 364 | |
| 365 static const Keyword IMPORT = const Keyword('IMPORT', "import", true); | |
| 366 | |
| 367 static const Keyword LIBRARY = const Keyword('LIBRARY', "library", true); | |
| 368 | |
| 369 static const Keyword OPERATOR = const Keyword('OPERATOR', "operator", true); | |
| 370 | |
| 371 static const Keyword PART = const Keyword('PART', "part", true); | |
| 372 | |
| 373 static const Keyword SET = const Keyword('SET', "set", true); | |
| 374 | |
| 375 static const Keyword STATIC = const Keyword('STATIC', "static", true); | |
| 376 | |
| 377 static const Keyword TYPEDEF = const Keyword('TYPEDEF', "typedef", true); | |
| 378 | |
| 379 static const List<Keyword> values = const [ | |
| 380 ASSERT, | |
| 381 BREAK, | |
| 382 CASE, | |
| 383 CATCH, | |
| 384 CLASS, | |
| 385 CONST, | |
| 386 CONTINUE, | |
| 387 DEFAULT, | |
| 388 DO, | |
| 389 ELSE, | |
| 390 ENUM, | |
| 391 EXTENDS, | |
| 392 FALSE, | |
| 393 FINAL, | |
| 394 FINALLY, | |
| 395 FOR, | |
| 396 IF, | |
| 397 IN, | |
| 398 IS, | |
| 399 NEW, | |
| 400 NULL, | |
| 401 RETHROW, | |
| 402 RETURN, | |
| 403 SUPER, | |
| 404 SWITCH, | |
| 405 THIS, | |
| 406 THROW, | |
| 407 TRUE, | |
| 408 TRY, | |
| 409 VAR, | |
| 410 VOID, | |
| 411 WHILE, | |
| 412 WITH, | |
| 413 ABSTRACT, | |
| 414 AS, | |
| 415 DEFERRED, | |
| 416 DYNAMIC, | |
| 417 EXPORT, | |
| 418 EXTERNAL, | |
| 419 FACTORY, | |
| 420 GET, | |
| 421 IMPLEMENTS, | |
| 422 IMPORT, | |
| 423 LIBRARY, | |
| 424 OPERATOR, | |
| 425 PART, | |
| 426 SET, | |
| 427 STATIC, | |
| 428 TYPEDEF | |
| 429 ]; | |
| 430 | |
| 431 /** | |
| 432 * A table mapping the lexemes of keywords to the corresponding keyword. | |
| 433 */ | |
| 434 static final Map<String, Keyword> keywords = _createKeywordMap(); | |
| 435 | |
| 436 /** | |
| 437 * The name of the keyword type. | |
| 438 */ | |
| 439 final String name; | |
| 440 | |
| 441 /** | |
| 442 * The lexeme for the keyword. | |
| 443 */ | |
| 444 final String syntax; | |
| 445 | |
| 446 /** | |
| 447 * A flag indicating whether the keyword is a pseudo-keyword. Pseudo keywords | |
| 448 * can be used as identifiers. | |
| 449 */ | |
| 450 final bool isPseudoKeyword; | |
| 451 | |
| 452 /** | |
| 453 * Initialize a newly created keyword to have the given [name] and [syntax]. | |
| 454 * The keyword is a pseudo-keyword if the [isPseudoKeyword] flag is `true`. | |
| 455 */ | |
| 456 const Keyword(this.name, this.syntax, [this.isPseudoKeyword = false]); | |
| 457 | |
| 458 @override | |
| 459 String toString() => name; | |
| 460 | |
| 461 /** | |
| 462 * Create a table mapping the lexemes of keywords to the corresponding keyword | |
| 463 * and return the table that was created. | |
| 464 */ | |
| 465 static Map<String, Keyword> _createKeywordMap() { | |
| 466 LinkedHashMap<String, Keyword> result = | |
| 467 new LinkedHashMap<String, Keyword>(); | |
| 468 for (Keyword keyword in values) { | |
| 469 result[keyword.syntax] = keyword; | |
| 470 } | |
| 471 return result; | |
| 472 } | |
| 473 } | |
| 474 | |
| 475 /** | |
| 476 * A state in a state machine used to scan keywords. | 167 * A state in a state machine used to scan keywords. |
| 477 */ | 168 */ |
| 478 class KeywordState { | 169 class KeywordState { |
| 479 /** | 170 /** |
| 480 * An empty transition table used by leaf states. | 171 * An empty transition table used by leaf states. |
| 481 */ | 172 */ |
| 482 static List<KeywordState> _EMPTY_TABLE = new List<KeywordState>(26); | 173 static List<KeywordState> _EMPTY_TABLE = new List<KeywordState>(26); |
| 483 | 174 |
| 484 /** | 175 /** |
| 485 * The initial state in the state machine. | 176 * The initial state in the state machine. |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 List<String> strings = new List<String>(values.length); | 263 List<String> strings = new List<String>(values.length); |
| 573 for (int i = 0; i < values.length; i++) { | 264 for (int i = 0; i < values.length; i++) { |
| 574 strings[i] = values[i].syntax; | 265 strings[i] = values[i].syntax; |
| 575 } | 266 } |
| 576 strings.sort(); | 267 strings.sort(); |
| 577 return _computeKeywordStateTable(0, strings, 0, strings.length); | 268 return _computeKeywordStateTable(0, strings, 0, strings.length); |
| 578 } | 269 } |
| 579 } | 270 } |
| 580 | 271 |
| 581 /** | 272 /** |
| 582 * A token representing a keyword in the language. | |
| 583 */ | |
| 584 class KeywordToken extends Token { | |
| 585 /** | |
| 586 * The keyword being represented by this token. | |
| 587 */ | |
| 588 final Keyword keyword; | |
| 589 | |
| 590 /** | |
| 591 * Initialize a newly created token to represent the given [keyword] at the | |
| 592 * given [offset]. | |
| 593 */ | |
| 594 KeywordToken(this.keyword, int offset) : super(TokenType.KEYWORD, offset); | |
| 595 | |
| 596 @override | |
| 597 String get lexeme => keyword.syntax; | |
| 598 | |
| 599 @override | |
| 600 Token copy() => new KeywordToken(keyword, offset); | |
| 601 | |
| 602 @override | |
| 603 Keyword value() => keyword; | |
| 604 } | |
| 605 | |
| 606 /** | |
| 607 * A keyword token that is preceded by comments. | |
| 608 */ | |
| 609 class KeywordTokenWithComment extends KeywordToken { | |
| 610 /** | |
| 611 * The first comment in the list of comments that precede this token. | |
| 612 */ | |
| 613 CommentToken _precedingComment; | |
| 614 | |
| 615 /** | |
| 616 * Initialize a newly created token to to represent the given [keyword] at the | |
| 617 * given [offset] and to be preceded by the comments reachable from the given | |
| 618 * [comment]. | |
| 619 */ | |
| 620 KeywordTokenWithComment(Keyword keyword, int offset, this._precedingComment) | |
| 621 : super(keyword, offset) { | |
| 622 _setCommentParent(_precedingComment); | |
| 623 } | |
| 624 | |
| 625 CommentToken get precedingComments => _precedingComment; | |
| 626 | |
| 627 void set precedingComments(CommentToken comment) { | |
| 628 _precedingComment = comment; | |
| 629 _setCommentParent(_precedingComment); | |
| 630 } | |
| 631 | |
| 632 @override | |
| 633 void applyDelta(int delta) { | |
| 634 super.applyDelta(delta); | |
| 635 Token token = precedingComments; | |
| 636 while (token != null) { | |
| 637 token.applyDelta(delta); | |
| 638 token = token.next; | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 @override | |
| 643 Token copy() => new KeywordTokenWithComment( | |
| 644 keyword, offset, copyComments(precedingComments)); | |
| 645 } | |
| 646 | |
| 647 /** | |
| 648 * The class `Scanner` implements a scanner for Dart code. | 273 * The class `Scanner` implements a scanner for Dart code. |
| 649 * | 274 * |
| 650 * The lexical structure of Dart is ambiguous without knowledge of the context | 275 * The lexical structure of Dart is ambiguous without knowledge of the context |
| 651 * in which a token is being scanned. For example, without context we cannot | 276 * in which a token is being scanned. For example, without context we cannot |
| 652 * determine whether source of the form "<<" should be scanned as a single | 277 * determine whether source of the form "<<" should be scanned as a single |
| 653 * left-shift operator or as two left angle brackets. This scanner does not have | 278 * left-shift operator or as two left angle brackets. This scanner does not have |
| 654 * any context, so it always resolves such conflicts by scanning the longest | 279 * any context, so it always resolves such conflicts by scanning the longest |
| 655 * possible token. | 280 * possible token. |
| 656 */ | 281 */ |
| 657 class Scanner { | 282 class Scanner { |
| (...skipping 1237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1895 : super(name, message, correction); | 1520 : super(name, message, correction); |
| 1896 | 1521 |
| 1897 @override | 1522 @override |
| 1898 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; | 1523 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; |
| 1899 | 1524 |
| 1900 @override | 1525 @override |
| 1901 ErrorType get type => ErrorType.SYNTACTIC_ERROR; | 1526 ErrorType get type => ErrorType.SYNTACTIC_ERROR; |
| 1902 } | 1527 } |
| 1903 | 1528 |
| 1904 /** | 1529 /** |
| 1905 * A token whose value is independent of it's type. | |
| 1906 */ | |
| 1907 class StringToken extends Token { | |
| 1908 /** | |
| 1909 * The lexeme represented by this token. | |
| 1910 */ | |
| 1911 String _value; | |
| 1912 | |
| 1913 /** | |
| 1914 * Initialize a newly created token to represent a token of the given [type] | |
| 1915 * with the given [value] at the given [offset]. | |
| 1916 */ | |
| 1917 StringToken(TokenType type, String value, int offset) : super(type, offset) { | |
| 1918 this._value = StringUtilities.intern(value); | |
| 1919 } | |
| 1920 | |
| 1921 @override | |
| 1922 String get lexeme => _value; | |
| 1923 | |
| 1924 @override | |
| 1925 Token copy() => new StringToken(type, _value, offset); | |
| 1926 | |
| 1927 @override | |
| 1928 String value() => _value; | |
| 1929 } | |
| 1930 | |
| 1931 /** | |
| 1932 * A string token that is preceded by comments. | |
| 1933 */ | |
| 1934 class StringTokenWithComment extends StringToken { | |
| 1935 /** | |
| 1936 * The first comment in the list of comments that precede this token. | |
| 1937 */ | |
| 1938 CommentToken _precedingComment; | |
| 1939 | |
| 1940 /** | |
| 1941 * Initialize a newly created token to have the given [type] at the given | |
| 1942 * [offset] and to be preceded by the comments reachable from the given | |
| 1943 * [comment]. | |
| 1944 */ | |
| 1945 StringTokenWithComment( | |
| 1946 TokenType type, String value, int offset, this._precedingComment) | |
| 1947 : super(type, value, offset) { | |
| 1948 _setCommentParent(_precedingComment); | |
| 1949 } | |
| 1950 | |
| 1951 CommentToken get precedingComments => _precedingComment; | |
| 1952 | |
| 1953 void set precedingComments(CommentToken comment) { | |
| 1954 _precedingComment = comment; | |
| 1955 _setCommentParent(_precedingComment); | |
| 1956 } | |
| 1957 | |
| 1958 @override | |
| 1959 void applyDelta(int delta) { | |
| 1960 super.applyDelta(delta); | |
| 1961 Token token = precedingComments; | |
| 1962 while (token != null) { | |
| 1963 token.applyDelta(delta); | |
| 1964 token = token.next; | |
| 1965 } | |
| 1966 } | |
| 1967 | |
| 1968 @override | |
| 1969 Token copy() => new StringTokenWithComment( | |
| 1970 type, lexeme, offset, copyComments(precedingComments)); | |
| 1971 } | |
| 1972 | |
| 1973 /** | |
| 1974 * A [CharacterReader] that reads characters from a character sequence, but adds | 1530 * A [CharacterReader] that reads characters from a character sequence, but adds |
| 1975 * a delta when reporting the current character offset so that the character | 1531 * a delta when reporting the current character offset so that the character |
| 1976 * sequence can be a subsequence from a larger sequence. | 1532 * sequence can be a subsequence from a larger sequence. |
| 1977 */ | 1533 */ |
| 1978 class SubSequenceReader extends CharSequenceReader { | 1534 class SubSequenceReader extends CharSequenceReader { |
| 1979 /** | 1535 /** |
| 1980 * The offset from the beginning of the file to the beginning of the source | 1536 * The offset from the beginning of the file to the beginning of the source |
| 1981 * being scanned. | 1537 * being scanned. |
| 1982 */ | 1538 */ |
| 1983 final int _offsetDelta; | 1539 final int _offsetDelta; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1994 | 1550 |
| 1995 @override | 1551 @override |
| 1996 void set offset(int offset) { | 1552 void set offset(int offset) { |
| 1997 super.offset = offset - _offsetDelta; | 1553 super.offset = offset - _offsetDelta; |
| 1998 } | 1554 } |
| 1999 | 1555 |
| 2000 @override | 1556 @override |
| 2001 String getString(int start, int endDelta) => | 1557 String getString(int start, int endDelta) => |
| 2002 super.getString(start - _offsetDelta, endDelta); | 1558 super.getString(start - _offsetDelta, endDelta); |
| 2003 } | 1559 } |
| 2004 | |
| 2005 /** | |
| 2006 * A token whose value is independent of it's type. | |
| 2007 */ | |
| 2008 class SyntheticStringToken extends StringToken { | |
| 2009 /** | |
| 2010 * Initialize a newly created token to represent a token of the given [type] | |
| 2011 * with the given [value] at the given [offset]. | |
| 2012 */ | |
| 2013 SyntheticStringToken(TokenType type, String value, int offset) | |
| 2014 : super(type, value, offset); | |
| 2015 | |
| 2016 @override | |
| 2017 bool get isSynthetic => true; | |
| 2018 } | |
| 2019 | |
| 2020 /** | |
| 2021 * A token that was scanned from the input. Each token knows which tokens | |
| 2022 * precede and follow it, acting as a link in a doubly linked list of tokens. | |
| 2023 */ | |
| 2024 class Token { | |
| 2025 /** | |
| 2026 * The type of the token. | |
| 2027 */ | |
| 2028 final TokenType type; | |
| 2029 | |
| 2030 /** | |
| 2031 * The offset from the beginning of the file to the first character in the | |
| 2032 * token. | |
| 2033 */ | |
| 2034 int offset = 0; | |
| 2035 | |
| 2036 /** | |
| 2037 * The previous token in the token stream. | |
| 2038 */ | |
| 2039 Token previous; | |
| 2040 | |
| 2041 /** | |
| 2042 * The next token in the token stream. | |
| 2043 */ | |
| 2044 Token _next; | |
| 2045 | |
| 2046 /** | |
| 2047 * Initialize a newly created token to have the given [type] and [offset]. | |
| 2048 */ | |
| 2049 Token(this.type, this.offset); | |
| 2050 | |
| 2051 /** | |
| 2052 * Return the offset from the beginning of the file to the character after the | |
| 2053 * last character of the token. | |
| 2054 */ | |
| 2055 int get end => offset + length; | |
| 2056 | |
| 2057 /** | |
| 2058 * Return `true` if this token represents an operator. | |
| 2059 */ | |
| 2060 bool get isOperator => type.isOperator; | |
| 2061 | |
| 2062 /** | |
| 2063 * Return `true` if this token is a synthetic token. A synthetic token is a | |
| 2064 * token that was introduced by the parser in order to recover from an error | |
| 2065 * in the code. | |
| 2066 */ | |
| 2067 bool get isSynthetic => length == 0; | |
| 2068 | |
| 2069 /** | |
| 2070 * Return `true` if this token represents an operator that can be defined by | |
| 2071 * users. | |
| 2072 */ | |
| 2073 bool get isUserDefinableOperator => type.isUserDefinableOperator; | |
| 2074 | |
| 2075 /** | |
| 2076 * Return the number of characters in the node's source range. | |
| 2077 */ | |
| 2078 int get length => lexeme.length; | |
| 2079 | |
| 2080 /** | |
| 2081 * Return the lexeme that represents this token. | |
| 2082 */ | |
| 2083 String get lexeme => type.lexeme; | |
| 2084 | |
| 2085 /** | |
| 2086 * Return the next token in the token stream. | |
| 2087 */ | |
| 2088 Token get next => _next; | |
| 2089 | |
| 2090 /** | |
| 2091 * Return the first comment in the list of comments that precede this token, | |
| 2092 * or `null` if there are no comments preceding this token. Additional | |
| 2093 * comments can be reached by following the token stream using [next] until | |
| 2094 * `null` is returned. | |
| 2095 * | |
| 2096 * For example, if the original contents were `/* one */ /* two */ id`, then | |
| 2097 * the first preceding comment token will have a lexeme of `/* one */` and | |
| 2098 * the next comment token will have a lexeme of `/* two */`. | |
| 2099 */ | |
| 2100 CommentToken get precedingComments => null; | |
| 2101 | |
| 2102 /** | |
| 2103 * Apply (add) the given [delta] to this token's offset. | |
| 2104 */ | |
| 2105 void applyDelta(int delta) { | |
| 2106 offset += delta; | |
| 2107 } | |
| 2108 | |
| 2109 /** | |
| 2110 * Return a newly created token that is a copy of this token but that is not a | |
| 2111 * part of any token stream. | |
| 2112 */ | |
| 2113 Token copy() => new Token(type, offset); | |
| 2114 | |
| 2115 /** | |
| 2116 * Copy a linked list of comment tokens identical to the given comment tokens. | |
| 2117 */ | |
| 2118 Token copyComments(Token token) { | |
| 2119 if (token == null) { | |
| 2120 return null; | |
| 2121 } | |
| 2122 Token head = token.copy(); | |
| 2123 Token tail = head; | |
| 2124 token = token.next; | |
| 2125 while (token != null) { | |
| 2126 tail = tail.setNext(token.copy()); | |
| 2127 token = token.next; | |
| 2128 } | |
| 2129 return head; | |
| 2130 } | |
| 2131 | |
| 2132 /** | |
| 2133 * Return `true` if this token has any one of the given [types]. | |
| 2134 */ | |
| 2135 bool matchesAny(List<TokenType> types) { | |
| 2136 for (TokenType type in types) { | |
| 2137 if (this.type == type) { | |
| 2138 return true; | |
| 2139 } | |
| 2140 } | |
| 2141 return false; | |
| 2142 } | |
| 2143 | |
| 2144 /** | |
| 2145 * Set the next token in the token stream to the given [token]. This has the | |
| 2146 * side-effect of setting this token to be the previous token for the given | |
| 2147 * token. Return the token that was passed in. | |
| 2148 */ | |
| 2149 Token setNext(Token token) { | |
| 2150 _next = token; | |
| 2151 token.previous = this; | |
| 2152 return token; | |
| 2153 } | |
| 2154 | |
| 2155 /** | |
| 2156 * Set the next token in the token stream to the given token without changing | |
| 2157 * which token is the previous token for the given token. Return the token | |
| 2158 * that was passed in. | |
| 2159 */ | |
| 2160 Token setNextWithoutSettingPrevious(Token token) { | |
| 2161 _next = token; | |
| 2162 return token; | |
| 2163 } | |
| 2164 | |
| 2165 @override | |
| 2166 String toString() => lexeme; | |
| 2167 | |
| 2168 /** | |
| 2169 * Return the value of this token. For keyword tokens, this is the keyword | |
| 2170 * associated with the token, for other tokens it is the lexeme associated | |
| 2171 * with the token. | |
| 2172 */ | |
| 2173 Object value() => type.lexeme; | |
| 2174 | |
| 2175 /** | |
| 2176 * Sets the `parent` property to `this` for the given [comment] and all the | |
| 2177 * next tokens. | |
| 2178 */ | |
| 2179 void _setCommentParent(CommentToken comment) { | |
| 2180 while (comment != null) { | |
| 2181 comment.parent = this; | |
| 2182 comment = comment.next; | |
| 2183 } | |
| 2184 } | |
| 2185 | |
| 2186 /** | |
| 2187 * Compare the given [tokens] to find the token that appears first in the | |
| 2188 * source being parsed. That is, return the left-most of all of the tokens. | |
| 2189 * The list must be non-`null`, but the elements of the list are allowed to be | |
| 2190 * `null`. Return the token with the smallest offset, or `null` if the list is | |
| 2191 * empty or if all of the elements of the list are `null`. | |
| 2192 */ | |
| 2193 static Token lexicallyFirst(List<Token> tokens) { | |
| 2194 Token first = null; | |
| 2195 int offset = -1; | |
| 2196 for (Token token in tokens) { | |
| 2197 if (token != null && (offset < 0 || token.offset < offset)) { | |
| 2198 first = token; | |
| 2199 offset = token.offset; | |
| 2200 } | |
| 2201 } | |
| 2202 return first; | |
| 2203 } | |
| 2204 } | |
| 2205 | |
| 2206 /** | |
| 2207 * The classes (or groups) of tokens with a similar use. | |
| 2208 */ | |
| 2209 class TokenClass { | |
| 2210 /** | |
| 2211 * A value used to indicate that the token type is not part of any specific | |
| 2212 * class of token. | |
| 2213 */ | |
| 2214 static const TokenClass NO_CLASS = const TokenClass('NO_CLASS'); | |
| 2215 | |
| 2216 /** | |
| 2217 * A value used to indicate that the token type is an additive operator. | |
| 2218 */ | |
| 2219 static const TokenClass ADDITIVE_OPERATOR = | |
| 2220 const TokenClass('ADDITIVE_OPERATOR', 13); | |
| 2221 | |
| 2222 /** | |
| 2223 * A value used to indicate that the token type is an assignment operator. | |
| 2224 */ | |
| 2225 static const TokenClass ASSIGNMENT_OPERATOR = | |
| 2226 const TokenClass('ASSIGNMENT_OPERATOR', 1); | |
| 2227 | |
| 2228 /** | |
| 2229 * A value used to indicate that the token type is a bitwise-and operator. | |
| 2230 */ | |
| 2231 static const TokenClass BITWISE_AND_OPERATOR = | |
| 2232 const TokenClass('BITWISE_AND_OPERATOR', 11); | |
| 2233 | |
| 2234 /** | |
| 2235 * A value used to indicate that the token type is a bitwise-or operator. | |
| 2236 */ | |
| 2237 static const TokenClass BITWISE_OR_OPERATOR = | |
| 2238 const TokenClass('BITWISE_OR_OPERATOR', 9); | |
| 2239 | |
| 2240 /** | |
| 2241 * A value used to indicate that the token type is a bitwise-xor operator. | |
| 2242 */ | |
| 2243 static const TokenClass BITWISE_XOR_OPERATOR = | |
| 2244 const TokenClass('BITWISE_XOR_OPERATOR', 10); | |
| 2245 | |
| 2246 /** | |
| 2247 * A value used to indicate that the token type is a cascade operator. | |
| 2248 */ | |
| 2249 static const TokenClass CASCADE_OPERATOR = | |
| 2250 const TokenClass('CASCADE_OPERATOR', 2); | |
| 2251 | |
| 2252 /** | |
| 2253 * A value used to indicate that the token type is a conditional operator. | |
| 2254 */ | |
| 2255 static const TokenClass CONDITIONAL_OPERATOR = | |
| 2256 const TokenClass('CONDITIONAL_OPERATOR', 3); | |
| 2257 | |
| 2258 /** | |
| 2259 * A value used to indicate that the token type is an equality operator. | |
| 2260 */ | |
| 2261 static const TokenClass EQUALITY_OPERATOR = | |
| 2262 const TokenClass('EQUALITY_OPERATOR', 7); | |
| 2263 | |
| 2264 /** | |
| 2265 * A value used to indicate that the token type is an if-null operator. | |
| 2266 */ | |
| 2267 static const TokenClass IF_NULL_OPERATOR = | |
| 2268 const TokenClass('IF_NULL_OPERATOR', 4); | |
| 2269 | |
| 2270 /** | |
| 2271 * A value used to indicate that the token type is a logical-and operator. | |
| 2272 */ | |
| 2273 static const TokenClass LOGICAL_AND_OPERATOR = | |
| 2274 const TokenClass('LOGICAL_AND_OPERATOR', 6); | |
| 2275 | |
| 2276 /** | |
| 2277 * A value used to indicate that the token type is a logical-or operator. | |
| 2278 */ | |
| 2279 static const TokenClass LOGICAL_OR_OPERATOR = | |
| 2280 const TokenClass('LOGICAL_OR_OPERATOR', 5); | |
| 2281 | |
| 2282 /** | |
| 2283 * A value used to indicate that the token type is a multiplicative operator. | |
| 2284 */ | |
| 2285 static const TokenClass MULTIPLICATIVE_OPERATOR = | |
| 2286 const TokenClass('MULTIPLICATIVE_OPERATOR', 14); | |
| 2287 | |
| 2288 /** | |
| 2289 * A value used to indicate that the token type is a relational operator. | |
| 2290 */ | |
| 2291 static const TokenClass RELATIONAL_OPERATOR = | |
| 2292 const TokenClass('RELATIONAL_OPERATOR', 8); | |
| 2293 | |
| 2294 /** | |
| 2295 * A value used to indicate that the token type is a shift operator. | |
| 2296 */ | |
| 2297 static const TokenClass SHIFT_OPERATOR = | |
| 2298 const TokenClass('SHIFT_OPERATOR', 12); | |
| 2299 | |
| 2300 /** | |
| 2301 * A value used to indicate that the token type is a unary operator. | |
| 2302 */ | |
| 2303 static const TokenClass UNARY_POSTFIX_OPERATOR = | |
| 2304 const TokenClass('UNARY_POSTFIX_OPERATOR', 16); | |
| 2305 | |
| 2306 /** | |
| 2307 * A value used to indicate that the token type is a unary operator. | |
| 2308 */ | |
| 2309 static const TokenClass UNARY_PREFIX_OPERATOR = | |
| 2310 const TokenClass('UNARY_PREFIX_OPERATOR', 15); | |
| 2311 | |
| 2312 /** | |
| 2313 * The name of the token class. | |
| 2314 */ | |
| 2315 final String name; | |
| 2316 | |
| 2317 /** | |
| 2318 * The precedence of tokens of this class, or `0` if the such tokens do not | |
| 2319 * represent an operator. | |
| 2320 */ | |
| 2321 final int precedence; | |
| 2322 | |
| 2323 const TokenClass(this.name, [this.precedence = 0]); | |
| 2324 | |
| 2325 @override | |
| 2326 String toString() => name; | |
| 2327 } | |
| 2328 | |
| 2329 /** | |
| 2330 * The types of tokens that can be returned by the scanner. | |
| 2331 */ | |
| 2332 class TokenType { | |
| 2333 /** | |
| 2334 * The type of the token that marks the end of the input. | |
| 2335 */ | |
| 2336 static const TokenType EOF = const TokenType_EOF('EOF'); | |
| 2337 | |
| 2338 static const TokenType DOUBLE = const TokenType('DOUBLE'); | |
| 2339 | |
| 2340 static const TokenType HEXADECIMAL = const TokenType('HEXADECIMAL'); | |
| 2341 | |
| 2342 static const TokenType IDENTIFIER = const TokenType('IDENTIFIER'); | |
| 2343 | |
| 2344 static const TokenType INT = const TokenType('INT'); | |
| 2345 | |
| 2346 static const TokenType KEYWORD = const TokenType('KEYWORD'); | |
| 2347 | |
| 2348 static const TokenType MULTI_LINE_COMMENT = | |
| 2349 const TokenType('MULTI_LINE_COMMENT'); | |
| 2350 | |
| 2351 static const TokenType SCRIPT_TAG = const TokenType('SCRIPT_TAG'); | |
| 2352 | |
| 2353 static const TokenType SINGLE_LINE_COMMENT = | |
| 2354 const TokenType('SINGLE_LINE_COMMENT'); | |
| 2355 | |
| 2356 static const TokenType STRING = const TokenType('STRING'); | |
| 2357 | |
| 2358 static const TokenType AMPERSAND = | |
| 2359 const TokenType('AMPERSAND', TokenClass.BITWISE_AND_OPERATOR, "&"); | |
| 2360 | |
| 2361 static const TokenType AMPERSAND_AMPERSAND = const TokenType( | |
| 2362 'AMPERSAND_AMPERSAND', TokenClass.LOGICAL_AND_OPERATOR, "&&"); | |
| 2363 | |
| 2364 static const TokenType AMPERSAND_EQ = | |
| 2365 const TokenType('AMPERSAND_EQ', TokenClass.ASSIGNMENT_OPERATOR, "&="); | |
| 2366 | |
| 2367 static const TokenType AT = const TokenType('AT', TokenClass.NO_CLASS, "@"); | |
| 2368 | |
| 2369 static const TokenType BANG = | |
| 2370 const TokenType('BANG', TokenClass.UNARY_PREFIX_OPERATOR, "!"); | |
| 2371 | |
| 2372 static const TokenType BANG_EQ = | |
| 2373 const TokenType('BANG_EQ', TokenClass.EQUALITY_OPERATOR, "!="); | |
| 2374 | |
| 2375 static const TokenType BAR = | |
| 2376 const TokenType('BAR', TokenClass.BITWISE_OR_OPERATOR, "|"); | |
| 2377 | |
| 2378 static const TokenType BAR_BAR = | |
| 2379 const TokenType('BAR_BAR', TokenClass.LOGICAL_OR_OPERATOR, "||"); | |
| 2380 | |
| 2381 static const TokenType BAR_EQ = | |
| 2382 const TokenType('BAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "|="); | |
| 2383 | |
| 2384 static const TokenType COLON = | |
| 2385 const TokenType('COLON', TokenClass.NO_CLASS, ":"); | |
| 2386 | |
| 2387 static const TokenType COMMA = | |
| 2388 const TokenType('COMMA', TokenClass.NO_CLASS, ","); | |
| 2389 | |
| 2390 static const TokenType CARET = | |
| 2391 const TokenType('CARET', TokenClass.BITWISE_XOR_OPERATOR, "^"); | |
| 2392 | |
| 2393 static const TokenType CARET_EQ = | |
| 2394 const TokenType('CARET_EQ', TokenClass.ASSIGNMENT_OPERATOR, "^="); | |
| 2395 | |
| 2396 static const TokenType CLOSE_CURLY_BRACKET = | |
| 2397 const TokenType('CLOSE_CURLY_BRACKET', TokenClass.NO_CLASS, "}"); | |
| 2398 | |
| 2399 static const TokenType CLOSE_PAREN = | |
| 2400 const TokenType('CLOSE_PAREN', TokenClass.NO_CLASS, ")"); | |
| 2401 | |
| 2402 static const TokenType CLOSE_SQUARE_BRACKET = | |
| 2403 const TokenType('CLOSE_SQUARE_BRACKET', TokenClass.NO_CLASS, "]"); | |
| 2404 | |
| 2405 static const TokenType EQ = | |
| 2406 const TokenType('EQ', TokenClass.ASSIGNMENT_OPERATOR, "="); | |
| 2407 | |
| 2408 static const TokenType EQ_EQ = | |
| 2409 const TokenType('EQ_EQ', TokenClass.EQUALITY_OPERATOR, "=="); | |
| 2410 | |
| 2411 static const TokenType FUNCTION = | |
| 2412 const TokenType('FUNCTION', TokenClass.NO_CLASS, "=>"); | |
| 2413 | |
| 2414 static const TokenType GT = | |
| 2415 const TokenType('GT', TokenClass.RELATIONAL_OPERATOR, ">"); | |
| 2416 | |
| 2417 static const TokenType GT_EQ = | |
| 2418 const TokenType('GT_EQ', TokenClass.RELATIONAL_OPERATOR, ">="); | |
| 2419 | |
| 2420 static const TokenType GT_GT = | |
| 2421 const TokenType('GT_GT', TokenClass.SHIFT_OPERATOR, ">>"); | |
| 2422 | |
| 2423 static const TokenType GT_GT_EQ = | |
| 2424 const TokenType('GT_GT_EQ', TokenClass.ASSIGNMENT_OPERATOR, ">>="); | |
| 2425 | |
| 2426 static const TokenType HASH = | |
| 2427 const TokenType('HASH', TokenClass.NO_CLASS, "#"); | |
| 2428 | |
| 2429 static const TokenType INDEX = | |
| 2430 const TokenType('INDEX', TokenClass.UNARY_POSTFIX_OPERATOR, "[]"); | |
| 2431 | |
| 2432 static const TokenType INDEX_EQ = | |
| 2433 const TokenType('INDEX_EQ', TokenClass.UNARY_POSTFIX_OPERATOR, "[]="); | |
| 2434 | |
| 2435 static const TokenType IS = | |
| 2436 const TokenType('IS', TokenClass.RELATIONAL_OPERATOR, "is"); | |
| 2437 | |
| 2438 static const TokenType LT = | |
| 2439 const TokenType('LT', TokenClass.RELATIONAL_OPERATOR, "<"); | |
| 2440 | |
| 2441 static const TokenType LT_EQ = | |
| 2442 const TokenType('LT_EQ', TokenClass.RELATIONAL_OPERATOR, "<="); | |
| 2443 | |
| 2444 static const TokenType LT_LT = | |
| 2445 const TokenType('LT_LT', TokenClass.SHIFT_OPERATOR, "<<"); | |
| 2446 | |
| 2447 static const TokenType LT_LT_EQ = | |
| 2448 const TokenType('LT_LT_EQ', TokenClass.ASSIGNMENT_OPERATOR, "<<="); | |
| 2449 | |
| 2450 static const TokenType MINUS = | |
| 2451 const TokenType('MINUS', TokenClass.ADDITIVE_OPERATOR, "-"); | |
| 2452 | |
| 2453 static const TokenType MINUS_EQ = | |
| 2454 const TokenType('MINUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, "-="); | |
| 2455 | |
| 2456 static const TokenType MINUS_MINUS = | |
| 2457 const TokenType('MINUS_MINUS', TokenClass.UNARY_PREFIX_OPERATOR, "--"); | |
| 2458 | |
| 2459 static const TokenType OPEN_CURLY_BRACKET = | |
| 2460 const TokenType('OPEN_CURLY_BRACKET', TokenClass.NO_CLASS, "{"); | |
| 2461 | |
| 2462 static const TokenType OPEN_PAREN = | |
| 2463 const TokenType('OPEN_PAREN', TokenClass.UNARY_POSTFIX_OPERATOR, "("); | |
| 2464 | |
| 2465 static const TokenType OPEN_SQUARE_BRACKET = const TokenType( | |
| 2466 'OPEN_SQUARE_BRACKET', TokenClass.UNARY_POSTFIX_OPERATOR, "["); | |
| 2467 | |
| 2468 static const TokenType PERCENT = | |
| 2469 const TokenType('PERCENT', TokenClass.MULTIPLICATIVE_OPERATOR, "%"); | |
| 2470 | |
| 2471 static const TokenType PERCENT_EQ = | |
| 2472 const TokenType('PERCENT_EQ', TokenClass.ASSIGNMENT_OPERATOR, "%="); | |
| 2473 | |
| 2474 static const TokenType PERIOD = | |
| 2475 const TokenType('PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, "."); | |
| 2476 | |
| 2477 static const TokenType PERIOD_PERIOD = | |
| 2478 const TokenType('PERIOD_PERIOD', TokenClass.CASCADE_OPERATOR, ".."); | |
| 2479 | |
| 2480 static const TokenType PLUS = | |
| 2481 const TokenType('PLUS', TokenClass.ADDITIVE_OPERATOR, "+"); | |
| 2482 | |
| 2483 static const TokenType PLUS_EQ = | |
| 2484 const TokenType('PLUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, "+="); | |
| 2485 | |
| 2486 static const TokenType PLUS_PLUS = | |
| 2487 const TokenType('PLUS_PLUS', TokenClass.UNARY_PREFIX_OPERATOR, "++"); | |
| 2488 | |
| 2489 static const TokenType QUESTION = | |
| 2490 const TokenType('QUESTION', TokenClass.CONDITIONAL_OPERATOR, "?"); | |
| 2491 | |
| 2492 static const TokenType QUESTION_PERIOD = const TokenType( | |
| 2493 'QUESTION_PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, '?.'); | |
| 2494 | |
| 2495 static const TokenType QUESTION_QUESTION = | |
| 2496 const TokenType('QUESTION_QUESTION', TokenClass.IF_NULL_OPERATOR, '??'); | |
| 2497 | |
| 2498 static const TokenType QUESTION_QUESTION_EQ = const TokenType( | |
| 2499 'QUESTION_QUESTION_EQ', TokenClass.ASSIGNMENT_OPERATOR, '??='); | |
| 2500 | |
| 2501 static const TokenType SEMICOLON = | |
| 2502 const TokenType('SEMICOLON', TokenClass.NO_CLASS, ";"); | |
| 2503 | |
| 2504 static const TokenType SLASH = | |
| 2505 const TokenType('SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, "/"); | |
| 2506 | |
| 2507 static const TokenType SLASH_EQ = | |
| 2508 const TokenType('SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, "/="); | |
| 2509 | |
| 2510 static const TokenType STAR = | |
| 2511 const TokenType('STAR', TokenClass.MULTIPLICATIVE_OPERATOR, "*"); | |
| 2512 | |
| 2513 static const TokenType STAR_EQ = | |
| 2514 const TokenType('STAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "*="); | |
| 2515 | |
| 2516 static const TokenType STRING_INTERPOLATION_EXPRESSION = const TokenType( | |
| 2517 'STRING_INTERPOLATION_EXPRESSION', TokenClass.NO_CLASS, "\${"); | |
| 2518 | |
| 2519 static const TokenType STRING_INTERPOLATION_IDENTIFIER = const TokenType( | |
| 2520 'STRING_INTERPOLATION_IDENTIFIER', TokenClass.NO_CLASS, "\$"); | |
| 2521 | |
| 2522 static const TokenType TILDE = | |
| 2523 const TokenType('TILDE', TokenClass.UNARY_PREFIX_OPERATOR, "~"); | |
| 2524 | |
| 2525 static const TokenType TILDE_SLASH = | |
| 2526 const TokenType('TILDE_SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, "~/"); | |
| 2527 | |
| 2528 static const TokenType TILDE_SLASH_EQ = | |
| 2529 const TokenType('TILDE_SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, "~/="); | |
| 2530 | |
| 2531 static const TokenType BACKPING = | |
| 2532 const TokenType('BACKPING', TokenClass.NO_CLASS, "`"); | |
| 2533 | |
| 2534 static const TokenType BACKSLASH = | |
| 2535 const TokenType('BACKSLASH', TokenClass.NO_CLASS, "\\"); | |
| 2536 | |
| 2537 static const TokenType PERIOD_PERIOD_PERIOD = | |
| 2538 const TokenType('PERIOD_PERIOD_PERIOD', TokenClass.NO_CLASS, "..."); | |
| 2539 | |
| 2540 static const TokenType GENERIC_METHOD_TYPE_LIST = | |
| 2541 const TokenType('GENERIC_METHOD_TYPE_LIST'); | |
| 2542 | |
| 2543 static const TokenType GENERIC_METHOD_TYPE_ASSIGN = | |
| 2544 const TokenType('GENERIC_METHOD_TYPE_ASSIGN'); | |
| 2545 | |
| 2546 /** | |
| 2547 * The class of the token. | |
| 2548 */ | |
| 2549 final TokenClass _tokenClass; | |
| 2550 | |
| 2551 /** | |
| 2552 * The name of the token type. | |
| 2553 */ | |
| 2554 final String name; | |
| 2555 | |
| 2556 /** | |
| 2557 * The lexeme that defines this type of token, or `null` if there is more than | |
| 2558 * one possible lexeme for this type of token. | |
| 2559 */ | |
| 2560 final String lexeme; | |
| 2561 | |
| 2562 const TokenType(this.name, | |
| 2563 [this._tokenClass = TokenClass.NO_CLASS, this.lexeme = null]); | |
| 2564 | |
| 2565 /** | |
| 2566 * Return `true` if this type of token represents an additive operator. | |
| 2567 */ | |
| 2568 bool get isAdditiveOperator => _tokenClass == TokenClass.ADDITIVE_OPERATOR; | |
| 2569 | |
| 2570 /** | |
| 2571 * Return `true` if this type of token represents an assignment operator. | |
| 2572 */ | |
| 2573 bool get isAssignmentOperator => | |
| 2574 _tokenClass == TokenClass.ASSIGNMENT_OPERATOR; | |
| 2575 | |
| 2576 /** | |
| 2577 * Return `true` if this type of token represents an associative operator. An | |
| 2578 * associative operator is an operator for which the following equality is | |
| 2579 * true: `(a * b) * c == a * (b * c)`. In other words, if the result of | |
| 2580 * applying the operator to multiple operands does not depend on the order in | |
| 2581 * which those applications occur. | |
| 2582 * | |
| 2583 * Note: This method considers the logical-and and logical-or operators to be | |
| 2584 * associative, even though the order in which the application of those | |
| 2585 * operators can have an effect because evaluation of the right-hand operand | |
| 2586 * is conditional. | |
| 2587 */ | |
| 2588 bool get isAssociativeOperator => | |
| 2589 this == AMPERSAND || | |
| 2590 this == AMPERSAND_AMPERSAND || | |
| 2591 this == BAR || | |
| 2592 this == BAR_BAR || | |
| 2593 this == CARET || | |
| 2594 this == PLUS || | |
| 2595 this == STAR; | |
| 2596 | |
| 2597 /** | |
| 2598 * Return `true` if this type of token represents an equality operator. | |
| 2599 */ | |
| 2600 bool get isEqualityOperator => _tokenClass == TokenClass.EQUALITY_OPERATOR; | |
| 2601 | |
| 2602 /** | |
| 2603 * Return `true` if this type of token represents an increment operator. | |
| 2604 */ | |
| 2605 bool get isIncrementOperator => | |
| 2606 identical(lexeme, "++") || identical(lexeme, "--"); | |
| 2607 | |
| 2608 /** | |
| 2609 * Return `true` if this type of token represents a multiplicative operator. | |
| 2610 */ | |
| 2611 bool get isMultiplicativeOperator => | |
| 2612 _tokenClass == TokenClass.MULTIPLICATIVE_OPERATOR; | |
| 2613 | |
| 2614 /** | |
| 2615 * Return `true` if this token type represents an operator. | |
| 2616 */ | |
| 2617 bool get isOperator => | |
| 2618 _tokenClass != TokenClass.NO_CLASS && | |
| 2619 this != OPEN_PAREN && | |
| 2620 this != OPEN_SQUARE_BRACKET && | |
| 2621 this != PERIOD; | |
| 2622 | |
| 2623 /** | |
| 2624 * Return `true` if this type of token represents a relational operator. | |
| 2625 */ | |
| 2626 bool get isRelationalOperator => | |
| 2627 _tokenClass == TokenClass.RELATIONAL_OPERATOR; | |
| 2628 | |
| 2629 /** | |
| 2630 * Return `true` if this type of token represents a shift operator. | |
| 2631 */ | |
| 2632 bool get isShiftOperator => _tokenClass == TokenClass.SHIFT_OPERATOR; | |
| 2633 | |
| 2634 /** | |
| 2635 * Return `true` if this type of token represents a unary postfix operator. | |
| 2636 */ | |
| 2637 bool get isUnaryPostfixOperator => | |
| 2638 _tokenClass == TokenClass.UNARY_POSTFIX_OPERATOR; | |
| 2639 | |
| 2640 /** | |
| 2641 * Return `true` if this type of token represents a unary prefix operator. | |
| 2642 */ | |
| 2643 bool get isUnaryPrefixOperator => | |
| 2644 _tokenClass == TokenClass.UNARY_PREFIX_OPERATOR; | |
| 2645 | |
| 2646 /** | |
| 2647 * Return `true` if this token type represents an operator that can be defined | |
| 2648 * by users. | |
| 2649 */ | |
| 2650 bool get isUserDefinableOperator => | |
| 2651 identical(lexeme, "==") || | |
| 2652 identical(lexeme, "~") || | |
| 2653 identical(lexeme, "[]") || | |
| 2654 identical(lexeme, "[]=") || | |
| 2655 identical(lexeme, "*") || | |
| 2656 identical(lexeme, "/") || | |
| 2657 identical(lexeme, "%") || | |
| 2658 identical(lexeme, "~/") || | |
| 2659 identical(lexeme, "+") || | |
| 2660 identical(lexeme, "-") || | |
| 2661 identical(lexeme, "<<") || | |
| 2662 identical(lexeme, ">>") || | |
| 2663 identical(lexeme, ">=") || | |
| 2664 identical(lexeme, ">") || | |
| 2665 identical(lexeme, "<=") || | |
| 2666 identical(lexeme, "<") || | |
| 2667 identical(lexeme, "&") || | |
| 2668 identical(lexeme, "^") || | |
| 2669 identical(lexeme, "|"); | |
| 2670 | |
| 2671 /** | |
| 2672 * Return the precedence of the token, or `0` if the token does not represent | |
| 2673 * an operator. | |
| 2674 */ | |
| 2675 int get precedence => _tokenClass.precedence; | |
| 2676 | |
| 2677 @override | |
| 2678 String toString() => name; | |
| 2679 } | |
| 2680 | |
| 2681 class TokenType_EOF extends TokenType { | |
| 2682 const TokenType_EOF(String name) : super(name, TokenClass.NO_CLASS, ""); | |
| 2683 | |
| 2684 @override | |
| 2685 String toString() => "-eof-"; | |
| 2686 } | |
| 2687 | |
| 2688 /** | |
| 2689 * A normal token that is preceded by comments. | |
| 2690 */ | |
| 2691 class TokenWithComment extends Token { | |
| 2692 /** | |
| 2693 * The first comment in the list of comments that precede this token. | |
| 2694 */ | |
| 2695 CommentToken _precedingComment; | |
| 2696 | |
| 2697 /** | |
| 2698 * Initialize a newly created token to have the given [type] at the given | |
| 2699 * [offset] and to be preceded by the comments reachable from the given | |
| 2700 * [comment]. | |
| 2701 */ | |
| 2702 TokenWithComment(TokenType type, int offset, this._precedingComment) | |
| 2703 : super(type, offset) { | |
| 2704 _setCommentParent(_precedingComment); | |
| 2705 } | |
| 2706 | |
| 2707 CommentToken get precedingComments => _precedingComment; | |
| 2708 | |
| 2709 void set precedingComments(CommentToken comment) { | |
| 2710 _precedingComment = comment; | |
| 2711 _setCommentParent(_precedingComment); | |
| 2712 } | |
| 2713 | |
| 2714 @override | |
| 2715 Token copy() => new TokenWithComment(type, offset, precedingComments); | |
| 2716 } | |
| OLD | NEW |