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 |