Linter Demo Errors: 4Warnings: 3File: /home/fstrocco/Dart/dart/benchmark/compiler/lib/src/scanner/token.dart // Copyright (c) 2011, 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. part of scanner; const int EOF_TOKEN = 0; const int KEYWORD_TOKEN = $k; const int IDENTIFIER_TOKEN = $a; const int BAD_INPUT_TOKEN = $X; const int DOUBLE_TOKEN = $d; const int INT_TOKEN = $i; const int HEXADECIMAL_TOKEN = $x; const int STRING_TOKEN = $SQ; const int AMPERSAND_TOKEN = $AMPERSAND; const int BACKPING_TOKEN = $BACKPING; const int BACKSLASH_TOKEN = $BACKSLASH; const int BANG_TOKEN = $BANG; const int BAR_TOKEN = $BAR; const int COLON_TOKEN = $COLON; const int COMMA_TOKEN = $COMMA; const int EQ_TOKEN = $EQ; const int GT_TOKEN = $GT; const int HASH_TOKEN = $HASH; const int OPEN_CURLY_BRACKET_TOKEN = $OPEN_CURLY_BRACKET; const int OPEN_SQUARE_BRACKET_TOKEN = $OPEN_SQUARE_BRACKET; const int OPEN_PAREN_TOKEN = $OPEN_PAREN; const int LT_TOKEN = $LT; const int MINUS_TOKEN = $MINUS; const int PERIOD_TOKEN = $PERIOD; const int PLUS_TOKEN = $PLUS; const int QUESTION_TOKEN = $QUESTION; const int AT_TOKEN = $AT; const int CLOSE_CURLY_BRACKET_TOKEN = $CLOSE_CURLY_BRACKET; const int CLOSE_SQUARE_BRACKET_TOKEN = $CLOSE_SQUARE_BRACKET; const int CLOSE_PAREN_TOKEN = $CLOSE_PAREN; const int SEMICOLON_TOKEN = $SEMICOLON; const int SLASH_TOKEN = $SLASH; const int TILDE_TOKEN = $TILDE; const int STAR_TOKEN = $STAR; const int PERCENT_TOKEN = $PERCENT; const int CARET_TOKEN = $CARET; const int STRING_INTERPOLATION_TOKEN = 128; const int LT_EQ_TOKEN = STRING_INTERPOLATION_TOKEN + 1; const int FUNCTION_TOKEN = LT_EQ_TOKEN + 1; const int SLASH_EQ_TOKEN = FUNCTION_TOKEN + 1; const int PERIOD_PERIOD_PERIOD_TOKEN = SLASH_EQ_TOKEN + 1; const int PERIOD_PERIOD_TOKEN = PERIOD_PERIOD_PERIOD_TOKEN + 1; const int EQ_EQ_EQ_TOKEN = PERIOD_PERIOD_TOKEN + 1; const int EQ_EQ_TOKEN = EQ_EQ_EQ_TOKEN + 1; const int LT_LT_EQ_TOKEN = EQ_EQ_TOKEN + 1; const int LT_LT_TOKEN = LT_LT_EQ_TOKEN + 1; const int GT_EQ_TOKEN = LT_LT_TOKEN + 1; const int GT_GT_EQ_TOKEN = GT_EQ_TOKEN + 1; const int INDEX_EQ_TOKEN = GT_GT_EQ_TOKEN + 1; const int INDEX_TOKEN = INDEX_EQ_TOKEN + 1; const int BANG_EQ_EQ_TOKEN = INDEX_TOKEN + 1; const int BANG_EQ_TOKEN = BANG_EQ_EQ_TOKEN + 1; const int AMPERSAND_AMPERSAND_TOKEN = BANG_EQ_TOKEN + 1; const int AMPERSAND_EQ_TOKEN = AMPERSAND_AMPERSAND_TOKEN + 1; const int BAR_BAR_TOKEN = AMPERSAND_EQ_TOKEN + 1; const int BAR_EQ_TOKEN = BAR_BAR_TOKEN + 1; const int STAR_EQ_TOKEN = BAR_EQ_TOKEN + 1; const int PLUS_PLUS_TOKEN = STAR_EQ_TOKEN + 1; const int PLUS_EQ_TOKEN = PLUS_PLUS_TOKEN + 1; const int MINUS_MINUS_TOKEN = PLUS_EQ_TOKEN + 1; const int MINUS_EQ_TOKEN = MINUS_MINUS_TOKEN + 1; const int TILDE_SLASH_EQ_TOKEN = MINUS_EQ_TOKEN + 1; const int TILDE_SLASH_TOKEN = TILDE_SLASH_EQ_TOKEN + 1; const int PERCENT_EQ_TOKEN = TILDE_SLASH_TOKEN + 1; const int GT_GT_TOKEN = PERCENT_EQ_TOKEN + 1; const int CARET_EQ_TOKEN = GT_GT_TOKEN + 1; const int COMMENT_TOKEN = CARET_EQ_TOKEN + 1; const int STRING_INTERPOLATION_IDENTIFIER_TOKEN = COMMENT_TOKEN + 1; /** * A token that doubles as a linked list. */ abstract class Token implements Spannable { /** * The character offset of the start of this token within the source text. */ final int charOffset; Token(this.charOffset); /** * The next token in the token stream. */ Token next; /** * The precedence info for this token. [info] determines the kind and the * precedence level of this token. * * Defined as getter to save a field in the [KeywordToken] subclass. */ PrecedenceInfo get info; /** * The string represented by this token, a substring of the source code. * * For [StringToken]s the [value] includes the quotes, explicit escapes, etc. */ String get value; /** * For symbol and keyword tokens, returns the string value represented by this * token. For [StringToken]s this method returns [:null:]. * * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time * constant originating in the [PrecedenceInfo] or in the [Keyword] instance. * This allows testing for keywords and symbols using [:identical:], e.g., * [:identical('class', token.value):]. * * Note that returning [:null:] for string tokens is important to identify * symbols and keywords, we cannot use [value] instead. The string literal * "$a($b" * produces ..., SymbolToken($), StringToken(a), StringToken((), ... * * After parsing the identifier 'a', the parser tests for a function * declaration using [:identical(next.stringValue, '('):], which (rihgtfully) * returns false because stringValue returns [:null:]. */ String get stringValue; /** * The kind enum of this token as determined by its [info]. */ int get kind => info.kind; /** * The precedence level for this token. */ int get precedence => info.precedence; /** * True if this token is an identifier. Some keywords allowed as identifiers, * see implementation in [KeywordToken]. */ bool isIdentifier(); /** * Returns a textual representation of this token to be used for debugging * purposes. The resulting string might contain information about the * structure of the token, for example 'StringToken(foo)' for the identifier * token 'foo'. * * Use [value] for the text actually parsed by the token. */ String toString(); /** * The number of characters parsed by this token. */ int get charCount { if (info == BAD_INPUT_INFO) { // This is a token that wraps around an error message. Return 1 // instead of the size of the length of the error message. return 1; } else { return value.length; } } int get hashCode => computeHashCode(charOffset, info, value); } /// A pair of tokens marking the beginning and the end of a span. Use for error /// reporting. class TokenPair implements Spannable { final Token begin; final Token end; TokenPair(this.begin, this.end); } /** * A [SymbolToken] represents the symbol in its precendence info. * Also used for end of file with EOF_INFO. */ class SymbolToken extends Token { final PrecedenceInfo info; SymbolToken(this.info, int charOffset) : super(charOffset); String get value => info.value; String get stringValue => info.value; bool isIdentifier() => false; String toString() => "SymbolToken($value)"; } /** * A [BeginGroupToken] represents a symbol that may be the beginning of * a pair of brackets, i.e., ( { [ < or ${ * The [endGroup] token points to the matching closing bracked in case * it can be identified during scanning. */ class BeginGroupToken extends SymbolToken { Token endGroup; BeginGroupToken(PrecedenceInfo info, int charOffset) : super(info, charOffset); } /** * A keyword token. */ class KeywordToken extends Token { final Keyword keyword; KeywordToken(this.keyword, int charOffset) : super(charOffset); PrecedenceInfo get info => keyword.info; String get value => keyword.syntax; String get stringValue => keyword.syntax; bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn; String toString() => "KeywordToken($value)"; } abstract class ErrorToken extends Token { ErrorToken(int charOffset) : super(charOffset); PrecedenceInfo get info => BAD_INPUT_INFO; String get value { throw new SpannableAssertionFailure(this, assertionMessage); } String get stringValue => null; bool isIdentifier() => false; String get assertionMessage; } class BadInputToken extends ErrorToken { final int character; BadInputToken(this.character, int charOffset) : super(charOffset); String toString() => "BadInputToken($character)"; String get assertionMessage { return 'Character U+${character.toRadixString(16)} not allowed here.'; } } class UnterminatedToken extends ErrorToken { final String start; final int endOffset; UnterminatedToken(this.start, int charOffset, this.endOffset) : super(charOffset); String toString() => "UnterminatedToken($start)"; String get assertionMessage => "'$start' isn't terminated."; int get charCount => endOffset - charOffset; } class UnmatchedToken extends ErrorToken { final BeginGroupToken begin; UnmatchedToken(BeginGroupToken begin) : this.begin = begin, super(begin.charOffset); String toString() => "UnmatchedToken(${begin.value})"; String get assertionMessage => "'$begin' isn't closed."; } /** * A String-valued token. Represents identifiers, string literals, * number literals, comments, and error tokens, using the corresponding * precedence info. */ class StringToken extends Token { /** * The length threshold above which substring tokens are computed lazily. * * For string tokens that are substrings of the program source, the actual * substring extraction is performed lazily. This is beneficial because * not all scanned code is actually used. For unused parts, the substrings * are never computed and allocated. */ static const int LAZY_THRESHOLD = 4; var /* String | LazySubtring */ valueOrLazySubstring; final PrecedenceInfo info; /** * Creates a non-lazy string token. If [canonicalize] is true, the string * is canonicalized before the token is created. */ StringToken.fromString(this.info, String value, int charOffset, {bool canonicalize : false}) : valueOrLazySubstring = canonicalizedString(value, canonicalize), super(charOffset); /** * Creates a lazy string token. If [canonicalize] is true, the string * is canonicalized before the token is created. */ StringToken.fromSubstring(this.info, String data, int start, int end, int charOffset, {bool canonicalize : false}) : super(charOffset) { int length = end - start; if (length <= LAZY_THRESHOLD) { valueOrLazySubstring = canonicalizedString(data.substring(start, end), canonicalize); } else { valueOrLazySubstring = new LazySubstring(data, start, length, canonicalize); } } /** * Creates a lazy string token. If [asciiOnly] is false, the byte array * is passed through a UTF-8 decoder. */ StringToken.fromUtf8Bytes(this.info, List data, int start, int end, bool asciiOnly, int charOffset) : super(charOffset) { int length = end - start; if (length <= LAZY_THRESHOLD) { valueOrLazySubstring = decodeUtf8(data, start, end, asciiOnly); } else { valueOrLazySubstring = new LazySubstring(data, start, length, asciiOnly); } } String get value { if (valueOrLazySubstring is String) { return valueOrLazySubstring; } else { assert(valueOrLazySubstring is LazySubstring); var data = valueOrLazySubstring.data; int start = valueOrLazySubstring.start; int end = start + valueOrLazySubstring.length; if (data is String) { valueOrLazySubstring = canonicalizedString( data.substring(start, end), valueOrLazySubstring.boolValue); } else { valueOrLazySubstring = decodeUtf8( data, start, end, valueOrLazySubstring.boolValue); } return valueOrLazySubstring; } } String get stringValue => null; bool isIdentifier() => identical(kind, IDENTIFIER_TOKEN); String toString() => "StringToken($value)"; static final HashSet canonicalizedSubstrings = new HashSet(); static String canonicalizedString(String s, bool canonicalize) { if (!canonicalize) return s; var result = canonicalizedSubstrings.lookup(s); if (result != null) return result; canonicalizedSubstrings.add(s); return s; } static String decodeUtf8(List data, int start, int end, bool asciiOnly) { var s; if (asciiOnly) { s = new String.fromCharCodes(data, start, end); } else { s = UTF8.decoder.convert(data, start, end); } return canonicalizedString(s, true); } } /** * This class represents the necessary information to compute a substring * lazily. The substring can either originate from a string or from * a [:List:] of UTF-8 bytes. */ abstract class LazySubstring { /** The original data, either a string or a List */ get data; int get start; int get length; /** * If this substring is based on a String, the [boolValue] indicates wheter * the resulting substring should be canonicalized. * * For substrings based on a byte array, the [boolValue] is true if the * array only holds ASCII characters. The resulting substring will be * canonicalized after decoding. */ bool get boolValue; LazySubstring.internal(); factory LazySubstring(data, int start, int length, bool b) { // See comment on [CompactLazySubstring]. if (start < 0x100000 && length < 0x200) { int fields = (start << 9); fields = fields | length; fields = fields << 1; if (b) fields |= 1; return new CompactLazySubstring(data, fields); } else { return new FullLazySubstring(data, start, length, b); } } } /** * This class encodes [start], [length] and [boolValue] in a single * 30 bit integer. It uses 20 bits for [start], which covers source files * of 1MB. [length] has 9 bits, which covers 512 characters. * * The file html_dart2js.dart is currently around 1MB. */ class CompactLazySubstring extends LazySubstring { final data; final int fields; CompactLazySubstring(this.data, this.fields) : super.internal(); int get start => fields >> 10; int get length => (fields >> 1) & 0x1ff; bool get boolValue => (fields & 1) == 1; } class FullLazySubstring extends LazySubstring { final data; final int start; final int length; final bool boolValue; FullLazySubstring(this.data, this.start, this.length, this.boolValue) : super.internal(); } bool isUserDefinableOperator(String value) { return isBinaryOperator(value) || isMinusOperator(value) || isTernaryOperator(value) || isUnaryOperator(value); } bool isUnaryOperator(String value) => identical(value, '~'); bool isBinaryOperator(String value) { return (identical(value, '==')) || (identical(value, '[]')) || (identical(value, '*')) || (identical(value, '/')) || (identical(value, '%')) || (identical(value, '~/')) || (identical(value, '+')) || (identical(value, '<<')) || (identical(value, '>>')) || (identical(value, '>=')) || (identical(value, '>')) || (identical(value, '<=')) || (identical(value, '<')) || (identical(value, '&')) || (identical(value, '^')) || (identical(value, '|')); } bool isTernaryOperator(String value) => identical(value, '[]='); bool isMinusOperator(String value) => identical(value, '-'); class PrecedenceInfo { final String value; final int precedence; final int kind; const PrecedenceInfo(this.value, this.precedence, this.kind); toString() => 'PrecedenceInfo($value, $precedence, $kind)'; int get hashCode => computeHashCode(value, precedence, kind); } // TODO(ahe): The following are not tokens in Dart. const PrecedenceInfo BACKPING_INFO = const PrecedenceInfo('`', 0, BACKPING_TOKEN); const PrecedenceInfo BACKSLASH_INFO = const PrecedenceInfo('\\', 0, BACKSLASH_TOKEN); const PrecedenceInfo PERIOD_PERIOD_PERIOD_INFO = const PrecedenceInfo('...', 0, PERIOD_PERIOD_PERIOD_TOKEN); /** * The cascade operator has the lowest precedence of any operator * except assignment. */ const int CASCADE_PRECEDENCE = 2; const PrecedenceInfo PERIOD_PERIOD_INFO = const PrecedenceInfo('..', CASCADE_PRECEDENCE, PERIOD_PERIOD_TOKEN); const PrecedenceInfo BANG_INFO = const PrecedenceInfo('!', 0, BANG_TOKEN); const PrecedenceInfo COLON_INFO = const PrecedenceInfo(':', 0, COLON_TOKEN); const PrecedenceInfo INDEX_INFO = const PrecedenceInfo('[]', 0, INDEX_TOKEN); const PrecedenceInfo MINUS_MINUS_INFO = const PrecedenceInfo('--', POSTFIX_PRECEDENCE, MINUS_MINUS_TOKEN); const PrecedenceInfo PLUS_PLUS_INFO = const PrecedenceInfo('++', POSTFIX_PRECEDENCE, PLUS_PLUS_TOKEN); const PrecedenceInfo TILDE_INFO = const PrecedenceInfo('~', 0, TILDE_TOKEN); const PrecedenceInfo FUNCTION_INFO = const PrecedenceInfo('=>', 0, FUNCTION_TOKEN); const PrecedenceInfo HASH_INFO = const PrecedenceInfo('#', 0, HASH_TOKEN); const PrecedenceInfo INDEX_EQ_INFO = const PrecedenceInfo('[]=', 0, INDEX_EQ_TOKEN); const PrecedenceInfo SEMICOLON_INFO = const PrecedenceInfo(';', 0, SEMICOLON_TOKEN); const PrecedenceInfo COMMA_INFO = const PrecedenceInfo(',', 0, COMMA_TOKEN); const PrecedenceInfo AT_INFO = const PrecedenceInfo('@', 0, AT_TOKEN); // Assignment operators. const int ASSIGNMENT_PRECEDENCE = 1; const PrecedenceInfo AMPERSAND_EQ_INFO = const PrecedenceInfo('&=', ASSIGNMENT_PRECEDENCE, AMPERSAND_EQ_TOKEN); const PrecedenceInfo BAR_EQ_INFO = const PrecedenceInfo('|=', ASSIGNMENT_PRECEDENCE, BAR_EQ_TOKEN); const PrecedenceInfo CARET_EQ_INFO = const PrecedenceInfo('^=', ASSIGNMENT_PRECEDENCE, CARET_EQ_TOKEN); const PrecedenceInfo EQ_INFO = const PrecedenceInfo('=', ASSIGNMENT_PRECEDENCE, EQ_TOKEN); const PrecedenceInfo GT_GT_EQ_INFO = const PrecedenceInfo('>>=', ASSIGNMENT_PRECEDENCE, GT_GT_EQ_TOKEN); const PrecedenceInfo LT_LT_EQ_INFO = const PrecedenceInfo('<<=', ASSIGNMENT_PRECEDENCE, LT_LT_EQ_TOKEN); const PrecedenceInfo MINUS_EQ_INFO = const PrecedenceInfo('-=', ASSIGNMENT_PRECEDENCE, MINUS_EQ_TOKEN); const PrecedenceInfo PERCENT_EQ_INFO = const PrecedenceInfo('%=', ASSIGNMENT_PRECEDENCE, PERCENT_EQ_TOKEN); const PrecedenceInfo PLUS_EQ_INFO = const PrecedenceInfo('+=', ASSIGNMENT_PRECEDENCE, PLUS_EQ_TOKEN); const PrecedenceInfo SLASH_EQ_INFO = const PrecedenceInfo('/=', ASSIGNMENT_PRECEDENCE, SLASH_EQ_TOKEN); const PrecedenceInfo STAR_EQ_INFO = const PrecedenceInfo('*=', ASSIGNMENT_PRECEDENCE, STAR_EQ_TOKEN); const PrecedenceInfo TILDE_SLASH_EQ_INFO = const PrecedenceInfo('~/=', ASSIGNMENT_PRECEDENCE, TILDE_SLASH_EQ_TOKEN); const PrecedenceInfo QUESTION_INFO = const PrecedenceInfo('?', 3, QUESTION_TOKEN); const PrecedenceInfo BAR_BAR_INFO = const PrecedenceInfo('||', 4, BAR_BAR_TOKEN); const PrecedenceInfo AMPERSAND_AMPERSAND_INFO = const PrecedenceInfo('&&', 5, AMPERSAND_AMPERSAND_TOKEN); const PrecedenceInfo BAR_INFO = const PrecedenceInfo('|', 8, BAR_TOKEN); const PrecedenceInfo CARET_INFO = const PrecedenceInfo('^', 9, CARET_TOKEN); const PrecedenceInfo AMPERSAND_INFO = const PrecedenceInfo('&', 10, AMPERSAND_TOKEN); // Equality operators. const int EQUALITY_PRECEDENCE = 6; const PrecedenceInfo BANG_EQ_EQ_INFO = const PrecedenceInfo('!==', EQUALITY_PRECEDENCE, BANG_EQ_EQ_TOKEN); const PrecedenceInfo BANG_EQ_INFO = const PrecedenceInfo('!=', EQUALITY_PRECEDENCE, BANG_EQ_TOKEN); const PrecedenceInfo EQ_EQ_EQ_INFO = const PrecedenceInfo('===', EQUALITY_PRECEDENCE, EQ_EQ_EQ_TOKEN); const PrecedenceInfo EQ_EQ_INFO = const PrecedenceInfo('==', EQUALITY_PRECEDENCE, EQ_EQ_TOKEN); // Relational operators. const int RELATIONAL_PRECEDENCE = 7; const PrecedenceInfo GT_EQ_INFO = const PrecedenceInfo('>=', RELATIONAL_PRECEDENCE, GT_EQ_TOKEN); const PrecedenceInfo GT_INFO = const PrecedenceInfo('>', RELATIONAL_PRECEDENCE, GT_TOKEN); const PrecedenceInfo IS_INFO = const PrecedenceInfo('is', RELATIONAL_PRECEDENCE, KEYWORD_TOKEN); const PrecedenceInfo AS_INFO = const PrecedenceInfo('as', RELATIONAL_PRECEDENCE, KEYWORD_TOKEN); const PrecedenceInfo LT_EQ_INFO = const PrecedenceInfo('<=', RELATIONAL_PRECEDENCE, LT_EQ_TOKEN); const PrecedenceInfo LT_INFO = const PrecedenceInfo('<', RELATIONAL_PRECEDENCE, LT_TOKEN); // Shift operators. const PrecedenceInfo GT_GT_INFO = const PrecedenceInfo('>>', 11, GT_GT_TOKEN); const PrecedenceInfo LT_LT_INFO = const PrecedenceInfo('<<', 11, LT_LT_TOKEN); // Additive operators. const PrecedenceInfo MINUS_INFO = const PrecedenceInfo('-', 12, MINUS_TOKEN); const PrecedenceInfo PLUS_INFO = const PrecedenceInfo('+', 12, PLUS_TOKEN); // Multiplicative operators. const PrecedenceInfo PERCENT_INFO = const PrecedenceInfo('%', 13, PERCENT_TOKEN); const PrecedenceInfo SLASH_INFO = const PrecedenceInfo('/', 13, SLASH_TOKEN); const PrecedenceInfo STAR_INFO = const PrecedenceInfo('*', 13, STAR_TOKEN); const PrecedenceInfo TILDE_SLASH_INFO = const PrecedenceInfo('~/', 13, TILDE_SLASH_TOKEN); const int POSTFIX_PRECEDENCE = 14; const PrecedenceInfo PERIOD_INFO = const PrecedenceInfo('.', POSTFIX_PRECEDENCE, PERIOD_TOKEN); const PrecedenceInfo KEYWORD_INFO = const PrecedenceInfo('keyword', 0, KEYWORD_TOKEN); const PrecedenceInfo EOF_INFO = const PrecedenceInfo('EOF', 0, EOF_TOKEN); const PrecedenceInfo IDENTIFIER_INFO = const PrecedenceInfo('identifier', 0, IDENTIFIER_TOKEN); const PrecedenceInfo BAD_INPUT_INFO = const PrecedenceInfo('malformed input', 0, BAD_INPUT_TOKEN); const PrecedenceInfo OPEN_PAREN_INFO = const PrecedenceInfo('(', POSTFIX_PRECEDENCE, OPEN_PAREN_TOKEN); const PrecedenceInfo CLOSE_PAREN_INFO = const PrecedenceInfo(')', 0, CLOSE_PAREN_TOKEN); const PrecedenceInfo OPEN_CURLY_BRACKET_INFO = const PrecedenceInfo('{', 0, OPEN_CURLY_BRACKET_TOKEN); const PrecedenceInfo CLOSE_CURLY_BRACKET_INFO = const PrecedenceInfo('}', 0, CLOSE_CURLY_BRACKET_TOKEN); const PrecedenceInfo INT_INFO = const PrecedenceInfo('int', 0, INT_TOKEN); const PrecedenceInfo STRING_INFO = const PrecedenceInfo('string', 0, STRING_TOKEN); const PrecedenceInfo OPEN_SQUARE_BRACKET_INFO = const PrecedenceInfo('[', POSTFIX_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN); const PrecedenceInfo CLOSE_SQUARE_BRACKET_INFO = const PrecedenceInfo(']', 0, CLOSE_SQUARE_BRACKET_TOKEN); const PrecedenceInfo DOUBLE_INFO = const PrecedenceInfo('double', 0, DOUBLE_TOKEN); const PrecedenceInfo STRING_INTERPOLATION_INFO = const PrecedenceInfo('\${', 0, STRING_INTERPOLATION_TOKEN); const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO = const PrecedenceInfo('\$', 0, STRING_INTERPOLATION_IDENTIFIER_TOKEN); const PrecedenceInfo HEXADECIMAL_INFO = const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN); const PrecedenceInfo COMMENT_INFO = const PrecedenceInfo('comment', 0, COMMENT_TOKEN);