Index: analyzer/lib/src/generated/scanner.dart |
diff --git a/analyzer/lib/src/generated/scanner.dart b/analyzer/lib/src/generated/scanner.dart |
deleted file mode 100644 |
index 9e028ca29686c8576ef50cad18146639563783bb..0000000000000000000000000000000000000000 |
--- a/analyzer/lib/src/generated/scanner.dart |
+++ /dev/null |
@@ -1,2673 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library engine.scanner; |
- |
-import 'dart:collection'; |
- |
-import 'error.dart'; |
-import 'java_engine.dart'; |
-import 'source.dart'; |
- |
-/** |
- * The opening half of a grouping pair of tokens. This is used for curly |
- * brackets ('{'), parentheses ('('), and square brackets ('['). |
- */ |
-class BeginToken extends Token { |
- /** |
- * The token that corresponds to this token. |
- */ |
- Token endToken; |
- |
- /** |
- * Initialize a newly created token to have the given [type] at the given |
- * [offset]. |
- */ |
- BeginToken(TokenType type, int offset) : super(type, offset) { |
- assert(type == TokenType.OPEN_CURLY_BRACKET || |
- type == TokenType.OPEN_PAREN || |
- type == TokenType.OPEN_SQUARE_BRACKET || |
- type == TokenType.STRING_INTERPOLATION_EXPRESSION); |
- } |
- |
- @override |
- Token copy() => new BeginToken(type, offset); |
-} |
- |
-/** |
- * A begin token that is preceded by comments. |
- */ |
-class BeginTokenWithComment extends BeginToken { |
- /** |
- * The first comment in the list of comments that precede this token. |
- */ |
- CommentToken _precedingComment; |
- |
- /** |
- * Initialize a newly created token to have the given [type] at the given |
- * [offset] and to be preceded by the comments reachable from the given |
- * [comment]. |
- */ |
- BeginTokenWithComment(TokenType type, int offset, this._precedingComment) |
- : super(type, offset) { |
- _setCommentParent(_precedingComment); |
- } |
- |
- CommentToken get precedingComments => _precedingComment; |
- |
- void set precedingComments(CommentToken comment) { |
- _precedingComment = comment; |
- _setCommentParent(_precedingComment); |
- } |
- |
- @override |
- void applyDelta(int delta) { |
- super.applyDelta(delta); |
- Token token = precedingComments; |
- while (token != null) { |
- token.applyDelta(delta); |
- token = token.next; |
- } |
- } |
- |
- @override |
- Token copy() => |
- new BeginTokenWithComment(type, offset, copyComments(precedingComments)); |
-} |
- |
-/** |
- * A [CharacterReader] that reads a range of characters from another character |
- * reader. |
- */ |
-class CharacterRangeReader extends CharacterReader { |
- /** |
- * The reader from which the characters are actually being read. |
- */ |
- final CharacterReader baseReader; |
- |
- /** |
- * The last character to be read. |
- */ |
- final int endIndex; |
- |
- /** |
- * Initialize a newly created reader to read the characters from the given |
- * [baseReader] between the [startIndex] inclusive to [endIndex] exclusive. |
- */ |
- CharacterRangeReader(this.baseReader, int startIndex, this.endIndex) { |
- baseReader.offset = startIndex - 1; |
- } |
- |
- @override |
- int get offset => baseReader.offset; |
- |
- @override |
- void set offset(int offset) { |
- baseReader.offset = offset; |
- } |
- |
- @override |
- int advance() { |
- if (baseReader.offset + 1 >= endIndex) { |
- return -1; |
- } |
- return baseReader.advance(); |
- } |
- |
- @override |
- String getString(int start, int endDelta) => |
- baseReader.getString(start, endDelta); |
- |
- @override |
- int peek() { |
- if (baseReader.offset + 1 >= endIndex) { |
- return -1; |
- } |
- return baseReader.peek(); |
- } |
-} |
- |
-/** |
- * An object used by the scanner to read the characters to be scanned. |
- */ |
-abstract class CharacterReader { |
- /** |
- * The current offset relative to the beginning of the source. Return the |
- * initial offset if the scanner has not yet scanned the source code, and one |
- * (1) past the end of the source code if the entire source code has been |
- * scanned. |
- */ |
- int get offset; |
- |
- /** |
- * Set the current offset relative to the beginning of the source to the given |
- * [offset]. The new offset must be between the initial offset and one (1) |
- * past the end of the source code. |
- */ |
- void set offset(int offset); |
- |
- /** |
- * Advance the current position and return the character at the new current |
- * position. |
- */ |
- int advance(); |
- |
- /** |
- * Return the substring of the source code between the [start] offset and the |
- * modified current position. The current position is modified by adding the |
- * [endDelta], which is the number of characters after the current location to |
- * be included in the string, or the number of characters before the current |
- * location to be excluded if the offset is negative. |
- */ |
- String getString(int start, int endDelta); |
- |
- /** |
- * Return the character at the current position without changing the current |
- * position. |
- */ |
- int peek(); |
-} |
- |
-/** |
- * A [CharacterReader] that reads characters from a character sequence. |
- */ |
-class CharSequenceReader implements CharacterReader { |
- /** |
- * The sequence from which characters will be read. |
- */ |
- final String _sequence; |
- |
- /** |
- * The number of characters in the string. |
- */ |
- int _stringLength = 0; |
- |
- /** |
- * The index, relative to the string, of the last character that was read. |
- */ |
- int _charOffset = 0; |
- |
- /** |
- * Initialize a newly created reader to read the characters in the given |
- * [_sequence]. |
- */ |
- CharSequenceReader(this._sequence) { |
- this._stringLength = _sequence.length; |
- this._charOffset = -1; |
- } |
- |
- @override |
- int get offset => _charOffset; |
- |
- @override |
- void set offset(int offset) { |
- _charOffset = offset; |
- } |
- |
- @override |
- int advance() { |
- if (_charOffset + 1 >= _stringLength) { |
- return -1; |
- } |
- return _sequence.codeUnitAt(++_charOffset); |
- } |
- |
- @override |
- String getString(int start, int endDelta) => |
- _sequence.substring(start, _charOffset + 1 + endDelta).toString(); |
- |
- @override |
- int peek() { |
- if (_charOffset + 1 >= _stringLength) { |
- return -1; |
- } |
- return _sequence.codeUnitAt(_charOffset + 1); |
- } |
-} |
- |
-/** |
- * A token representing a comment. |
- */ |
-class CommentToken extends StringToken { |
- /** |
- * The [Token] that contains this comment. |
- */ |
- Token parent; |
- |
- /** |
- * Initialize a newly created token to represent a token of the given [type] |
- * with the given [value] at the given [offset]. |
- */ |
- CommentToken(TokenType type, String value, int offset) |
- : super(type, value, offset); |
- |
- @override |
- CommentToken copy() => new CommentToken(type, _value, offset); |
-} |
- |
-/** |
- * A documentation comment token. |
- */ |
-class DocumentationCommentToken extends CommentToken { |
- /** |
- * The references embedded within the documentation comment. |
- * This list will be empty unless this is a documentation comment that has |
- * references embedded within it. |
- */ |
- final List<Token> references = <Token>[]; |
- |
- /** |
- * Initialize a newly created token to represent a token of the given [type] |
- * with the given [value] at the given [offset]. |
- */ |
- DocumentationCommentToken(TokenType type, String value, int offset) |
- : super(type, value, offset); |
- |
- @override |
- CommentToken copy() => new DocumentationCommentToken(type, _value, offset); |
-} |
- |
-/** |
- * The keywords in the Dart programming language. |
- */ |
-class Keyword { |
- static const Keyword ASSERT = const Keyword('ASSERT', "assert"); |
- |
- static const Keyword BREAK = const Keyword('BREAK', "break"); |
- |
- static const Keyword CASE = const Keyword('CASE', "case"); |
- |
- static const Keyword CATCH = const Keyword('CATCH', "catch"); |
- |
- static const Keyword CLASS = const Keyword('CLASS', "class"); |
- |
- static const Keyword CONST = const Keyword('CONST', "const"); |
- |
- static const Keyword CONTINUE = const Keyword('CONTINUE', "continue"); |
- |
- static const Keyword DEFAULT = const Keyword('DEFAULT', "default"); |
- |
- static const Keyword DO = const Keyword('DO', "do"); |
- |
- static const Keyword ELSE = const Keyword('ELSE', "else"); |
- |
- static const Keyword ENUM = const Keyword('ENUM', "enum"); |
- |
- static const Keyword EXTENDS = const Keyword('EXTENDS', "extends"); |
- |
- static const Keyword FALSE = const Keyword('FALSE', "false"); |
- |
- static const Keyword FINAL = const Keyword('FINAL', "final"); |
- |
- static const Keyword FINALLY = const Keyword('FINALLY', "finally"); |
- |
- static const Keyword FOR = const Keyword('FOR', "for"); |
- |
- static const Keyword IF = const Keyword('IF', "if"); |
- |
- static const Keyword IN = const Keyword('IN', "in"); |
- |
- static const Keyword IS = const Keyword('IS', "is"); |
- |
- static const Keyword NEW = const Keyword('NEW', "new"); |
- |
- static const Keyword NULL = const Keyword('NULL', "null"); |
- |
- static const Keyword RETHROW = const Keyword('RETHROW', "rethrow"); |
- |
- static const Keyword RETURN = const Keyword('RETURN', "return"); |
- |
- static const Keyword SUPER = const Keyword('SUPER', "super"); |
- |
- static const Keyword SWITCH = const Keyword('SWITCH', "switch"); |
- |
- static const Keyword THIS = const Keyword('THIS', "this"); |
- |
- static const Keyword THROW = const Keyword('THROW', "throw"); |
- |
- static const Keyword TRUE = const Keyword('TRUE', "true"); |
- |
- static const Keyword TRY = const Keyword('TRY', "try"); |
- |
- static const Keyword VAR = const Keyword('VAR', "var"); |
- |
- static const Keyword VOID = const Keyword('VOID', "void"); |
- |
- static const Keyword WHILE = const Keyword('WHILE', "while"); |
- |
- static const Keyword WITH = const Keyword('WITH', "with"); |
- |
- static const Keyword ABSTRACT = const Keyword('ABSTRACT', "abstract", true); |
- |
- static const Keyword AS = const Keyword('AS', "as", true); |
- |
- static const Keyword DEFERRED = const Keyword('DEFERRED', "deferred", true); |
- |
- static const Keyword DYNAMIC = const Keyword('DYNAMIC', "dynamic", true); |
- |
- static const Keyword EXPORT = const Keyword('EXPORT', "export", true); |
- |
- static const Keyword EXTERNAL = const Keyword('EXTERNAL', "external", true); |
- |
- static const Keyword FACTORY = const Keyword('FACTORY', "factory", true); |
- |
- static const Keyword GET = const Keyword('GET', "get", true); |
- |
- static const Keyword IMPLEMENTS = |
- const Keyword('IMPLEMENTS', "implements", true); |
- |
- static const Keyword IMPORT = const Keyword('IMPORT', "import", true); |
- |
- static const Keyword LIBRARY = const Keyword('LIBRARY', "library", true); |
- |
- static const Keyword OPERATOR = const Keyword('OPERATOR', "operator", true); |
- |
- static const Keyword PART = const Keyword('PART', "part", true); |
- |
- static const Keyword SET = const Keyword('SET', "set", true); |
- |
- static const Keyword STATIC = const Keyword('STATIC', "static", true); |
- |
- static const Keyword TYPEDEF = const Keyword('TYPEDEF', "typedef", true); |
- |
- static const List<Keyword> values = const [ |
- ASSERT, |
- BREAK, |
- CASE, |
- CATCH, |
- CLASS, |
- CONST, |
- CONTINUE, |
- DEFAULT, |
- DO, |
- ELSE, |
- ENUM, |
- EXTENDS, |
- FALSE, |
- FINAL, |
- FINALLY, |
- FOR, |
- IF, |
- IN, |
- IS, |
- NEW, |
- NULL, |
- RETHROW, |
- RETURN, |
- SUPER, |
- SWITCH, |
- THIS, |
- THROW, |
- TRUE, |
- TRY, |
- VAR, |
- VOID, |
- WHILE, |
- WITH, |
- ABSTRACT, |
- AS, |
- DEFERRED, |
- DYNAMIC, |
- EXPORT, |
- EXTERNAL, |
- FACTORY, |
- GET, |
- IMPLEMENTS, |
- IMPORT, |
- LIBRARY, |
- OPERATOR, |
- PART, |
- SET, |
- STATIC, |
- TYPEDEF |
- ]; |
- |
- /** |
- * A table mapping the lexemes of keywords to the corresponding keyword. |
- */ |
- static final Map<String, Keyword> keywords = _createKeywordMap(); |
- |
- /** |
- * The name of the keyword type. |
- */ |
- final String name; |
- |
- /** |
- * The lexeme for the keyword. |
- */ |
- final String syntax; |
- |
- /** |
- * A flag indicating whether the keyword is a pseudo-keyword. Pseudo keywords |
- * can be used as identifiers. |
- */ |
- final bool isPseudoKeyword; |
- |
- /** |
- * Initialize a newly created keyword to have the given [name] and [syntax]. |
- * The keyword is a pseudo-keyword if the [isPseudoKeyword] flag is `true`. |
- */ |
- const Keyword(this.name, this.syntax, [this.isPseudoKeyword = false]); |
- |
- @override |
- String toString() => name; |
- |
- /** |
- * Create a table mapping the lexemes of keywords to the corresponding keyword |
- * and return the table that was created. |
- */ |
- static Map<String, Keyword> _createKeywordMap() { |
- LinkedHashMap<String, Keyword> result = |
- new LinkedHashMap<String, Keyword>(); |
- for (Keyword keyword in values) { |
- result[keyword.syntax] = keyword; |
- } |
- return result; |
- } |
-} |
- |
-/** |
- * A state in a state machine used to scan keywords. |
- */ |
-class KeywordState { |
- /** |
- * An empty transition table used by leaf states. |
- */ |
- static List<KeywordState> _EMPTY_TABLE = new List<KeywordState>(26); |
- |
- /** |
- * The initial state in the state machine. |
- */ |
- static final KeywordState KEYWORD_STATE = _createKeywordStateTable(); |
- |
- /** |
- * A table mapping characters to the states to which those characters will |
- * transition. (The index into the array is the offset from the character |
- * `'a'` to the transitioning character.) |
- */ |
- final List<KeywordState> _table; |
- |
- /** |
- * The keyword that is recognized by this state, or `null` if this state is |
- * not a terminal state. |
- */ |
- Keyword _keyword; |
- |
- /** |
- * Initialize a newly created state to have the given transitions and to |
- * recognize the keyword with the given [syntax]. |
- */ |
- KeywordState(this._table, String syntax) { |
- this._keyword = (syntax == null) ? null : Keyword.keywords[syntax]; |
- } |
- |
- /** |
- * Return the keyword that was recognized by this state, or `null` if this |
- * state does not recognized a keyword. |
- */ |
- Keyword keyword() => _keyword; |
- |
- /** |
- * Return the state that follows this state on a transition of the given |
- * [character], or `null` if there is no valid state reachable from this state |
- * with such a transition. |
- */ |
- KeywordState next(int character) => _table[character - 0x61]; |
- |
- /** |
- * Create the next state in the state machine where we have already recognized |
- * the subset of strings in the given array of [strings] starting at the given |
- * [offset] and having the given [length]. All of these strings have a common |
- * prefix and the next character is at the given [start] index. |
- */ |
- static KeywordState _computeKeywordStateTable( |
- int start, List<String> strings, int offset, int length) { |
- List<KeywordState> result = new List<KeywordState>(26); |
- assert(length != 0); |
- int chunk = 0x0; |
- int chunkStart = -1; |
- bool isLeaf = false; |
- for (int i = offset; i < offset + length; i++) { |
- if (strings[i].length == start) { |
- isLeaf = true; |
- } |
- if (strings[i].length > start) { |
- int c = strings[i].codeUnitAt(start); |
- if (chunk != c) { |
- if (chunkStart != -1) { |
- result[chunk - 0x61] = _computeKeywordStateTable( |
- start + 1, strings, chunkStart, i - chunkStart); |
- } |
- chunkStart = i; |
- chunk = c; |
- } |
- } |
- } |
- if (chunkStart != -1) { |
- assert(result[chunk - 0x61] == null); |
- result[chunk - 0x61] = _computeKeywordStateTable( |
- start + 1, strings, chunkStart, offset + length - chunkStart); |
- } else { |
- assert(length == 1); |
- return new KeywordState(_EMPTY_TABLE, strings[offset]); |
- } |
- if (isLeaf) { |
- return new KeywordState(result, strings[offset]); |
- } else { |
- return new KeywordState(result, null); |
- } |
- } |
- |
- /** |
- * Create and return the initial state in the state machine. |
- */ |
- static KeywordState _createKeywordStateTable() { |
- List<Keyword> values = Keyword.values; |
- List<String> strings = new List<String>(values.length); |
- for (int i = 0; i < values.length; i++) { |
- strings[i] = values[i].syntax; |
- } |
- strings.sort(); |
- return _computeKeywordStateTable(0, strings, 0, strings.length); |
- } |
-} |
- |
-/** |
- * A token representing a keyword in the language. |
- */ |
-class KeywordToken extends Token { |
- /** |
- * The keyword being represented by this token. |
- */ |
- final Keyword keyword; |
- |
- /** |
- * Initialize a newly created token to represent the given [keyword] at the |
- * given [offset]. |
- */ |
- KeywordToken(this.keyword, int offset) : super(TokenType.KEYWORD, offset); |
- |
- @override |
- String get lexeme => keyword.syntax; |
- |
- @override |
- Token copy() => new KeywordToken(keyword, offset); |
- |
- @override |
- Keyword value() => keyword; |
-} |
- |
-/** |
- * A keyword token that is preceded by comments. |
- */ |
-class KeywordTokenWithComment extends KeywordToken { |
- /** |
- * The first comment in the list of comments that precede this token. |
- */ |
- CommentToken _precedingComment; |
- |
- /** |
- * Initialize a newly created token to to represent the given [keyword] at the |
- * given [offset] and to be preceded by the comments reachable from the given |
- * [comment]. |
- */ |
- KeywordTokenWithComment(Keyword keyword, int offset, this._precedingComment) |
- : super(keyword, offset) { |
- _setCommentParent(_precedingComment); |
- } |
- |
- CommentToken get precedingComments => _precedingComment; |
- |
- void set precedingComments(CommentToken comment) { |
- _precedingComment = comment; |
- _setCommentParent(_precedingComment); |
- } |
- |
- @override |
- void applyDelta(int delta) { |
- super.applyDelta(delta); |
- Token token = precedingComments; |
- while (token != null) { |
- token.applyDelta(delta); |
- token = token.next; |
- } |
- } |
- |
- @override |
- Token copy() => new KeywordTokenWithComment( |
- keyword, offset, copyComments(precedingComments)); |
-} |
- |
-/** |
- * The class `Scanner` implements a scanner for Dart code. |
- * |
- * The lexical structure of Dart is ambiguous without knowledge of the context |
- * in which a token is being scanned. For example, without context we cannot |
- * determine whether source of the form "<<" should be scanned as a single |
- * left-shift operator or as two left angle brackets. This scanner does not have |
- * any context, so it always resolves such conflicts by scanning the longest |
- * possible token. |
- */ |
-class Scanner { |
- /** |
- * The source being scanned. |
- */ |
- final Source source; |
- |
- /** |
- * The reader used to access the characters in the source. |
- */ |
- final CharacterReader _reader; |
- |
- /** |
- * The error listener that will be informed of any errors that are found |
- * during the scan. |
- */ |
- final AnalysisErrorListener _errorListener; |
- |
- /** |
- * The flag specifying whether documentation comments should be parsed. |
- */ |
- bool _preserveComments = true; |
- |
- /** |
- * The token pointing to the head of the linked list of tokens. |
- */ |
- Token _tokens; |
- |
- /** |
- * The last token that was scanned. |
- */ |
- Token _tail; |
- |
- /** |
- * The first token in the list of comment tokens found since the last |
- * non-comment token. |
- */ |
- Token _firstComment; |
- |
- /** |
- * The last token in the list of comment tokens found since the last |
- * non-comment token. |
- */ |
- Token _lastComment; |
- |
- /** |
- * The index of the first character of the current token. |
- */ |
- int _tokenStart = 0; |
- |
- /** |
- * A list containing the offsets of the first character of each line in the |
- * source code. |
- */ |
- List<int> _lineStarts = new List<int>(); |
- |
- /** |
- * A list, treated something like a stack, of tokens representing the |
- * beginning of a matched pair. It is used to pair the end tokens with the |
- * begin tokens. |
- */ |
- List<BeginToken> _groupingStack = new List<BeginToken>(); |
- |
- /** |
- * The index of the last item in the [_groupingStack], or `-1` if the stack is |
- * empty. |
- */ |
- int _stackEnd = -1; |
- |
- /** |
- * A flag indicating whether any unmatched groups were found during the parse. |
- */ |
- bool _hasUnmatchedGroups = false; |
- |
- /** |
- * Initialize a newly created scanner to scan characters from the given |
- * [source]. The given character [_reader] will be used to read the characters |
- * in the source. The given [_errorListener] will be informed of any errors |
- * that are found. |
- */ |
- Scanner(this.source, this._reader, this._errorListener) { |
- _tokens = new Token(TokenType.EOF, -1); |
- _tokens.setNext(_tokens); |
- _tail = _tokens; |
- _tokenStart = -1; |
- _lineStarts.add(0); |
- } |
- |
- /** |
- * Return the first token in the token stream that was scanned. |
- */ |
- Token get firstToken => _tokens.next; |
- |
- /** |
- * Return `true` if any unmatched groups were found during the parse. |
- */ |
- bool get hasUnmatchedGroups => _hasUnmatchedGroups; |
- |
- /** |
- * Return an array containing the offsets of the first character of each line |
- * in the source code. |
- */ |
- List<int> get lineStarts => _lineStarts; |
- |
- /** |
- * Set whether documentation tokens should be preserved. |
- */ |
- void set preserveComments(bool preserveComments) { |
- this._preserveComments = preserveComments; |
- } |
- |
- /** |
- * Return the last token that was scanned. |
- */ |
- Token get tail => _tail; |
- |
- /** |
- * Append the given [token] to the end of the token stream being scanned. This |
- * method is intended to be used by subclasses that copy existing tokens and |
- * should not normally be used because it will fail to correctly associate any |
- * comments with the token being passed in. |
- */ |
- void appendToken(Token token) { |
- _tail = _tail.setNext(token); |
- } |
- |
- int bigSwitch(int next) { |
- _beginToken(); |
- if (next == 0xD) { |
- // '\r' |
- next = _reader.advance(); |
- if (next == 0xA) { |
- // '\n' |
- next = _reader.advance(); |
- } |
- recordStartOfLine(); |
- return next; |
- } else if (next == 0xA) { |
- // '\n' |
- next = _reader.advance(); |
- recordStartOfLine(); |
- return next; |
- } else if (next == 0x9 || next == 0x20) { |
- // '\t' || ' ' |
- return _reader.advance(); |
- } |
- if (next == 0x72) { |
- // 'r' |
- int peek = _reader.peek(); |
- if (peek == 0x22 || peek == 0x27) { |
- // '"' || "'" |
- int start = _reader.offset; |
- return _tokenizeString(_reader.advance(), start, true); |
- } |
- } |
- if (0x61 <= next && next <= 0x7A) { |
- // 'a'-'z' |
- return _tokenizeKeywordOrIdentifier(next, true); |
- } |
- if ((0x41 <= next && next <= 0x5A) || next == 0x5F || next == 0x24) { |
- // 'A'-'Z' || '_' || '$' |
- return _tokenizeIdentifier(next, _reader.offset, true); |
- } |
- if (next == 0x3C) { |
- // '<' |
- return _tokenizeLessThan(next); |
- } |
- if (next == 0x3E) { |
- // '>' |
- return _tokenizeGreaterThan(next); |
- } |
- if (next == 0x3D) { |
- // '=' |
- return _tokenizeEquals(next); |
- } |
- if (next == 0x21) { |
- // '!' |
- return _tokenizeExclamation(next); |
- } |
- if (next == 0x2B) { |
- // '+' |
- return _tokenizePlus(next); |
- } |
- if (next == 0x2D) { |
- // '-' |
- return _tokenizeMinus(next); |
- } |
- if (next == 0x2A) { |
- // '*' |
- return _tokenizeMultiply(next); |
- } |
- if (next == 0x25) { |
- // '%' |
- return _tokenizePercent(next); |
- } |
- if (next == 0x26) { |
- // '&' |
- return _tokenizeAmpersand(next); |
- } |
- if (next == 0x7C) { |
- // '|' |
- return _tokenizeBar(next); |
- } |
- if (next == 0x5E) { |
- // '^' |
- return _tokenizeCaret(next); |
- } |
- if (next == 0x5B) { |
- // '[' |
- return _tokenizeOpenSquareBracket(next); |
- } |
- if (next == 0x7E) { |
- // '~' |
- return _tokenizeTilde(next); |
- } |
- if (next == 0x5C) { |
- // '\\' |
- _appendTokenOfType(TokenType.BACKSLASH); |
- return _reader.advance(); |
- } |
- if (next == 0x23) { |
- // '#' |
- return _tokenizeTag(next); |
- } |
- if (next == 0x28) { |
- // '(' |
- _appendBeginToken(TokenType.OPEN_PAREN); |
- return _reader.advance(); |
- } |
- if (next == 0x29) { |
- // ')' |
- _appendEndToken(TokenType.CLOSE_PAREN, TokenType.OPEN_PAREN); |
- return _reader.advance(); |
- } |
- if (next == 0x2C) { |
- // ',' |
- _appendTokenOfType(TokenType.COMMA); |
- return _reader.advance(); |
- } |
- if (next == 0x3A) { |
- // ':' |
- _appendTokenOfType(TokenType.COLON); |
- return _reader.advance(); |
- } |
- if (next == 0x3B) { |
- // ';' |
- _appendTokenOfType(TokenType.SEMICOLON); |
- return _reader.advance(); |
- } |
- if (next == 0x3F) { |
- // '?' |
- return _tokenizeQuestion(); |
- } |
- if (next == 0x5D) { |
- // ']' |
- _appendEndToken( |
- TokenType.CLOSE_SQUARE_BRACKET, TokenType.OPEN_SQUARE_BRACKET); |
- return _reader.advance(); |
- } |
- if (next == 0x60) { |
- // '`' |
- _appendTokenOfType(TokenType.BACKPING); |
- return _reader.advance(); |
- } |
- if (next == 0x7B) { |
- // '{' |
- _appendBeginToken(TokenType.OPEN_CURLY_BRACKET); |
- return _reader.advance(); |
- } |
- if (next == 0x7D) { |
- // '}' |
- _appendEndToken( |
- TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET); |
- return _reader.advance(); |
- } |
- if (next == 0x2F) { |
- // '/' |
- return _tokenizeSlashOrComment(next); |
- } |
- if (next == 0x40) { |
- // '@' |
- _appendTokenOfType(TokenType.AT); |
- return _reader.advance(); |
- } |
- if (next == 0x22 || next == 0x27) { |
- // '"' || "'" |
- return _tokenizeString(next, _reader.offset, false); |
- } |
- if (next == 0x2E) { |
- // '.' |
- return _tokenizeDotOrNumber(next); |
- } |
- if (next == 0x30) { |
- // '0' |
- return _tokenizeHexOrNumber(next); |
- } |
- if (0x31 <= next && next <= 0x39) { |
- // '1'-'9' |
- return _tokenizeNumber(next); |
- } |
- if (next == -1) { |
- // EOF |
- return -1; |
- } |
- _reportError(ScannerErrorCode.ILLEGAL_CHARACTER, [next]); |
- return _reader.advance(); |
- } |
- |
- /** |
- * Record the fact that we are at the beginning of a new line in the source. |
- */ |
- void recordStartOfLine() { |
- _lineStarts.add(_reader.offset); |
- } |
- |
- /** |
- * Record that the source begins on the given [line] and [column] at the |
- * current offset as given by the reader. Both the line and the column are |
- * one-based indexes. The line starts for lines before the given line will not |
- * be correct. |
- * |
- * This method must be invoked at most one time and must be invoked before |
- * scanning begins. The values provided must be sensible. The results are |
- * undefined if these conditions are violated. |
- */ |
- void setSourceStart(int line, int column) { |
- int offset = _reader.offset; |
- if (line < 1 || column < 1 || offset < 0 || (line + column - 2) >= offset) { |
- return; |
- } |
- for (int i = 2; i < line; i++) { |
- _lineStarts.add(1); |
- } |
- _lineStarts.add(offset - column + 1); |
- } |
- |
- /** |
- * Scan the source code to produce a list of tokens representing the source, |
- * and return the first token in the list of tokens that were produced. |
- */ |
- Token tokenize() { |
- int next = _reader.advance(); |
- while (next != -1) { |
- next = bigSwitch(next); |
- } |
- _appendEofToken(); |
- return firstToken; |
- } |
- |
- void _appendBeginToken(TokenType type) { |
- BeginToken token; |
- if (_firstComment == null) { |
- token = new BeginToken(type, _tokenStart); |
- } else { |
- token = new BeginTokenWithComment(type, _tokenStart, _firstComment); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- _tail = _tail.setNext(token); |
- _groupingStack.add(token); |
- _stackEnd++; |
- } |
- |
- void _appendCommentToken(TokenType type, String value) { |
- // Ignore comment tokens if client specified that it doesn't need them. |
- if (!_preserveComments) { |
- return; |
- } |
- // OK, remember comment tokens. |
- CommentToken token; |
- if (_isDocumentationComment(value)) { |
- token = new DocumentationCommentToken(type, value, _tokenStart); |
- } else { |
- token = new CommentToken(type, value, _tokenStart); |
- } |
- if (_firstComment == null) { |
- _firstComment = token; |
- _lastComment = _firstComment; |
- } else { |
- _lastComment = _lastComment.setNext(token); |
- } |
- } |
- |
- void _appendEndToken(TokenType type, TokenType beginType) { |
- Token token; |
- if (_firstComment == null) { |
- token = new Token(type, _tokenStart); |
- } else { |
- token = new TokenWithComment(type, _tokenStart, _firstComment); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- _tail = _tail.setNext(token); |
- if (_stackEnd >= 0) { |
- BeginToken begin = _groupingStack[_stackEnd]; |
- if (begin.type == beginType) { |
- begin.endToken = token; |
- _groupingStack.removeAt(_stackEnd--); |
- } |
- } |
- } |
- |
- void _appendEofToken() { |
- Token eofToken; |
- if (_firstComment == null) { |
- eofToken = new Token(TokenType.EOF, _reader.offset + 1); |
- } else { |
- eofToken = new TokenWithComment( |
- TokenType.EOF, _reader.offset + 1, _firstComment); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- // The EOF token points to itself so that there is always infinite |
- // look-ahead. |
- eofToken.setNext(eofToken); |
- _tail = _tail.setNext(eofToken); |
- if (_stackEnd >= 0) { |
- _hasUnmatchedGroups = true; |
- // TODO(brianwilkerson) Fix the ungrouped tokens? |
- } |
- } |
- |
- void _appendKeywordToken(Keyword keyword) { |
- if (_firstComment == null) { |
- _tail = _tail.setNext(new KeywordToken(keyword, _tokenStart)); |
- } else { |
- _tail = _tail.setNext( |
- new KeywordTokenWithComment(keyword, _tokenStart, _firstComment)); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- } |
- |
- void _appendStringToken(TokenType type, String value) { |
- if (_firstComment == null) { |
- _tail = _tail.setNext(new StringToken(type, value, _tokenStart)); |
- } else { |
- _tail = _tail.setNext( |
- new StringTokenWithComment(type, value, _tokenStart, _firstComment)); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- } |
- |
- void _appendStringTokenWithOffset(TokenType type, String value, int offset) { |
- if (_firstComment == null) { |
- _tail = _tail.setNext(new StringToken(type, value, _tokenStart + offset)); |
- } else { |
- _tail = _tail.setNext(new StringTokenWithComment( |
- type, value, _tokenStart + offset, _firstComment)); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- } |
- |
- void _appendTokenOfType(TokenType type) { |
- if (_firstComment == null) { |
- _tail = _tail.setNext(new Token(type, _tokenStart)); |
- } else { |
- _tail = |
- _tail.setNext(new TokenWithComment(type, _tokenStart, _firstComment)); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- } |
- |
- void _appendTokenOfTypeWithOffset(TokenType type, int offset) { |
- if (_firstComment == null) { |
- _tail = _tail.setNext(new Token(type, offset)); |
- } else { |
- _tail = _tail.setNext(new TokenWithComment(type, offset, _firstComment)); |
- _firstComment = null; |
- _lastComment = null; |
- } |
- } |
- |
- void _beginToken() { |
- _tokenStart = _reader.offset; |
- } |
- |
- /** |
- * Return the beginning token corresponding to a closing brace that was found |
- * while scanning inside a string interpolation expression. Tokens that cannot |
- * be matched with the closing brace will be dropped from the stack. |
- */ |
- BeginToken _findTokenMatchingClosingBraceInInterpolationExpression() { |
- while (_stackEnd >= 0) { |
- BeginToken begin = _groupingStack[_stackEnd]; |
- if (begin.type == TokenType.OPEN_CURLY_BRACKET || |
- begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) { |
- return begin; |
- } |
- _hasUnmatchedGroups = true; |
- _groupingStack.removeAt(_stackEnd--); |
- } |
- // |
- // We should never get to this point because we wouldn't be inside a string |
- // interpolation expression unless we had previously found the start of the |
- // expression. |
- // |
- return null; |
- } |
- |
- /** |
- * Report an error at the current offset. The [errorCode] is the error code |
- * indicating the nature of the error. The [arguments] are any arguments |
- * needed to complete the error message |
- */ |
- void _reportError(ScannerErrorCode errorCode, [List<Object> arguments]) { |
- _errorListener.onError( |
- new AnalysisError(source, _reader.offset, 1, errorCode, arguments)); |
- } |
- |
- int _select(int choice, TokenType yesType, TokenType noType) { |
- int next = _reader.advance(); |
- if (next == choice) { |
- _appendTokenOfType(yesType); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(noType); |
- return next; |
- } |
- } |
- |
- int _selectWithOffset( |
- int choice, TokenType yesType, TokenType noType, int offset) { |
- int next = _reader.advance(); |
- if (next == choice) { |
- _appendTokenOfTypeWithOffset(yesType, offset); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfTypeWithOffset(noType, offset); |
- return next; |
- } |
- } |
- |
- int _tokenizeAmpersand(int next) { |
- // && &= & |
- next = _reader.advance(); |
- if (next == 0x26) { |
- _appendTokenOfType(TokenType.AMPERSAND_AMPERSAND); |
- return _reader.advance(); |
- } else if (next == 0x3D) { |
- _appendTokenOfType(TokenType.AMPERSAND_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.AMPERSAND); |
- return next; |
- } |
- } |
- |
- int _tokenizeBar(int next) { |
- // | || |= |
- next = _reader.advance(); |
- if (next == 0x7C) { |
- _appendTokenOfType(TokenType.BAR_BAR); |
- return _reader.advance(); |
- } else if (next == 0x3D) { |
- _appendTokenOfType(TokenType.BAR_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.BAR); |
- return next; |
- } |
- } |
- |
- int _tokenizeCaret(int next) => |
- _select(0x3D, TokenType.CARET_EQ, TokenType.CARET); |
- |
- int _tokenizeDotOrNumber(int next) { |
- int start = _reader.offset; |
- next = _reader.advance(); |
- if (0x30 <= next && next <= 0x39) { |
- return _tokenizeFractionPart(next, start); |
- } else if (0x2E == next) { |
- return _select( |
- 0x2E, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIOD); |
- } else { |
- _appendTokenOfType(TokenType.PERIOD); |
- return next; |
- } |
- } |
- |
- int _tokenizeEquals(int next) { |
- // = == => |
- next = _reader.advance(); |
- if (next == 0x3D) { |
- _appendTokenOfType(TokenType.EQ_EQ); |
- return _reader.advance(); |
- } else if (next == 0x3E) { |
- _appendTokenOfType(TokenType.FUNCTION); |
- return _reader.advance(); |
- } |
- _appendTokenOfType(TokenType.EQ); |
- return next; |
- } |
- |
- int _tokenizeExclamation(int next) { |
- // ! != |
- next = _reader.advance(); |
- if (next == 0x3D) { |
- _appendTokenOfType(TokenType.BANG_EQ); |
- return _reader.advance(); |
- } |
- _appendTokenOfType(TokenType.BANG); |
- return next; |
- } |
- |
- int _tokenizeExponent(int next) { |
- if (next == 0x2B || next == 0x2D) { |
- next = _reader.advance(); |
- } |
- bool hasDigits = false; |
- while (true) { |
- if (0x30 <= next && next <= 0x39) { |
- hasDigits = true; |
- } else { |
- if (!hasDigits) { |
- _reportError(ScannerErrorCode.MISSING_DIGIT); |
- } |
- return next; |
- } |
- next = _reader.advance(); |
- } |
- } |
- |
- int _tokenizeFractionPart(int next, int start) { |
- bool done = false; |
- bool hasDigit = false; |
- LOOP: while (!done) { |
- if (0x30 <= next && next <= 0x39) { |
- hasDigit = true; |
- } else if (0x65 == next || 0x45 == next) { |
- hasDigit = true; |
- next = _tokenizeExponent(_reader.advance()); |
- done = true; |
- continue LOOP; |
- } else { |
- done = true; |
- continue LOOP; |
- } |
- next = _reader.advance(); |
- } |
- if (!hasDigit) { |
- _appendStringToken(TokenType.INT, _reader.getString(start, -2)); |
- if (0x2E == next) { |
- return _selectWithOffset(0x2E, TokenType.PERIOD_PERIOD_PERIOD, |
- TokenType.PERIOD_PERIOD, _reader.offset - 1); |
- } |
- _appendTokenOfTypeWithOffset(TokenType.PERIOD, _reader.offset - 1); |
- return bigSwitch(next); |
- } |
- _appendStringToken( |
- TokenType.DOUBLE, _reader.getString(start, next < 0 ? 0 : -1)); |
- return next; |
- } |
- |
- int _tokenizeGreaterThan(int next) { |
- // > >= >> >>= |
- next = _reader.advance(); |
- if (0x3D == next) { |
- _appendTokenOfType(TokenType.GT_EQ); |
- return _reader.advance(); |
- } else if (0x3E == next) { |
- next = _reader.advance(); |
- if (0x3D == next) { |
- _appendTokenOfType(TokenType.GT_GT_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.GT_GT); |
- return next; |
- } |
- } else { |
- _appendTokenOfType(TokenType.GT); |
- return next; |
- } |
- } |
- |
- int _tokenizeHex(int next) { |
- int start = _reader.offset - 1; |
- bool hasDigits = false; |
- while (true) { |
- next = _reader.advance(); |
- if ((0x30 <= next && next <= 0x39) || |
- (0x41 <= next && next <= 0x46) || |
- (0x61 <= next && next <= 0x66)) { |
- hasDigits = true; |
- } else { |
- if (!hasDigits) { |
- _reportError(ScannerErrorCode.MISSING_HEX_DIGIT); |
- } |
- _appendStringToken( |
- TokenType.HEXADECIMAL, _reader.getString(start, next < 0 ? 0 : -1)); |
- return next; |
- } |
- } |
- } |
- |
- int _tokenizeHexOrNumber(int next) { |
- int x = _reader.peek(); |
- if (x == 0x78 || x == 0x58) { |
- _reader.advance(); |
- return _tokenizeHex(x); |
- } |
- return _tokenizeNumber(next); |
- } |
- |
- int _tokenizeIdentifier(int next, int start, bool allowDollar) { |
- while ((0x61 <= next && next <= 0x7A) || |
- (0x41 <= next && next <= 0x5A) || |
- (0x30 <= next && next <= 0x39) || |
- next == 0x5F || |
- (next == 0x24 && allowDollar)) { |
- next = _reader.advance(); |
- } |
- _appendStringToken( |
- TokenType.IDENTIFIER, _reader.getString(start, next < 0 ? 0 : -1)); |
- return next; |
- } |
- |
- int _tokenizeInterpolatedExpression(int next, int start) { |
- _appendBeginToken(TokenType.STRING_INTERPOLATION_EXPRESSION); |
- next = _reader.advance(); |
- while (next != -1) { |
- if (next == 0x7D) { |
- BeginToken begin = |
- _findTokenMatchingClosingBraceInInterpolationExpression(); |
- if (begin == null) { |
- _beginToken(); |
- _appendTokenOfType(TokenType.CLOSE_CURLY_BRACKET); |
- next = _reader.advance(); |
- _beginToken(); |
- return next; |
- } else if (begin.type == TokenType.OPEN_CURLY_BRACKET) { |
- _beginToken(); |
- _appendEndToken( |
- TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET); |
- next = _reader.advance(); |
- _beginToken(); |
- } else if (begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) { |
- _beginToken(); |
- _appendEndToken(TokenType.CLOSE_CURLY_BRACKET, |
- TokenType.STRING_INTERPOLATION_EXPRESSION); |
- next = _reader.advance(); |
- _beginToken(); |
- return next; |
- } |
- } else { |
- next = bigSwitch(next); |
- } |
- } |
- return next; |
- } |
- |
- int _tokenizeInterpolatedIdentifier(int next, int start) { |
- _appendStringTokenWithOffset( |
- TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 0); |
- if ((0x41 <= next && next <= 0x5A) || |
- (0x61 <= next && next <= 0x7A) || |
- next == 0x5F) { |
- _beginToken(); |
- next = _tokenizeKeywordOrIdentifier(next, false); |
- } |
- _beginToken(); |
- return next; |
- } |
- |
- int _tokenizeKeywordOrIdentifier(int next, bool allowDollar) { |
- KeywordState state = KeywordState.KEYWORD_STATE; |
- int start = _reader.offset; |
- while (state != null && 0x61 <= next && next <= 0x7A) { |
- state = state.next(next); |
- next = _reader.advance(); |
- } |
- if (state == null || state.keyword() == null) { |
- return _tokenizeIdentifier(next, start, allowDollar); |
- } |
- if ((0x41 <= next && next <= 0x5A) || |
- (0x30 <= next && next <= 0x39) || |
- next == 0x5F || |
- next == 0x24) { |
- return _tokenizeIdentifier(next, start, allowDollar); |
- } else if (next < 128) { |
- _appendKeywordToken(state.keyword()); |
- return next; |
- } else { |
- return _tokenizeIdentifier(next, start, allowDollar); |
- } |
- } |
- |
- int _tokenizeLessThan(int next) { |
- // < <= << <<= |
- next = _reader.advance(); |
- if (0x3D == next) { |
- _appendTokenOfType(TokenType.LT_EQ); |
- return _reader.advance(); |
- } else if (0x3C == next) { |
- return _select(0x3D, TokenType.LT_LT_EQ, TokenType.LT_LT); |
- } else { |
- _appendTokenOfType(TokenType.LT); |
- return next; |
- } |
- } |
- |
- int _tokenizeMinus(int next) { |
- // - -- -= |
- next = _reader.advance(); |
- if (next == 0x2D) { |
- _appendTokenOfType(TokenType.MINUS_MINUS); |
- return _reader.advance(); |
- } else if (next == 0x3D) { |
- _appendTokenOfType(TokenType.MINUS_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.MINUS); |
- return next; |
- } |
- } |
- |
- int _tokenizeMultiLineComment(int next) { |
- int nesting = 1; |
- next = _reader.advance(); |
- while (true) { |
- if (-1 == next) { |
- _reportError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT); |
- _appendCommentToken( |
- TokenType.MULTI_LINE_COMMENT, _reader.getString(_tokenStart, 0)); |
- return next; |
- } else if (0x2A == next) { |
- next = _reader.advance(); |
- if (0x2F == next) { |
- --nesting; |
- if (0 == nesting) { |
- _appendCommentToken(TokenType.MULTI_LINE_COMMENT, |
- _reader.getString(_tokenStart, 0)); |
- return _reader.advance(); |
- } else { |
- next = _reader.advance(); |
- } |
- } |
- } else if (0x2F == next) { |
- next = _reader.advance(); |
- if (0x2A == next) { |
- next = _reader.advance(); |
- ++nesting; |
- } |
- } else if (next == 0xD) { |
- next = _reader.advance(); |
- if (next == 0xA) { |
- next = _reader.advance(); |
- } |
- recordStartOfLine(); |
- } else if (next == 0xA) { |
- recordStartOfLine(); |
- next = _reader.advance(); |
- } else { |
- next = _reader.advance(); |
- } |
- } |
- } |
- |
- int _tokenizeMultiLineRawString(int quoteChar, int start) { |
- int next = _reader.advance(); |
- outer: while (next != -1) { |
- while (next != quoteChar) { |
- if (next == -1) { |
- break outer; |
- } else if (next == 0xD) { |
- next = _reader.advance(); |
- if (next == 0xA) { |
- next = _reader.advance(); |
- } |
- recordStartOfLine(); |
- } else if (next == 0xA) { |
- next = _reader.advance(); |
- recordStartOfLine(); |
- } else { |
- next = _reader.advance(); |
- } |
- } |
- next = _reader.advance(); |
- if (next == quoteChar) { |
- next = _reader.advance(); |
- if (next == quoteChar) { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- return _reader.advance(); |
- } |
- } |
- } |
- _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL); |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- return _reader.advance(); |
- } |
- |
- int _tokenizeMultiLineString(int quoteChar, int start, bool raw) { |
- if (raw) { |
- return _tokenizeMultiLineRawString(quoteChar, start); |
- } |
- int next = _reader.advance(); |
- while (next != -1) { |
- if (next == 0x24) { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, -1)); |
- next = _tokenizeStringInterpolation(start); |
- _beginToken(); |
- start = _reader.offset; |
- continue; |
- } |
- if (next == quoteChar) { |
- next = _reader.advance(); |
- if (next == quoteChar) { |
- next = _reader.advance(); |
- if (next == quoteChar) { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- return _reader.advance(); |
- } |
- } |
- continue; |
- } |
- if (next == 0x5C) { |
- next = _reader.advance(); |
- if (next == -1) { |
- break; |
- } |
- if (next == 0xD) { |
- next = _reader.advance(); |
- if (next == 0xA) { |
- next = _reader.advance(); |
- } |
- recordStartOfLine(); |
- } else if (next == 0xA) { |
- recordStartOfLine(); |
- next = _reader.advance(); |
- } else { |
- next = _reader.advance(); |
- } |
- } else if (next == 0xD) { |
- next = _reader.advance(); |
- if (next == 0xA) { |
- next = _reader.advance(); |
- } |
- recordStartOfLine(); |
- } else if (next == 0xA) { |
- recordStartOfLine(); |
- next = _reader.advance(); |
- } else { |
- next = _reader.advance(); |
- } |
- } |
- _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL); |
- if (start == _reader.offset) { |
- _appendStringTokenWithOffset(TokenType.STRING, "", 1); |
- } else { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- } |
- return _reader.advance(); |
- } |
- |
- int _tokenizeMultiply(int next) => |
- _select(0x3D, TokenType.STAR_EQ, TokenType.STAR); |
- |
- int _tokenizeNumber(int next) { |
- int start = _reader.offset; |
- while (true) { |
- next = _reader.advance(); |
- if (0x30 <= next && next <= 0x39) { |
- continue; |
- } else if (next == 0x2E) { |
- return _tokenizeFractionPart(_reader.advance(), start); |
- } else if (next == 0x65 || next == 0x45) { |
- return _tokenizeFractionPart(next, start); |
- } else { |
- _appendStringToken( |
- TokenType.INT, _reader.getString(start, next < 0 ? 0 : -1)); |
- return next; |
- } |
- } |
- } |
- |
- int _tokenizeOpenSquareBracket(int next) { |
- // [ [] []= |
- next = _reader.advance(); |
- if (next == 0x5D) { |
- return _select(0x3D, TokenType.INDEX_EQ, TokenType.INDEX); |
- } else { |
- _appendBeginToken(TokenType.OPEN_SQUARE_BRACKET); |
- return next; |
- } |
- } |
- |
- int _tokenizePercent(int next) => |
- _select(0x3D, TokenType.PERCENT_EQ, TokenType.PERCENT); |
- |
- int _tokenizePlus(int next) { |
- // + ++ += |
- next = _reader.advance(); |
- if (0x2B == next) { |
- _appendTokenOfType(TokenType.PLUS_PLUS); |
- return _reader.advance(); |
- } else if (0x3D == next) { |
- _appendTokenOfType(TokenType.PLUS_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.PLUS); |
- return next; |
- } |
- } |
- |
- int _tokenizeQuestion() { |
- // ? ?. ?? ??= |
- int next = _reader.advance(); |
- if (next == 0x2E) { |
- // '.' |
- _appendTokenOfType(TokenType.QUESTION_PERIOD); |
- return _reader.advance(); |
- } else if (next == 0x3F) { |
- // '?' |
- next = _reader.advance(); |
- if (next == 0x3D) { |
- // '=' |
- _appendTokenOfType(TokenType.QUESTION_QUESTION_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.QUESTION_QUESTION); |
- return next; |
- } |
- } else { |
- _appendTokenOfType(TokenType.QUESTION); |
- return next; |
- } |
- } |
- |
- int _tokenizeSingleLineComment(int next) { |
- while (true) { |
- next = _reader.advance(); |
- if (-1 == next) { |
- _appendCommentToken( |
- TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, 0)); |
- return next; |
- } else if (0xA == next || 0xD == next) { |
- _appendCommentToken( |
- TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, -1)); |
- return next; |
- } |
- } |
- } |
- |
- int _tokenizeSingleLineRawString(int next, int quoteChar, int start) { |
- next = _reader.advance(); |
- while (next != -1) { |
- if (next == quoteChar) { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- return _reader.advance(); |
- } else if (next == 0xD || next == 0xA) { |
- _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL); |
- _appendStringToken(TokenType.STRING, _reader.getString(start, -1)); |
- return _reader.advance(); |
- } |
- next = _reader.advance(); |
- } |
- _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL); |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- return _reader.advance(); |
- } |
- |
- int _tokenizeSingleLineString(int next, int quoteChar, int start) { |
- while (next != quoteChar) { |
- if (next == 0x5C) { |
- next = _reader.advance(); |
- } else if (next == 0x24) { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, -1)); |
- next = _tokenizeStringInterpolation(start); |
- _beginToken(); |
- start = _reader.offset; |
- continue; |
- } |
- if (next <= 0xD && (next == 0xA || next == 0xD || next == -1)) { |
- _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL); |
- if (start == _reader.offset) { |
- _appendStringTokenWithOffset(TokenType.STRING, "", 1); |
- } else if (next == -1) { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- } else { |
- _appendStringToken(TokenType.STRING, _reader.getString(start, -1)); |
- } |
- return _reader.advance(); |
- } |
- next = _reader.advance(); |
- } |
- _appendStringToken(TokenType.STRING, _reader.getString(start, 0)); |
- return _reader.advance(); |
- } |
- |
- int _tokenizeSlashOrComment(int next) { |
- next = _reader.advance(); |
- if (0x2A == next) { |
- return _tokenizeMultiLineComment(next); |
- } else if (0x2F == next) { |
- return _tokenizeSingleLineComment(next); |
- } else if (0x3D == next) { |
- _appendTokenOfType(TokenType.SLASH_EQ); |
- return _reader.advance(); |
- } else { |
- _appendTokenOfType(TokenType.SLASH); |
- return next; |
- } |
- } |
- |
- int _tokenizeString(int next, int start, bool raw) { |
- int quoteChar = next; |
- next = _reader.advance(); |
- if (quoteChar == next) { |
- next = _reader.advance(); |
- if (quoteChar == next) { |
- // Multiline string. |
- return _tokenizeMultiLineString(quoteChar, start, raw); |
- } else { |
- // Empty string. |
- _appendStringToken(TokenType.STRING, _reader.getString(start, -1)); |
- return next; |
- } |
- } |
- if (raw) { |
- return _tokenizeSingleLineRawString(next, quoteChar, start); |
- } else { |
- return _tokenizeSingleLineString(next, quoteChar, start); |
- } |
- } |
- |
- int _tokenizeStringInterpolation(int start) { |
- _beginToken(); |
- int next = _reader.advance(); |
- if (next == 0x7B) { |
- return _tokenizeInterpolatedExpression(next, start); |
- } else { |
- return _tokenizeInterpolatedIdentifier(next, start); |
- } |
- } |
- |
- int _tokenizeTag(int next) { |
- // # or #!.*[\n\r] |
- if (_reader.offset == 0) { |
- if (_reader.peek() == 0x21) { |
- do { |
- next = _reader.advance(); |
- } while (next != 0xA && next != 0xD && next > 0); |
- _appendStringToken( |
- TokenType.SCRIPT_TAG, _reader.getString(_tokenStart, 0)); |
- return next; |
- } |
- } |
- _appendTokenOfType(TokenType.HASH); |
- return _reader.advance(); |
- } |
- |
- int _tokenizeTilde(int next) { |
- // ~ ~/ ~/= |
- next = _reader.advance(); |
- if (next == 0x2F) { |
- return _select(0x3D, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH); |
- } else { |
- _appendTokenOfType(TokenType.TILDE); |
- return next; |
- } |
- } |
- |
- /** |
- * Checks if [value] is a single-line or multi-line comment. |
- */ |
- static bool _isDocumentationComment(String value) { |
- return StringUtilities.startsWith3(value, 0, 0x2F, 0x2F, 0x2F) || |
- StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x2A); |
- } |
-} |
- |
-/** |
- * The error codes used for errors detected by the scanner. |
- */ |
-class ScannerErrorCode extends ErrorCode { |
- static const ScannerErrorCode ILLEGAL_CHARACTER = |
- const ScannerErrorCode('ILLEGAL_CHARACTER', "Illegal character {0}"); |
- |
- static const ScannerErrorCode MISSING_DIGIT = |
- const ScannerErrorCode('MISSING_DIGIT', "Decimal digit expected"); |
- |
- static const ScannerErrorCode MISSING_HEX_DIGIT = |
- const ScannerErrorCode('MISSING_HEX_DIGIT', "Hexidecimal digit expected"); |
- |
- static const ScannerErrorCode MISSING_QUOTE = |
- const ScannerErrorCode('MISSING_QUOTE', "Expected quote (' or \")"); |
- |
- static const ScannerErrorCode UNABLE_GET_CONTENT = const ScannerErrorCode( |
- 'UNABLE_GET_CONTENT', "Unable to get content: {0}"); |
- |
- static const ScannerErrorCode UNTERMINATED_MULTI_LINE_COMMENT = |
- const ScannerErrorCode( |
- 'UNTERMINATED_MULTI_LINE_COMMENT', "Unterminated multi-line comment"); |
- |
- static const ScannerErrorCode UNTERMINATED_STRING_LITERAL = |
- const ScannerErrorCode( |
- 'UNTERMINATED_STRING_LITERAL', "Unterminated string literal"); |
- |
- /** |
- * Initialize a newly created error code to have the given [name]. The message |
- * associated with the error will be created from the given [message] |
- * template. The correction associated with the error will be created from the |
- * given [correction] template. |
- */ |
- const ScannerErrorCode(String name, String message, [String correction]) |
- : super(name, message, correction); |
- |
- @override |
- ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; |
- |
- @override |
- ErrorType get type => ErrorType.SYNTACTIC_ERROR; |
-} |
- |
-/** |
- * A token whose value is independent of it's type. |
- */ |
-class StringToken extends Token { |
- /** |
- * The lexeme represented by this token. |
- */ |
- String _value; |
- |
- /** |
- * Initialize a newly created token to represent a token of the given [type] |
- * with the given [value] at the given [offset]. |
- */ |
- StringToken(TokenType type, String value, int offset) : super(type, offset) { |
- this._value = StringUtilities.intern(value); |
- } |
- |
- @override |
- String get lexeme => _value; |
- |
- @override |
- Token copy() => new StringToken(type, _value, offset); |
- |
- @override |
- String value() => _value; |
-} |
- |
-/** |
- * A string token that is preceded by comments. |
- */ |
-class StringTokenWithComment extends StringToken { |
- /** |
- * The first comment in the list of comments that precede this token. |
- */ |
- CommentToken _precedingComment; |
- |
- /** |
- * Initialize a newly created token to have the given [type] at the given |
- * [offset] and to be preceded by the comments reachable from the given |
- * [comment]. |
- */ |
- StringTokenWithComment( |
- TokenType type, String value, int offset, this._precedingComment) |
- : super(type, value, offset) { |
- _setCommentParent(_precedingComment); |
- } |
- |
- CommentToken get precedingComments => _precedingComment; |
- |
- void set precedingComments(CommentToken comment) { |
- _precedingComment = comment; |
- _setCommentParent(_precedingComment); |
- } |
- |
- @override |
- void applyDelta(int delta) { |
- super.applyDelta(delta); |
- Token token = precedingComments; |
- while (token != null) { |
- token.applyDelta(delta); |
- token = token.next; |
- } |
- } |
- |
- @override |
- Token copy() => new StringTokenWithComment( |
- type, lexeme, offset, copyComments(precedingComments)); |
-} |
- |
-/** |
- * A [CharacterReader] that reads characters from a character sequence, but adds |
- * a delta when reporting the current character offset so that the character |
- * sequence can be a subsequence from a larger sequence. |
- */ |
-class SubSequenceReader extends CharSequenceReader { |
- /** |
- * The offset from the beginning of the file to the beginning of the source |
- * being scanned. |
- */ |
- final int _offsetDelta; |
- |
- /** |
- * Initialize a newly created reader to read the characters in the given |
- * [sequence]. The [_offsetDelta] is the offset from the beginning of the file |
- * to the beginning of the source being scanned |
- */ |
- SubSequenceReader(String sequence, this._offsetDelta) : super(sequence); |
- |
- @override |
- int get offset => _offsetDelta + super.offset; |
- |
- @override |
- void set offset(int offset) { |
- super.offset = offset - _offsetDelta; |
- } |
- |
- @override |
- String getString(int start, int endDelta) => |
- super.getString(start - _offsetDelta, endDelta); |
-} |
- |
-/** |
- * A token whose value is independent of it's type. |
- */ |
-class SyntheticStringToken extends StringToken { |
- /** |
- * Initialize a newly created token to represent a token of the given [type] |
- * with the given [value] at the given [offset]. |
- */ |
- SyntheticStringToken(TokenType type, String value, int offset) |
- : super(type, value, offset); |
- |
- @override |
- bool get isSynthetic => true; |
-} |
- |
-/** |
- * A token that was scanned from the input. Each token knows which tokens |
- * precede and follow it, acting as a link in a doubly linked list of tokens. |
- */ |
-class Token { |
- /** |
- * The type of the token. |
- */ |
- final TokenType type; |
- |
- /** |
- * The offset from the beginning of the file to the first character in the |
- * token. |
- */ |
- int offset = 0; |
- |
- /** |
- * The previous token in the token stream. |
- */ |
- Token previous; |
- |
- /** |
- * The next token in the token stream. |
- */ |
- Token _next; |
- |
- /** |
- * Initialize a newly created token to have the given [type] and [offset]. |
- */ |
- Token(this.type, int offset) { |
- this.offset = offset; |
- } |
- |
- /** |
- * Return the offset from the beginning of the file to the character after the |
- * last character of the token. |
- */ |
- int get end => offset + length; |
- |
- /** |
- * Return `true` if this token represents an operator. |
- */ |
- bool get isOperator => type.isOperator; |
- |
- /** |
- * Return `true` if this token is a synthetic token. A synthetic token is a |
- * token that was introduced by the parser in order to recover from an error |
- * in the code. |
- */ |
- bool get isSynthetic => length == 0; |
- |
- /** |
- * Return `true` if this token represents an operator that can be defined by |
- * users. |
- */ |
- bool get isUserDefinableOperator => type.isUserDefinableOperator; |
- |
- /** |
- * Return the number of characters in the node's source range. |
- */ |
- int get length => lexeme.length; |
- |
- /** |
- * Return the lexeme that represents this token. |
- */ |
- String get lexeme => type.lexeme; |
- |
- /** |
- * Return the next token in the token stream. |
- */ |
- Token get next => _next; |
- |
- /** |
- * Return the first comment in the list of comments that precede this token, |
- * or `null` if there are no comments preceding this token. Additional |
- * comments can be reached by following the token stream using [next] until |
- * `null` is returned. |
- * |
- * For example, if the original contents were "/* one */ /* two */ id", then |
- * the first preceding comment token will have a lexeme of "/* one */" and |
- * the next comment token will have a lexeme of "/* two */". |
- */ |
- CommentToken get precedingComments => null; |
- |
- /** |
- * Apply (add) the given [delta] to this token's offset. |
- */ |
- void applyDelta(int delta) { |
- offset += delta; |
- } |
- |
- /** |
- * Return a newly created token that is a copy of this token but that is not a |
- * part of any token stream. |
- */ |
- Token copy() => new Token(type, offset); |
- |
- /** |
- * Copy a linked list of comment tokens identical to the given comment tokens. |
- */ |
- Token copyComments(Token token) { |
- if (token == null) { |
- return null; |
- } |
- Token head = token.copy(); |
- Token tail = head; |
- token = token.next; |
- while (token != null) { |
- tail = tail.setNext(token.copy()); |
- token = token.next; |
- } |
- return head; |
- } |
- |
- /** |
- * Return `true` if this token has any one of the given [types]. |
- */ |
- bool matchesAny(List<TokenType> types) { |
- for (TokenType type in types) { |
- if (this.type == type) { |
- return true; |
- } |
- } |
- return false; |
- } |
- |
- /** |
- * Set the next token in the token stream to the given [token]. This has the |
- * side-effect of setting this token to be the previous token for the given |
- * token. Return the token that was passed in. |
- */ |
- Token setNext(Token token) { |
- _next = token; |
- token.previous = this; |
- return token; |
- } |
- |
- /** |
- * Set the next token in the token stream to the given token without changing |
- * which token is the previous token for the given token. Return the token |
- * that was passed in. |
- */ |
- Token setNextWithoutSettingPrevious(Token token) { |
- _next = token; |
- return token; |
- } |
- |
- @override |
- String toString() => lexeme; |
- |
- /** |
- * Return the value of this token. For keyword tokens, this is the keyword |
- * associated with the token, for other tokens it is the lexeme associated |
- * with the token. |
- */ |
- Object value() => type.lexeme; |
- |
- /** |
- * Sets the `parent` property to `this` for the given [comment] and all the |
- * next tokens. |
- */ |
- void _setCommentParent(CommentToken comment) { |
- while (comment != null) { |
- comment.parent = this; |
- comment = comment.next; |
- } |
- } |
- |
- /** |
- * Compare the given [tokens] to find the token that appears first in the |
- * source being parsed. That is, return the left-most of all of the tokens. |
- * The list must be non-`null`, but the elements of the list are allowed to be |
- * `null`. Return the token with the smallest offset, or `null` if the list is |
- * empty or if all of the elements of the list are `null`. |
- */ |
- static Token lexicallyFirst(List<Token> tokens) { |
- Token first = null; |
- int offset = -1; |
- for (Token token in tokens) { |
- if (token != null && (offset < 0 || token.offset < offset)) { |
- first = token; |
- offset = token.offset; |
- } |
- } |
- return first; |
- } |
-} |
- |
-/** |
- * The classes (or groups) of tokens with a similar use. |
- */ |
-class TokenClass { |
- /** |
- * A value used to indicate that the token type is not part of any specific |
- * class of token. |
- */ |
- static const TokenClass NO_CLASS = const TokenClass('NO_CLASS'); |
- |
- /** |
- * A value used to indicate that the token type is an additive operator. |
- */ |
- static const TokenClass ADDITIVE_OPERATOR = |
- const TokenClass('ADDITIVE_OPERATOR', 13); |
- |
- /** |
- * A value used to indicate that the token type is an assignment operator. |
- */ |
- static const TokenClass ASSIGNMENT_OPERATOR = |
- const TokenClass('ASSIGNMENT_OPERATOR', 1); |
- |
- /** |
- * A value used to indicate that the token type is a bitwise-and operator. |
- */ |
- static const TokenClass BITWISE_AND_OPERATOR = |
- const TokenClass('BITWISE_AND_OPERATOR', 11); |
- |
- /** |
- * A value used to indicate that the token type is a bitwise-or operator. |
- */ |
- static const TokenClass BITWISE_OR_OPERATOR = |
- const TokenClass('BITWISE_OR_OPERATOR', 9); |
- |
- /** |
- * A value used to indicate that the token type is a bitwise-xor operator. |
- */ |
- static const TokenClass BITWISE_XOR_OPERATOR = |
- const TokenClass('BITWISE_XOR_OPERATOR', 10); |
- |
- /** |
- * A value used to indicate that the token type is a cascade operator. |
- */ |
- static const TokenClass CASCADE_OPERATOR = |
- const TokenClass('CASCADE_OPERATOR', 2); |
- |
- /** |
- * A value used to indicate that the token type is a conditional operator. |
- */ |
- static const TokenClass CONDITIONAL_OPERATOR = |
- const TokenClass('CONDITIONAL_OPERATOR', 3); |
- |
- /** |
- * A value used to indicate that the token type is an equality operator. |
- */ |
- static const TokenClass EQUALITY_OPERATOR = |
- const TokenClass('EQUALITY_OPERATOR', 7); |
- |
- /** |
- * A value used to indicate that the token type is an if-null operator. |
- */ |
- static const TokenClass IF_NULL_OPERATOR = |
- const TokenClass('IF_NULL_OPERATOR', 4); |
- |
- /** |
- * A value used to indicate that the token type is a logical-and operator. |
- */ |
- static const TokenClass LOGICAL_AND_OPERATOR = |
- const TokenClass('LOGICAL_AND_OPERATOR', 6); |
- |
- /** |
- * A value used to indicate that the token type is a logical-or operator. |
- */ |
- static const TokenClass LOGICAL_OR_OPERATOR = |
- const TokenClass('LOGICAL_OR_OPERATOR', 5); |
- |
- /** |
- * A value used to indicate that the token type is a multiplicative operator. |
- */ |
- static const TokenClass MULTIPLICATIVE_OPERATOR = |
- const TokenClass('MULTIPLICATIVE_OPERATOR', 14); |
- |
- /** |
- * A value used to indicate that the token type is a relational operator. |
- */ |
- static const TokenClass RELATIONAL_OPERATOR = |
- const TokenClass('RELATIONAL_OPERATOR', 8); |
- |
- /** |
- * A value used to indicate that the token type is a shift operator. |
- */ |
- static const TokenClass SHIFT_OPERATOR = |
- const TokenClass('SHIFT_OPERATOR', 12); |
- |
- /** |
- * A value used to indicate that the token type is a unary operator. |
- */ |
- static const TokenClass UNARY_POSTFIX_OPERATOR = |
- const TokenClass('UNARY_POSTFIX_OPERATOR', 16); |
- |
- /** |
- * A value used to indicate that the token type is a unary operator. |
- */ |
- static const TokenClass UNARY_PREFIX_OPERATOR = |
- const TokenClass('UNARY_PREFIX_OPERATOR', 15); |
- |
- /** |
- * The name of the token class. |
- */ |
- final String name; |
- |
- /** |
- * The precedence of tokens of this class, or `0` if the such tokens do not |
- * represent an operator. |
- */ |
- final int precedence; |
- |
- const TokenClass(this.name, [this.precedence = 0]); |
- |
- @override |
- String toString() => name; |
-} |
- |
-/** |
- * The types of tokens that can be returned by the scanner. |
- */ |
-class TokenType { |
- /** |
- * The type of the token that marks the end of the input. |
- */ |
- static const TokenType EOF = const TokenType_EOF('EOF'); |
- |
- static const TokenType DOUBLE = const TokenType('DOUBLE'); |
- |
- static const TokenType HEXADECIMAL = const TokenType('HEXADECIMAL'); |
- |
- static const TokenType IDENTIFIER = const TokenType('IDENTIFIER'); |
- |
- static const TokenType INT = const TokenType('INT'); |
- |
- static const TokenType KEYWORD = const TokenType('KEYWORD'); |
- |
- static const TokenType MULTI_LINE_COMMENT = |
- const TokenType('MULTI_LINE_COMMENT'); |
- |
- static const TokenType SCRIPT_TAG = const TokenType('SCRIPT_TAG'); |
- |
- static const TokenType SINGLE_LINE_COMMENT = |
- const TokenType('SINGLE_LINE_COMMENT'); |
- |
- static const TokenType STRING = const TokenType('STRING'); |
- |
- static const TokenType AMPERSAND = |
- const TokenType('AMPERSAND', TokenClass.BITWISE_AND_OPERATOR, "&"); |
- |
- static const TokenType AMPERSAND_AMPERSAND = const TokenType( |
- 'AMPERSAND_AMPERSAND', TokenClass.LOGICAL_AND_OPERATOR, "&&"); |
- |
- static const TokenType AMPERSAND_EQ = |
- const TokenType('AMPERSAND_EQ', TokenClass.ASSIGNMENT_OPERATOR, "&="); |
- |
- static const TokenType AT = const TokenType('AT', TokenClass.NO_CLASS, "@"); |
- |
- static const TokenType BANG = |
- const TokenType('BANG', TokenClass.UNARY_PREFIX_OPERATOR, "!"); |
- |
- static const TokenType BANG_EQ = |
- const TokenType('BANG_EQ', TokenClass.EQUALITY_OPERATOR, "!="); |
- |
- static const TokenType BAR = |
- const TokenType('BAR', TokenClass.BITWISE_OR_OPERATOR, "|"); |
- |
- static const TokenType BAR_BAR = |
- const TokenType('BAR_BAR', TokenClass.LOGICAL_OR_OPERATOR, "||"); |
- |
- static const TokenType BAR_EQ = |
- const TokenType('BAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "|="); |
- |
- static const TokenType COLON = |
- const TokenType('COLON', TokenClass.NO_CLASS, ":"); |
- |
- static const TokenType COMMA = |
- const TokenType('COMMA', TokenClass.NO_CLASS, ","); |
- |
- static const TokenType CARET = |
- const TokenType('CARET', TokenClass.BITWISE_XOR_OPERATOR, "^"); |
- |
- static const TokenType CARET_EQ = |
- const TokenType('CARET_EQ', TokenClass.ASSIGNMENT_OPERATOR, "^="); |
- |
- static const TokenType CLOSE_CURLY_BRACKET = |
- const TokenType('CLOSE_CURLY_BRACKET', TokenClass.NO_CLASS, "}"); |
- |
- static const TokenType CLOSE_PAREN = |
- const TokenType('CLOSE_PAREN', TokenClass.NO_CLASS, ")"); |
- |
- static const TokenType CLOSE_SQUARE_BRACKET = |
- const TokenType('CLOSE_SQUARE_BRACKET', TokenClass.NO_CLASS, "]"); |
- |
- static const TokenType EQ = |
- const TokenType('EQ', TokenClass.ASSIGNMENT_OPERATOR, "="); |
- |
- static const TokenType EQ_EQ = |
- const TokenType('EQ_EQ', TokenClass.EQUALITY_OPERATOR, "=="); |
- |
- static const TokenType FUNCTION = |
- const TokenType('FUNCTION', TokenClass.NO_CLASS, "=>"); |
- |
- static const TokenType GT = |
- const TokenType('GT', TokenClass.RELATIONAL_OPERATOR, ">"); |
- |
- static const TokenType GT_EQ = |
- const TokenType('GT_EQ', TokenClass.RELATIONAL_OPERATOR, ">="); |
- |
- static const TokenType GT_GT = |
- const TokenType('GT_GT', TokenClass.SHIFT_OPERATOR, ">>"); |
- |
- static const TokenType GT_GT_EQ = |
- const TokenType('GT_GT_EQ', TokenClass.ASSIGNMENT_OPERATOR, ">>="); |
- |
- static const TokenType HASH = |
- const TokenType('HASH', TokenClass.NO_CLASS, "#"); |
- |
- static const TokenType INDEX = |
- const TokenType('INDEX', TokenClass.UNARY_POSTFIX_OPERATOR, "[]"); |
- |
- static const TokenType INDEX_EQ = |
- const TokenType('INDEX_EQ', TokenClass.UNARY_POSTFIX_OPERATOR, "[]="); |
- |
- static const TokenType IS = |
- const TokenType('IS', TokenClass.RELATIONAL_OPERATOR, "is"); |
- |
- static const TokenType LT = |
- const TokenType('LT', TokenClass.RELATIONAL_OPERATOR, "<"); |
- |
- static const TokenType LT_EQ = |
- const TokenType('LT_EQ', TokenClass.RELATIONAL_OPERATOR, "<="); |
- |
- static const TokenType LT_LT = |
- const TokenType('LT_LT', TokenClass.SHIFT_OPERATOR, "<<"); |
- |
- static const TokenType LT_LT_EQ = |
- const TokenType('LT_LT_EQ', TokenClass.ASSIGNMENT_OPERATOR, "<<="); |
- |
- static const TokenType MINUS = |
- const TokenType('MINUS', TokenClass.ADDITIVE_OPERATOR, "-"); |
- |
- static const TokenType MINUS_EQ = |
- const TokenType('MINUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, "-="); |
- |
- static const TokenType MINUS_MINUS = |
- const TokenType('MINUS_MINUS', TokenClass.UNARY_PREFIX_OPERATOR, "--"); |
- |
- static const TokenType OPEN_CURLY_BRACKET = |
- const TokenType('OPEN_CURLY_BRACKET', TokenClass.NO_CLASS, "{"); |
- |
- static const TokenType OPEN_PAREN = |
- const TokenType('OPEN_PAREN', TokenClass.UNARY_POSTFIX_OPERATOR, "("); |
- |
- static const TokenType OPEN_SQUARE_BRACKET = const TokenType( |
- 'OPEN_SQUARE_BRACKET', TokenClass.UNARY_POSTFIX_OPERATOR, "["); |
- |
- static const TokenType PERCENT = |
- const TokenType('PERCENT', TokenClass.MULTIPLICATIVE_OPERATOR, "%"); |
- |
- static const TokenType PERCENT_EQ = |
- const TokenType('PERCENT_EQ', TokenClass.ASSIGNMENT_OPERATOR, "%="); |
- |
- static const TokenType PERIOD = |
- const TokenType('PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, "."); |
- |
- static const TokenType PERIOD_PERIOD = |
- const TokenType('PERIOD_PERIOD', TokenClass.CASCADE_OPERATOR, ".."); |
- |
- static const TokenType PLUS = |
- const TokenType('PLUS', TokenClass.ADDITIVE_OPERATOR, "+"); |
- |
- static const TokenType PLUS_EQ = |
- const TokenType('PLUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, "+="); |
- |
- static const TokenType PLUS_PLUS = |
- const TokenType('PLUS_PLUS', TokenClass.UNARY_PREFIX_OPERATOR, "++"); |
- |
- static const TokenType QUESTION = |
- const TokenType('QUESTION', TokenClass.CONDITIONAL_OPERATOR, "?"); |
- |
- static const TokenType QUESTION_PERIOD = const TokenType( |
- 'QUESTION_PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, '?.'); |
- |
- static const TokenType QUESTION_QUESTION = |
- const TokenType('QUESTION_QUESTION', TokenClass.IF_NULL_OPERATOR, '??'); |
- |
- static const TokenType QUESTION_QUESTION_EQ = const TokenType( |
- 'QUESTION_QUESTION_EQ', TokenClass.ASSIGNMENT_OPERATOR, '??='); |
- |
- static const TokenType SEMICOLON = |
- const TokenType('SEMICOLON', TokenClass.NO_CLASS, ";"); |
- |
- static const TokenType SLASH = |
- const TokenType('SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, "/"); |
- |
- static const TokenType SLASH_EQ = |
- const TokenType('SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, "/="); |
- |
- static const TokenType STAR = |
- const TokenType('STAR', TokenClass.MULTIPLICATIVE_OPERATOR, "*"); |
- |
- static const TokenType STAR_EQ = |
- const TokenType('STAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "*="); |
- |
- static const TokenType STRING_INTERPOLATION_EXPRESSION = const TokenType( |
- 'STRING_INTERPOLATION_EXPRESSION', TokenClass.NO_CLASS, "\${"); |
- |
- static const TokenType STRING_INTERPOLATION_IDENTIFIER = const TokenType( |
- 'STRING_INTERPOLATION_IDENTIFIER', TokenClass.NO_CLASS, "\$"); |
- |
- static const TokenType TILDE = |
- const TokenType('TILDE', TokenClass.UNARY_PREFIX_OPERATOR, "~"); |
- |
- static const TokenType TILDE_SLASH = |
- const TokenType('TILDE_SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, "~/"); |
- |
- static const TokenType TILDE_SLASH_EQ = |
- const TokenType('TILDE_SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, "~/="); |
- |
- static const TokenType BACKPING = |
- const TokenType('BACKPING', TokenClass.NO_CLASS, "`"); |
- |
- static const TokenType BACKSLASH = |
- const TokenType('BACKSLASH', TokenClass.NO_CLASS, "\\"); |
- |
- static const TokenType PERIOD_PERIOD_PERIOD = |
- const TokenType('PERIOD_PERIOD_PERIOD', TokenClass.NO_CLASS, "..."); |
- |
- /** |
- * The class of the token. |
- */ |
- final TokenClass _tokenClass; |
- |
- /** |
- * The name of the token type. |
- */ |
- final String name; |
- |
- /** |
- * The lexeme that defines this type of token, or `null` if there is more than |
- * one possible lexeme for this type of token. |
- */ |
- final String lexeme; |
- |
- const TokenType(this.name, |
- [this._tokenClass = TokenClass.NO_CLASS, this.lexeme = null]); |
- |
- /** |
- * Return `true` if this type of token represents an additive operator. |
- */ |
- bool get isAdditiveOperator => _tokenClass == TokenClass.ADDITIVE_OPERATOR; |
- |
- /** |
- * Return `true` if this type of token represents an assignment operator. |
- */ |
- bool get isAssignmentOperator => |
- _tokenClass == TokenClass.ASSIGNMENT_OPERATOR; |
- |
- /** |
- * Return `true` if this type of token represents an associative operator. An |
- * associative operator is an operator for which the following equality is |
- * true: `(a * b) * c == a * (b * c)`. In other words, if the result of |
- * applying the operator to multiple operands does not depend on the order in |
- * which those applications occur. |
- * |
- * Note: This method considers the logical-and and logical-or operators to be |
- * associative, even though the order in which the application of those |
- * operators can have an effect because evaluation of the right-hand operand |
- * is conditional. |
- */ |
- bool get isAssociativeOperator => this == AMPERSAND || |
- this == AMPERSAND_AMPERSAND || |
- this == BAR || |
- this == BAR_BAR || |
- this == CARET || |
- this == PLUS || |
- this == STAR; |
- |
- /** |
- * Return `true` if this type of token represents an equality operator. |
- */ |
- bool get isEqualityOperator => _tokenClass == TokenClass.EQUALITY_OPERATOR; |
- |
- /** |
- * Return `true` if this type of token represents an increment operator. |
- */ |
- bool get isIncrementOperator => |
- identical(lexeme, "++") || identical(lexeme, "--"); |
- |
- /** |
- * Return `true` if this type of token represents a multiplicative operator. |
- */ |
- bool get isMultiplicativeOperator => |
- _tokenClass == TokenClass.MULTIPLICATIVE_OPERATOR; |
- |
- /** |
- * Return `true` if this token type represents an operator. |
- */ |
- bool get isOperator => _tokenClass != TokenClass.NO_CLASS && |
- this != OPEN_PAREN && |
- this != OPEN_SQUARE_BRACKET && |
- this != PERIOD; |
- |
- /** |
- * Return `true` if this type of token represents a relational operator. |
- */ |
- bool get isRelationalOperator => |
- _tokenClass == TokenClass.RELATIONAL_OPERATOR; |
- |
- /** |
- * Return `true` if this type of token represents a shift operator. |
- */ |
- bool get isShiftOperator => _tokenClass == TokenClass.SHIFT_OPERATOR; |
- |
- /** |
- * Return `true` if this type of token represents a unary postfix operator. |
- */ |
- bool get isUnaryPostfixOperator => |
- _tokenClass == TokenClass.UNARY_POSTFIX_OPERATOR; |
- |
- /** |
- * Return `true` if this type of token represents a unary prefix operator. |
- */ |
- bool get isUnaryPrefixOperator => |
- _tokenClass == TokenClass.UNARY_PREFIX_OPERATOR; |
- |
- /** |
- * Return `true` if this token type represents an operator that can be defined |
- * by users. |
- */ |
- bool get isUserDefinableOperator => identical(lexeme, "==") || |
- identical(lexeme, "~") || |
- identical(lexeme, "[]") || |
- identical(lexeme, "[]=") || |
- identical(lexeme, "*") || |
- identical(lexeme, "/") || |
- identical(lexeme, "%") || |
- identical(lexeme, "~/") || |
- identical(lexeme, "+") || |
- identical(lexeme, "-") || |
- identical(lexeme, "<<") || |
- identical(lexeme, ">>") || |
- identical(lexeme, ">=") || |
- identical(lexeme, ">") || |
- identical(lexeme, "<=") || |
- identical(lexeme, "<") || |
- identical(lexeme, "&") || |
- identical(lexeme, "^") || |
- identical(lexeme, "|"); |
- |
- /** |
- * Return the precedence of the token, or `0` if the token does not represent |
- * an operator. |
- */ |
- int get precedence => _tokenClass.precedence; |
- |
- @override |
- String toString() => name; |
-} |
- |
-class TokenType_EOF extends TokenType { |
- const TokenType_EOF(String name) : super(name, TokenClass.NO_CLASS, ""); |
- |
- @override |
- String toString() => "-eof-"; |
-} |
- |
-/** |
- * A normal token that is preceded by comments. |
- */ |
-class TokenWithComment extends Token { |
- /** |
- * The first comment in the list of comments that precede this token. |
- */ |
- CommentToken _precedingComment; |
- |
- /** |
- * Initialize a newly created token to have the given [type] at the given |
- * [offset] and to be preceded by the comments reachable from the given |
- * [comment]. |
- */ |
- TokenWithComment(TokenType type, int offset, this._precedingComment) |
- : super(type, offset) { |
- _setCommentParent(_precedingComment); |
- } |
- |
- CommentToken get precedingComments => _precedingComment; |
- |
- void set precedingComments(CommentToken comment) { |
- _precedingComment = comment; |
- _setCommentParent(_precedingComment); |
- } |
- |
- @override |
- Token copy() => new TokenWithComment(type, offset, precedingComments); |
-} |