| OLD | NEW |
| (Empty) | |
| 1 // This code was auto-generated, is not intended to be edited, and is subject to |
| 2 // significant change. Please see the README file for more information. |
| 3 |
| 4 library engine.scanner; |
| 5 |
| 6 import 'dart:collection'; |
| 7 import 'java_core.dart'; |
| 8 import 'source.dart'; |
| 9 import 'error.dart'; |
| 10 import 'instrumentation.dart'; |
| 11 |
| 12 /** |
| 13 * The enumeration {@code Keyword} defines the keywords in the Dart programming
language. |
| 14 */ |
| 15 class Keyword { |
| 16 static final Keyword ASSERT = new Keyword.con1('ASSERT', 0, "assert"); |
| 17 static final Keyword BREAK = new Keyword.con1('BREAK', 1, "break"); |
| 18 static final Keyword CASE = new Keyword.con1('CASE', 2, "case"); |
| 19 static final Keyword CATCH = new Keyword.con1('CATCH', 3, "catch"); |
| 20 static final Keyword CLASS = new Keyword.con1('CLASS', 4, "class"); |
| 21 static final Keyword CONST = new Keyword.con1('CONST', 5, "const"); |
| 22 static final Keyword CONTINUE = new Keyword.con1('CONTINUE', 6, "continue"); |
| 23 static final Keyword DEFAULT = new Keyword.con1('DEFAULT', 7, "default"); |
| 24 static final Keyword DO = new Keyword.con1('DO', 8, "do"); |
| 25 static final Keyword ELSE = new Keyword.con1('ELSE', 9, "else"); |
| 26 static final Keyword EXTENDS = new Keyword.con1('EXTENDS', 10, "extends"); |
| 27 static final Keyword FALSE = new Keyword.con1('FALSE', 11, "false"); |
| 28 static final Keyword FINAL = new Keyword.con1('FINAL', 12, "final"); |
| 29 static final Keyword FINALLY = new Keyword.con1('FINALLY', 13, "finally"); |
| 30 static final Keyword FOR = new Keyword.con1('FOR', 14, "for"); |
| 31 static final Keyword IF = new Keyword.con1('IF', 15, "if"); |
| 32 static final Keyword IN = new Keyword.con1('IN', 16, "in"); |
| 33 static final Keyword IS = new Keyword.con1('IS', 17, "is"); |
| 34 static final Keyword NEW = new Keyword.con1('NEW', 18, "new"); |
| 35 static final Keyword NULL = new Keyword.con1('NULL', 19, "null"); |
| 36 static final Keyword RETURN = new Keyword.con1('RETURN', 20, "return"); |
| 37 static final Keyword SUPER = new Keyword.con1('SUPER', 21, "super"); |
| 38 static final Keyword SWITCH = new Keyword.con1('SWITCH', 22, "switch"); |
| 39 static final Keyword THIS = new Keyword.con1('THIS', 23, "this"); |
| 40 static final Keyword THROW = new Keyword.con1('THROW', 24, "throw"); |
| 41 static final Keyword TRUE = new Keyword.con1('TRUE', 25, "true"); |
| 42 static final Keyword TRY = new Keyword.con1('TRY', 26, "try"); |
| 43 static final Keyword VAR = new Keyword.con1('VAR', 27, "var"); |
| 44 static final Keyword VOID = new Keyword.con1('VOID', 28, "void"); |
| 45 static final Keyword WHILE = new Keyword.con1('WHILE', 29, "while"); |
| 46 static final Keyword WITH = new Keyword.con1('WITH', 30, "with"); |
| 47 static final Keyword ABSTRACT = new Keyword.con2('ABSTRACT', 31, "abstract", t
rue); |
| 48 static final Keyword AS = new Keyword.con2('AS', 32, "as", true); |
| 49 static final Keyword DYNAMIC = new Keyword.con2('DYNAMIC', 33, "dynamic", true
); |
| 50 static final Keyword EXPORT = new Keyword.con2('EXPORT', 34, "export", true); |
| 51 static final Keyword EXTERNAL = new Keyword.con2('EXTERNAL', 35, "external", t
rue); |
| 52 static final Keyword FACTORY = new Keyword.con2('FACTORY', 36, "factory", true
); |
| 53 static final Keyword GET = new Keyword.con2('GET', 37, "get", true); |
| 54 static final Keyword IMPLEMENTS = new Keyword.con2('IMPLEMENTS', 38, "implemen
ts", true); |
| 55 static final Keyword IMPORT = new Keyword.con2('IMPORT', 39, "import", true); |
| 56 static final Keyword LIBRARY = new Keyword.con2('LIBRARY', 40, "library", true
); |
| 57 static final Keyword OPERATOR = new Keyword.con2('OPERATOR', 41, "operator", t
rue); |
| 58 static final Keyword PART = new Keyword.con2('PART', 42, "part", true); |
| 59 static final Keyword SET = new Keyword.con2('SET', 43, "set", true); |
| 60 static final Keyword STATIC = new Keyword.con2('STATIC', 44, "static", true); |
| 61 static final Keyword TYPEDEF = new Keyword.con2('TYPEDEF', 45, "typedef", true
); |
| 62 static final List<Keyword> values = [ASSERT, BREAK, CASE, CATCH, CLASS, CONST,
CONTINUE, DEFAULT, DO, ELSE, EXTENDS, FALSE, FINAL, FINALLY, FOR, IF, IN, IS, N
EW, NULL, RETURN, SUPER, SWITCH, THIS, THROW, TRUE, TRY, VAR, VOID, WHILE, WITH,
ABSTRACT, AS, DYNAMIC, EXPORT, EXTERNAL, FACTORY, GET, IMPLEMENTS, IMPORT, LIBR
ARY, OPERATOR, PART, SET, STATIC, TYPEDEF]; |
| 63 String __name; |
| 64 int __ordinal = 0; |
| 65 /** |
| 66 * The lexeme for the keyword. |
| 67 */ |
| 68 String _syntax; |
| 69 /** |
| 70 * A flag indicating whether the keyword is a pseudo-keyword. Pseudo keywords
can be used as |
| 71 * identifiers. |
| 72 */ |
| 73 bool _isPseudoKeyword2 = false; |
| 74 /** |
| 75 * A table mapping the lexemes of keywords to the corresponding keyword. |
| 76 */ |
| 77 static Map<String, Keyword> keywords = createKeywordMap(); |
| 78 /** |
| 79 * Create a table mapping the lexemes of keywords to the corresponding keyword
. |
| 80 * @return the table that was created |
| 81 */ |
| 82 static Map<String, Keyword> createKeywordMap() { |
| 83 LinkedHashMap<String, Keyword> result = new LinkedHashMap<String, Keyword>()
; |
| 84 for (Keyword keyword in values) { |
| 85 result[keyword._syntax] = keyword; |
| 86 } |
| 87 return result; |
| 88 } |
| 89 /** |
| 90 * Initialize a newly created keyword to have the given syntax. The keyword is
not a |
| 91 * pseudo-keyword. |
| 92 * @param syntax the lexeme for the keyword |
| 93 */ |
| 94 Keyword.con1(String ___name, int ___ordinal, String syntax) { |
| 95 _jtd_constructor_215_impl(___name, ___ordinal, syntax); |
| 96 } |
| 97 _jtd_constructor_215_impl(String ___name, int ___ordinal, String syntax) { |
| 98 _jtd_constructor_216_impl(___name, ___ordinal, syntax, false); |
| 99 } |
| 100 /** |
| 101 * Initialize a newly created keyword to have the given syntax. The keyword is
a pseudo-keyword if |
| 102 * the given flag is {@code true}. |
| 103 * @param syntax the lexeme for the keyword |
| 104 * @param isPseudoKeyword {@code true} if this keyword is a pseudo-keyword |
| 105 */ |
| 106 Keyword.con2(String ___name, int ___ordinal, String syntax, bool isPseudoKeywo
rd) { |
| 107 _jtd_constructor_216_impl(___name, ___ordinal, syntax, isPseudoKeyword); |
| 108 } |
| 109 _jtd_constructor_216_impl(String ___name, int ___ordinal, String syntax, bool
isPseudoKeyword) { |
| 110 __name = ___name; |
| 111 __ordinal = ___ordinal; |
| 112 this._syntax = syntax; |
| 113 this._isPseudoKeyword2 = isPseudoKeyword; |
| 114 } |
| 115 /** |
| 116 * Return the lexeme for the keyword. |
| 117 * @return the lexeme for the keyword |
| 118 */ |
| 119 String get syntax => _syntax; |
| 120 /** |
| 121 * Return {@code true} if this keyword is a pseudo-keyword. Pseudo keywords ca
n be used as |
| 122 * identifiers. |
| 123 * @return {@code true} if this keyword is a pseudo-keyword |
| 124 */ |
| 125 bool isPseudoKeyword() => _isPseudoKeyword2; |
| 126 String toString() => __name; |
| 127 } |
| 128 /** |
| 129 * Instances of the class {@code CharBufferScanner} implement a scanner that rea
ds from a character |
| 130 * buffer. The scanning logic is in the superclass. |
| 131 */ |
| 132 class CharBufferScanner extends AbstractScanner { |
| 133 /** |
| 134 * The buffer from which characters will be read. |
| 135 */ |
| 136 CharBuffer _buffer; |
| 137 /** |
| 138 * The number of characters in the buffer. |
| 139 */ |
| 140 int _bufferLength = 0; |
| 141 /** |
| 142 * The index of the last character that was read. |
| 143 */ |
| 144 int _charOffset = 0; |
| 145 /** |
| 146 * Initialize a newly created scanner to scan the characters in the given char
acter buffer. |
| 147 * @param source the source being scanned |
| 148 * @param buffer the buffer from which characters will be read |
| 149 * @param errorListener the error listener that will be informed of any errors
that are found |
| 150 */ |
| 151 CharBufferScanner(Source source, CharBuffer buffer, AnalysisErrorListener erro
rListener) : super(source, errorListener) { |
| 152 this._buffer = buffer; |
| 153 this._bufferLength = buffer.length(); |
| 154 this._charOffset = -1; |
| 155 } |
| 156 int get offset => _charOffset; |
| 157 int advance() { |
| 158 if (_charOffset + 1 >= _bufferLength) { |
| 159 return -1; |
| 160 } |
| 161 return _buffer.charAt(++_charOffset); |
| 162 } |
| 163 String getString(int start, int endDelta) => _buffer.subSequence(start, _charO
ffset + 1 + endDelta).toString(); |
| 164 int peek() { |
| 165 if (_charOffset + 1 >= _buffer.length()) { |
| 166 return -1; |
| 167 } |
| 168 return _buffer.charAt(_charOffset + 1); |
| 169 } |
| 170 } |
| 171 /** |
| 172 * Instances of the class {@code TokenWithComment} represent a normal token that
is preceded by |
| 173 * comments. |
| 174 */ |
| 175 class TokenWithComment extends Token { |
| 176 /** |
| 177 * The first comment in the list of comments that precede this token. |
| 178 */ |
| 179 Token _precedingComment; |
| 180 /** |
| 181 * Initialize a newly created token to have the given type and offset and to b
e preceded by the |
| 182 * comments reachable from the given comment. |
| 183 * @param type the type of the token |
| 184 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 185 * @param precedingComment the first comment in the list of comments that prec
ede this token |
| 186 */ |
| 187 TokenWithComment(TokenType type, int offset, Token precedingComment) : super(t
ype, offset) { |
| 188 this._precedingComment = precedingComment; |
| 189 } |
| 190 Token get precedingComments => _precedingComment; |
| 191 } |
| 192 /** |
| 193 * Instances of the class {@code Token} represent a token that was scanned from
the input. Each |
| 194 * token knows which token follows it, acting as the head of a linked list of to
kens. |
| 195 */ |
| 196 class Token { |
| 197 /** |
| 198 * The type of the token. |
| 199 */ |
| 200 TokenType _type; |
| 201 /** |
| 202 * The offset from the beginning of the file to the first character in the tok
en. |
| 203 */ |
| 204 int _offset = 0; |
| 205 /** |
| 206 * The previous token in the token stream. |
| 207 */ |
| 208 Token _previous; |
| 209 /** |
| 210 * The next token in the token stream. |
| 211 */ |
| 212 Token _next; |
| 213 /** |
| 214 * Initialize a newly created token to have the given type and offset. |
| 215 * @param type the type of the token |
| 216 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 217 */ |
| 218 Token(TokenType type, int offset) { |
| 219 this._type = type; |
| 220 this._offset = offset; |
| 221 } |
| 222 /** |
| 223 * Return the offset from the beginning of the file to the character after las
t character of the |
| 224 * token. |
| 225 * @return the offset from the beginning of the file to the first character af
ter last character |
| 226 * of the token |
| 227 */ |
| 228 int get end => _offset + length; |
| 229 /** |
| 230 * Return the number of characters in the node's source range. |
| 231 * @return the number of characters in the node's source range |
| 232 */ |
| 233 int get length => lexeme.length; |
| 234 /** |
| 235 * Return the lexeme that represents this token. |
| 236 * @return the lexeme that represents this token |
| 237 */ |
| 238 String get lexeme => _type.lexeme; |
| 239 /** |
| 240 * Return the next token in the token stream. |
| 241 * @return the next token in the token stream |
| 242 */ |
| 243 Token get next => _next; |
| 244 /** |
| 245 * Return the offset from the beginning of the file to the first character in
the token. |
| 246 * @return the offset from the beginning of the file to the first character in
the token |
| 247 */ |
| 248 int get offset => _offset; |
| 249 /** |
| 250 * Return the first comment in the list of comments that precede this token, o
r {@code null} if |
| 251 * there are no comments preceding this token. Additional comments can be reac
hed by following the |
| 252 * token stream using {@link #getNext()} until {@code null} is returned. |
| 253 * @return the first comment in the list of comments that precede this token |
| 254 */ |
| 255 Token get precedingComments => null; |
| 256 /** |
| 257 * Return the previous token in the token stream. |
| 258 * @return the previous token in the token stream |
| 259 */ |
| 260 Token get previous => _previous; |
| 261 /** |
| 262 * Return the type of the token. |
| 263 * @return the type of the token |
| 264 */ |
| 265 TokenType get type => _type; |
| 266 /** |
| 267 * Return {@code true} if this token represents an operator. |
| 268 * @return {@code true} if this token represents an operator |
| 269 */ |
| 270 bool isOperator() => _type.isOperator(); |
| 271 /** |
| 272 * Return {@code true} if this token is a synthetic token. A synthetic token i
s a token that was |
| 273 * introduced by the parser in order to recover from an error in the code. Syn
thetic tokens always |
| 274 * have a length of zero ({@code 0}). |
| 275 * @return {@code true} if this token is a synthetic token |
| 276 */ |
| 277 bool isSynthetic() => length == 0; |
| 278 /** |
| 279 * Return {@code true} if this token represents an operator that can be define
d by users. |
| 280 * @return {@code true} if this token represents an operator that can be defin
ed by users |
| 281 */ |
| 282 bool isUserDefinableOperator() => _type.isUserDefinableOperator(); |
| 283 /** |
| 284 * Set the next token in the token stream to the given token. This has the sid
e-effect of setting |
| 285 * this token to be the previous token for the given token. |
| 286 * @param token the next token in the token stream |
| 287 * @return the token that was passed in |
| 288 */ |
| 289 Token setNext(Token token) { |
| 290 _next = token; |
| 291 token.previous2 = this; |
| 292 return token; |
| 293 } |
| 294 /** |
| 295 * Set the next token in the token stream to the given token without changing
which token is the |
| 296 * previous token for the given token. |
| 297 * @param token the next token in the token stream |
| 298 * @return the token that was passed in |
| 299 */ |
| 300 Token setNextWithoutSettingPrevious(Token token) { |
| 301 _next = token; |
| 302 return token; |
| 303 } |
| 304 /** |
| 305 * Set the offset from the beginning of the file to the first character in the
token to the given |
| 306 * offset. |
| 307 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 308 */ |
| 309 void set offset2(int offset) { |
| 310 this._offset = offset; |
| 311 } |
| 312 String toString() => lexeme; |
| 313 /** |
| 314 * Return the value of this token. For keyword tokens, this is the keyword ass
ociated with the |
| 315 * token, for other tokens it is the lexeme associated with the token. |
| 316 * @return the value of this token |
| 317 */ |
| 318 Object value() => _type.lexeme; |
| 319 /** |
| 320 * Set the previous token in the token stream to the given token. |
| 321 * @param previous the previous token in the token stream |
| 322 */ |
| 323 void set previous2(Token previous) { |
| 324 this._previous = previous; |
| 325 } |
| 326 } |
| 327 /** |
| 328 * Instances of the class {@code KeywordToken} represent a keyword in the langua
ge. |
| 329 */ |
| 330 class KeywordToken extends Token { |
| 331 /** |
| 332 * The keyword being represented by this token. |
| 333 */ |
| 334 Keyword _keyword; |
| 335 /** |
| 336 * Initialize a newly created token to represent the given keyword. |
| 337 * @param keyword the keyword being represented by this token |
| 338 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 339 */ |
| 340 KeywordToken(Keyword keyword, int offset) : super(TokenType.KEYWORD, offset) { |
| 341 this._keyword = keyword; |
| 342 } |
| 343 /** |
| 344 * Return the keyword being represented by this token. |
| 345 * @return the keyword being represented by this token |
| 346 */ |
| 347 Keyword get keyword => _keyword; |
| 348 String get lexeme => _keyword.syntax; |
| 349 Keyword value() => _keyword; |
| 350 } |
| 351 /** |
| 352 * Instances of the class {@code StringToken} represent a token whose value is i
ndependent of it's |
| 353 * type. |
| 354 */ |
| 355 class StringToken extends Token { |
| 356 /** |
| 357 * The lexeme represented by this token. |
| 358 */ |
| 359 String _value2; |
| 360 /** |
| 361 * Initialize a newly created token to represent a token of the given type wit
h the given value. |
| 362 * @param type the type of the token |
| 363 * @param value the lexeme represented by this token |
| 364 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 365 */ |
| 366 StringToken(TokenType type, String value, int offset) : super(type, offset) { |
| 367 this._value2 = value; |
| 368 } |
| 369 String get lexeme => _value2; |
| 370 String value() => _value2; |
| 371 } |
| 372 /** |
| 373 * The enumeration {@code ScannerErrorCode} defines the error codes used for err
ors detected by the |
| 374 * scanner. |
| 375 */ |
| 376 class ScannerErrorCode implements ErrorCode { |
| 377 static final ScannerErrorCode ILLEGAL_CHARACTER = new ScannerErrorCode('ILLEGA
L_CHARACTER', 0, "Illegal character %x"); |
| 378 static final ScannerErrorCode MISSING_DIGIT = new ScannerErrorCode('MISSING_DI
GIT', 1, "Decimal digit expected"); |
| 379 static final ScannerErrorCode MISSING_HEX_DIGIT = new ScannerErrorCode('MISSIN
G_HEX_DIGIT', 2, "Hexidecimal digit expected"); |
| 380 static final ScannerErrorCode MISSING_QUOTE = new ScannerErrorCode('MISSING_QU
OTE', 3, "Expected quote (' or \")"); |
| 381 static final ScannerErrorCode UNTERMINATED_MULTI_LINE_COMMENT = new ScannerErr
orCode('UNTERMINATED_MULTI_LINE_COMMENT', 4, "Unterminated multi-line comment"); |
| 382 static final ScannerErrorCode UNTERMINATED_STRING_LITERAL = new ScannerErrorCo
de('UNTERMINATED_STRING_LITERAL', 5, "Unterminated string literal"); |
| 383 static final List<ScannerErrorCode> values = [ILLEGAL_CHARACTER, MISSING_DIGIT
, MISSING_HEX_DIGIT, MISSING_QUOTE, UNTERMINATED_MULTI_LINE_COMMENT, UNTERMINATE
D_STRING_LITERAL]; |
| 384 final String __name; |
| 385 final int __ordinal; |
| 386 /** |
| 387 * The message template used to create the message to be displayed for this er
ror. |
| 388 */ |
| 389 String _message; |
| 390 /** |
| 391 * Initialize a newly created error code to have the given message. |
| 392 * @param message the message template used to create the message to be displa
yed for this error |
| 393 */ |
| 394 ScannerErrorCode(this.__name, this.__ordinal, String message) { |
| 395 this._message = message; |
| 396 } |
| 397 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; |
| 398 String get message => _message; |
| 399 ErrorType get type => ErrorType.SYNTACTIC_ERROR; |
| 400 bool needsRecompilation() => true; |
| 401 String toString() => __name; |
| 402 } |
| 403 /** |
| 404 * Instances of the class {@code BeginTokenWithComment} represent a begin token
that is preceded by |
| 405 * comments. |
| 406 */ |
| 407 class BeginTokenWithComment extends BeginToken { |
| 408 /** |
| 409 * The first comment in the list of comments that precede this token. |
| 410 */ |
| 411 Token _precedingComment; |
| 412 /** |
| 413 * Initialize a newly created token to have the given type and offset and to b
e preceded by the |
| 414 * comments reachable from the given comment. |
| 415 * @param type the type of the token |
| 416 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 417 * @param precedingComment the first comment in the list of comments that prec
ede this token |
| 418 */ |
| 419 BeginTokenWithComment(TokenType type, int offset, Token precedingComment) : su
per(type, offset) { |
| 420 this._precedingComment = precedingComment; |
| 421 } |
| 422 Token get precedingComments => _precedingComment; |
| 423 } |
| 424 /** |
| 425 * The enumeration {@code TokenType} defines the types of tokens that can be ret
urned by the |
| 426 * scanner. |
| 427 */ |
| 428 class TokenType { |
| 429 /** |
| 430 * The type of the token that marks the end of the input. |
| 431 */ |
| 432 static final TokenType EOF = new TokenType_EOF('EOF', 0, null, ""); |
| 433 static final TokenType DOUBLE = new TokenType.con1('DOUBLE', 1); |
| 434 static final TokenType HEXADECIMAL = new TokenType.con1('HEXADECIMAL', 2); |
| 435 static final TokenType IDENTIFIER = new TokenType.con1('IDENTIFIER', 3); |
| 436 static final TokenType INT = new TokenType.con1('INT', 4); |
| 437 static final TokenType KEYWORD = new TokenType.con1('KEYWORD', 5); |
| 438 static final TokenType MULTI_LINE_COMMENT = new TokenType.con1('MULTI_LINE_COM
MENT', 6); |
| 439 static final TokenType SCRIPT_TAG = new TokenType.con1('SCRIPT_TAG', 7); |
| 440 static final TokenType SINGLE_LINE_COMMENT = new TokenType.con1('SINGLE_LINE_C
OMMENT', 8); |
| 441 static final TokenType STRING = new TokenType.con1('STRING', 9); |
| 442 static final TokenType AMPERSAND = new TokenType.con2('AMPERSAND', 10, TokenCl
ass.BITWISE_AND_OPERATOR, "&"); |
| 443 static final TokenType AMPERSAND_AMPERSAND = new TokenType.con2('AMPERSAND_AMP
ERSAND', 11, TokenClass.LOGICAL_AND_OPERATOR, "&&"); |
| 444 static final TokenType AMPERSAND_EQ = new TokenType.con2('AMPERSAND_EQ', 12, T
okenClass.ASSIGNMENT_OPERATOR, "&="); |
| 445 static final TokenType AT = new TokenType.con2('AT', 13, null, "@"); |
| 446 static final TokenType BANG = new TokenType.con2('BANG', 14, TokenClass.UNARY_
PREFIX_OPERATOR, "!"); |
| 447 static final TokenType BANG_EQ = new TokenType.con2('BANG_EQ', 15, TokenClass.
EQUALITY_OPERATOR, "!="); |
| 448 static final TokenType BAR = new TokenType.con2('BAR', 16, TokenClass.BITWISE_
OR_OPERATOR, "|"); |
| 449 static final TokenType BAR_BAR = new TokenType.con2('BAR_BAR', 17, TokenClass.
LOGICAL_OR_OPERATOR, "||"); |
| 450 static final TokenType BAR_EQ = new TokenType.con2('BAR_EQ', 18, TokenClass.AS
SIGNMENT_OPERATOR, "|="); |
| 451 static final TokenType COLON = new TokenType.con2('COLON', 19, null, ":"); |
| 452 static final TokenType COMMA = new TokenType.con2('COMMA', 20, null, ","); |
| 453 static final TokenType CARET = new TokenType.con2('CARET', 21, TokenClass.BITW
ISE_XOR_OPERATOR, "^"); |
| 454 static final TokenType CARET_EQ = new TokenType.con2('CARET_EQ', 22, TokenClas
s.ASSIGNMENT_OPERATOR, "^="); |
| 455 static final TokenType CLOSE_CURLY_BRACKET = new TokenType.con2('CLOSE_CURLY_B
RACKET', 23, null, "}"); |
| 456 static final TokenType CLOSE_PAREN = new TokenType.con2('CLOSE_PAREN', 24, nul
l, ")"); |
| 457 static final TokenType CLOSE_SQUARE_BRACKET = new TokenType.con2('CLOSE_SQUARE
_BRACKET', 25, null, "]"); |
| 458 static final TokenType EQ = new TokenType.con2('EQ', 26, TokenClass.ASSIGNMENT
_OPERATOR, "="); |
| 459 static final TokenType EQ_EQ = new TokenType.con2('EQ_EQ', 27, TokenClass.EQUA
LITY_OPERATOR, "=="); |
| 460 static final TokenType FUNCTION = new TokenType.con2('FUNCTION', 28, null, "=>
"); |
| 461 static final TokenType GT = new TokenType.con2('GT', 29, TokenClass.RELATIONAL
_OPERATOR, ">"); |
| 462 static final TokenType GT_EQ = new TokenType.con2('GT_EQ', 30, TokenClass.RELA
TIONAL_OPERATOR, ">="); |
| 463 static final TokenType GT_GT = new TokenType.con2('GT_GT', 31, TokenClass.SHIF
T_OPERATOR, ">>"); |
| 464 static final TokenType GT_GT_EQ = new TokenType.con2('GT_GT_EQ', 32, TokenClas
s.ASSIGNMENT_OPERATOR, ">>="); |
| 465 static final TokenType HASH = new TokenType.con2('HASH', 33, null, "#"); |
| 466 static final TokenType INDEX = new TokenType.con2('INDEX', 34, TokenClass.UNAR
Y_POSTFIX_OPERATOR, "[]"); |
| 467 static final TokenType INDEX_EQ = new TokenType.con2('INDEX_EQ', 35, TokenClas
s.UNARY_POSTFIX_OPERATOR, "[]="); |
| 468 static final TokenType IS = new TokenType.con2('IS', 36, TokenClass.RELATIONAL
_OPERATOR, "is"); |
| 469 static final TokenType LT = new TokenType.con2('LT', 37, TokenClass.RELATIONAL
_OPERATOR, "<"); |
| 470 static final TokenType LT_EQ = new TokenType.con2('LT_EQ', 38, TokenClass.RELA
TIONAL_OPERATOR, "<="); |
| 471 static final TokenType LT_LT = new TokenType.con2('LT_LT', 39, TokenClass.SHIF
T_OPERATOR, "<<"); |
| 472 static final TokenType LT_LT_EQ = new TokenType.con2('LT_LT_EQ', 40, TokenClas
s.ASSIGNMENT_OPERATOR, "<<="); |
| 473 static final TokenType MINUS = new TokenType.con2('MINUS', 41, TokenClass.ADDI
TIVE_OPERATOR, "-"); |
| 474 static final TokenType MINUS_EQ = new TokenType.con2('MINUS_EQ', 42, TokenClas
s.ASSIGNMENT_OPERATOR, "-="); |
| 475 static final TokenType MINUS_MINUS = new TokenType.con2('MINUS_MINUS', 43, Tok
enClass.UNARY_PREFIX_OPERATOR, "--"); |
| 476 static final TokenType OPEN_CURLY_BRACKET = new TokenType.con2('OPEN_CURLY_BRA
CKET', 44, null, "{"); |
| 477 static final TokenType OPEN_PAREN = new TokenType.con2('OPEN_PAREN', 45, Token
Class.UNARY_POSTFIX_OPERATOR, "("); |
| 478 static final TokenType OPEN_SQUARE_BRACKET = new TokenType.con2('OPEN_SQUARE_B
RACKET', 46, TokenClass.UNARY_POSTFIX_OPERATOR, "["); |
| 479 static final TokenType PERCENT = new TokenType.con2('PERCENT', 47, TokenClass.
MULTIPLICATIVE_OPERATOR, "%"); |
| 480 static final TokenType PERCENT_EQ = new TokenType.con2('PERCENT_EQ', 48, Token
Class.ASSIGNMENT_OPERATOR, "%="); |
| 481 static final TokenType PERIOD = new TokenType.con2('PERIOD', 49, TokenClass.UN
ARY_POSTFIX_OPERATOR, "."); |
| 482 static final TokenType PERIOD_PERIOD = new TokenType.con2('PERIOD_PERIOD', 50,
TokenClass.CASCADE_OPERATOR, ".."); |
| 483 static final TokenType PLUS = new TokenType.con2('PLUS', 51, TokenClass.ADDITI
VE_OPERATOR, "+"); |
| 484 static final TokenType PLUS_EQ = new TokenType.con2('PLUS_EQ', 52, TokenClass.
ASSIGNMENT_OPERATOR, "+="); |
| 485 static final TokenType PLUS_PLUS = new TokenType.con2('PLUS_PLUS', 53, TokenCl
ass.UNARY_PREFIX_OPERATOR, "++"); |
| 486 static final TokenType QUESTION = new TokenType.con2('QUESTION', 54, TokenClas
s.CONDITIONAL_OPERATOR, "?"); |
| 487 static final TokenType SEMICOLON = new TokenType.con2('SEMICOLON', 55, null, "
;"); |
| 488 static final TokenType SLASH = new TokenType.con2('SLASH', 56, TokenClass.MULT
IPLICATIVE_OPERATOR, "/"); |
| 489 static final TokenType SLASH_EQ = new TokenType.con2('SLASH_EQ', 57, TokenClas
s.ASSIGNMENT_OPERATOR, "/="); |
| 490 static final TokenType STAR = new TokenType.con2('STAR', 58, TokenClass.MULTIP
LICATIVE_OPERATOR, "*"); |
| 491 static final TokenType STAR_EQ = new TokenType.con2('STAR_EQ', 59, TokenClass.
ASSIGNMENT_OPERATOR, "*="); |
| 492 static final TokenType STRING_INTERPOLATION_EXPRESSION = new TokenType.con2('S
TRING_INTERPOLATION_EXPRESSION', 60, null, "\${"); |
| 493 static final TokenType STRING_INTERPOLATION_IDENTIFIER = new TokenType.con2('S
TRING_INTERPOLATION_IDENTIFIER', 61, null, "\$"); |
| 494 static final TokenType TILDE = new TokenType.con2('TILDE', 62, TokenClass.UNAR
Y_PREFIX_OPERATOR, "~"); |
| 495 static final TokenType TILDE_SLASH = new TokenType.con2('TILDE_SLASH', 63, Tok
enClass.MULTIPLICATIVE_OPERATOR, "~/"); |
| 496 static final TokenType TILDE_SLASH_EQ = new TokenType.con2('TILDE_SLASH_EQ', 6
4, TokenClass.ASSIGNMENT_OPERATOR, "~/="); |
| 497 static final TokenType BACKPING = new TokenType.con2('BACKPING', 65, null, "`"
); |
| 498 static final TokenType BACKSLASH = new TokenType.con2('BACKSLASH', 66, null, "
\\"); |
| 499 static final TokenType PERIOD_PERIOD_PERIOD = new TokenType.con2('PERIOD_PERIO
D_PERIOD', 67, null, "..."); |
| 500 static final List<TokenType> values = [EOF, DOUBLE, HEXADECIMAL, IDENTIFIER, I
NT, KEYWORD, MULTI_LINE_COMMENT, SCRIPT_TAG, SINGLE_LINE_COMMENT, STRING, AMPERS
AND, AMPERSAND_AMPERSAND, AMPERSAND_EQ, AT, BANG, BANG_EQ, BAR, BAR_BAR, BAR_EQ,
COLON, COMMA, CARET, CARET_EQ, CLOSE_CURLY_BRACKET, CLOSE_PAREN, CLOSE_SQUARE_B
RACKET, EQ, EQ_EQ, FUNCTION, GT, GT_EQ, GT_GT, GT_GT_EQ, HASH, INDEX, INDEX_EQ,
IS, LT, LT_EQ, LT_LT, LT_LT_EQ, MINUS, MINUS_EQ, MINUS_MINUS, OPEN_CURLY_BRACKET
, OPEN_PAREN, OPEN_SQUARE_BRACKET, PERCENT, PERCENT_EQ, PERIOD, PERIOD_PERIOD, P
LUS, PLUS_EQ, PLUS_PLUS, QUESTION, SEMICOLON, SLASH, SLASH_EQ, STAR, STAR_EQ, ST
RING_INTERPOLATION_EXPRESSION, STRING_INTERPOLATION_IDENTIFIER, TILDE, TILDE_SLA
SH, TILDE_SLASH_EQ, BACKPING, BACKSLASH, PERIOD_PERIOD_PERIOD]; |
| 501 String __name; |
| 502 int __ordinal = 0; |
| 503 /** |
| 504 * The class of the token. |
| 505 */ |
| 506 TokenClass _tokenClass; |
| 507 /** |
| 508 * The lexeme that defines this type of token, or {@code null} if there is mor
e than one possible |
| 509 * lexeme for this type of token. |
| 510 */ |
| 511 String _lexeme; |
| 512 TokenType.con1(String ___name, int ___ordinal) { |
| 513 _jtd_constructor_227_impl(___name, ___ordinal); |
| 514 } |
| 515 _jtd_constructor_227_impl(String ___name, int ___ordinal) { |
| 516 _jtd_constructor_228_impl(___name, ___ordinal, TokenClass.NO_CLASS, null); |
| 517 } |
| 518 TokenType.con2(String ___name, int ___ordinal, TokenClass tokenClass, String l
exeme) { |
| 519 _jtd_constructor_228_impl(___name, ___ordinal, tokenClass, lexeme); |
| 520 } |
| 521 _jtd_constructor_228_impl(String ___name, int ___ordinal, TokenClass tokenClas
s, String lexeme) { |
| 522 __name = ___name; |
| 523 __ordinal = ___ordinal; |
| 524 this._tokenClass = tokenClass == null ? TokenClass.NO_CLASS : tokenClass; |
| 525 this._lexeme = lexeme; |
| 526 } |
| 527 /** |
| 528 * Return the lexeme that defines this type of token, or {@code null} if there
is more than one |
| 529 * possible lexeme for this type of token. |
| 530 * @return the lexeme that defines this type of token |
| 531 */ |
| 532 String get lexeme => _lexeme; |
| 533 /** |
| 534 * Return the precedence of the token, or {@code 0} if the token does not repr
esent an operator. |
| 535 * @return the precedence of the token |
| 536 */ |
| 537 int get precedence => _tokenClass.precedence; |
| 538 /** |
| 539 * Return {@code true} if this type of token represents an additive operator. |
| 540 * @return {@code true} if this type of token represents an additive operator |
| 541 */ |
| 542 bool isAdditiveOperator() => _tokenClass == TokenClass.ADDITIVE_OPERATOR; |
| 543 /** |
| 544 * Return {@code true} if this type of token represents an assignment operator
. |
| 545 * @return {@code true} if this type of token represents an assignment operato
r |
| 546 */ |
| 547 bool isAssignmentOperator() => _tokenClass == TokenClass.ASSIGNMENT_OPERATOR; |
| 548 /** |
| 549 * Return {@code true} if this type of token represents an equality operator. |
| 550 * @return {@code true} if this type of token represents an equality operator |
| 551 */ |
| 552 bool isEqualityOperator() => _tokenClass == TokenClass.EQUALITY_OPERATOR; |
| 553 /** |
| 554 * Return {@code true} if this type of token represents an increment operator. |
| 555 * @return {@code true} if this type of token represents an increment operator |
| 556 */ |
| 557 bool isIncrementOperator() => _lexeme == "++" || _lexeme == "--"; |
| 558 /** |
| 559 * Return {@code true} if this type of token represents a multiplicative opera
tor. |
| 560 * @return {@code true} if this type of token represents a multiplicative oper
ator |
| 561 */ |
| 562 bool isMultiplicativeOperator() => _tokenClass == TokenClass.MULTIPLICATIVE_OP
ERATOR; |
| 563 /** |
| 564 * Return {@code true} if this token type represents an operator. |
| 565 * @return {@code true} if this token type represents an operator |
| 566 */ |
| 567 bool isOperator() => _tokenClass != TokenClass.NO_CLASS && this != TokenType.O
PEN_PAREN && this != TokenType.OPEN_SQUARE_BRACKET && this != TokenType.PERIOD; |
| 568 /** |
| 569 * Return {@code true} if this type of token represents a relational operator. |
| 570 * @return {@code true} if this type of token represents a relational operator |
| 571 */ |
| 572 bool isRelationalOperator() => _tokenClass == TokenClass.RELATIONAL_OPERATOR; |
| 573 /** |
| 574 * Return {@code true} if this type of token represents a shift operator. |
| 575 * @return {@code true} if this type of token represents a shift operator |
| 576 */ |
| 577 bool isShiftOperator() => _tokenClass == TokenClass.SHIFT_OPERATOR; |
| 578 /** |
| 579 * Return {@code true} if this type of token represents a unary postfix operat
or. |
| 580 * @return {@code true} if this type of token represents a unary postfix opera
tor |
| 581 */ |
| 582 bool isUnaryPostfixOperator() => _tokenClass == TokenClass.UNARY_POSTFIX_OPERA
TOR; |
| 583 /** |
| 584 * Return {@code true} if this type of token represents a unary prefix operato
r. |
| 585 * @return {@code true} if this type of token represents a unary prefix operat
or |
| 586 */ |
| 587 bool isUnaryPrefixOperator() => _tokenClass == TokenClass.UNARY_PREFIX_OPERATO
R; |
| 588 /** |
| 589 * Return {@code true} if this token type represents an operator that can be d
efined by users. |
| 590 * @return {@code true} if this token type represents an operator that can be
defined by users |
| 591 */ |
| 592 bool isUserDefinableOperator() => _lexeme == "==" || _lexeme == "~" || _lexeme
== "[]" || _lexeme == "[]=" || _lexeme == "*" || _lexeme == "/" || _lexeme == "
%" || _lexeme == "~/" || _lexeme == "+" || _lexeme == "-" || _lexeme == "<<" ||
_lexeme == ">>" || _lexeme == ">=" || _lexeme == ">" || _lexeme == "<=" || _lexe
me == "<" || _lexeme == "&" || _lexeme == "^" || _lexeme == "|"; |
| 593 String toString() => __name; |
| 594 } |
| 595 class TokenType_EOF extends TokenType { |
| 596 TokenType_EOF(String ___name, int ___ordinal, TokenClass arg0, String arg1) :
super.con2(___name, ___ordinal, arg0, arg1); |
| 597 String toString() => "-eof-"; |
| 598 } |
| 599 /** |
| 600 * Instances of the class {@code TokenWithComment} represent a string token that
is preceded by |
| 601 * comments. |
| 602 */ |
| 603 class StringTokenWithComment extends StringToken { |
| 604 /** |
| 605 * The first comment in the list of comments that precede this token. |
| 606 */ |
| 607 Token _precedingComment; |
| 608 /** |
| 609 * Initialize a newly created token to have the given type and offset and to b
e preceded by the |
| 610 * comments reachable from the given comment. |
| 611 * @param type the type of the token |
| 612 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 613 * @param precedingComment the first comment in the list of comments that prec
ede this token |
| 614 */ |
| 615 StringTokenWithComment(TokenType type, String value, int offset, Token precedi
ngComment) : super(type, value, offset) { |
| 616 this._precedingComment = precedingComment; |
| 617 } |
| 618 Token get precedingComments => _precedingComment; |
| 619 } |
| 620 /** |
| 621 * Instances of the class {@code BeginToken} represent the opening half of a gro
uping pair of |
| 622 * tokens. This is used for curly brackets ('{'), parentheses ('('), and square
brackets ('['). |
| 623 */ |
| 624 class BeginToken extends Token { |
| 625 /** |
| 626 * The token that corresponds to this token. |
| 627 */ |
| 628 Token _endToken; |
| 629 /** |
| 630 * Initialize a newly created token representing the opening half of a groupin
g pair of tokens. |
| 631 * @param type the type of the token |
| 632 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 633 */ |
| 634 BeginToken(TokenType type, int offset) : super(type, offset) { |
| 635 assert((type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.OPEN_PAREN
|| type == TokenType.OPEN_SQUARE_BRACKET || type == TokenType.STRING_INTERPOLAT
ION_EXPRESSION)); |
| 636 } |
| 637 /** |
| 638 * Return the token that corresponds to this token. |
| 639 * @return the token that corresponds to this token |
| 640 */ |
| 641 Token get endToken => _endToken; |
| 642 /** |
| 643 * Set the token that corresponds to this token to the given token. |
| 644 * @param token the token that corresponds to this token |
| 645 */ |
| 646 void set endToken2(Token token) { |
| 647 this._endToken = token; |
| 648 } |
| 649 } |
| 650 /** |
| 651 * The enumeration {@code TokenClass} represents classes (or groups) of tokens w
ith a similar use. |
| 652 */ |
| 653 class TokenClass { |
| 654 /** |
| 655 * A value used to indicate that the token type is not part of any specific cl
ass of token. |
| 656 */ |
| 657 static final TokenClass NO_CLASS = new TokenClass.con1('NO_CLASS', 0); |
| 658 /** |
| 659 * A value used to indicate that the token type is an additive operator. |
| 660 */ |
| 661 static final TokenClass ADDITIVE_OPERATOR = new TokenClass.con2('ADDITIVE_OPER
ATOR', 1, 12); |
| 662 /** |
| 663 * A value used to indicate that the token type is an assignment operator. |
| 664 */ |
| 665 static final TokenClass ASSIGNMENT_OPERATOR = new TokenClass.con2('ASSIGNMENT_
OPERATOR', 2, 1); |
| 666 /** |
| 667 * A value used to indicate that the token type is a bitwise-and operator. |
| 668 */ |
| 669 static final TokenClass BITWISE_AND_OPERATOR = new TokenClass.con2('BITWISE_AN
D_OPERATOR', 3, 8); |
| 670 /** |
| 671 * A value used to indicate that the token type is a bitwise-or operator. |
| 672 */ |
| 673 static final TokenClass BITWISE_OR_OPERATOR = new TokenClass.con2('BITWISE_OR_
OPERATOR', 4, 6); |
| 674 /** |
| 675 * A value used to indicate that the token type is a bitwise-xor operator. |
| 676 */ |
| 677 static final TokenClass BITWISE_XOR_OPERATOR = new TokenClass.con2('BITWISE_XO
R_OPERATOR', 5, 7); |
| 678 /** |
| 679 * A value used to indicate that the token type is a cascade operator. |
| 680 */ |
| 681 static final TokenClass CASCADE_OPERATOR = new TokenClass.con2('CASCADE_OPERAT
OR', 6, 2); |
| 682 /** |
| 683 * A value used to indicate that the token type is a conditional operator. |
| 684 */ |
| 685 static final TokenClass CONDITIONAL_OPERATOR = new TokenClass.con2('CONDITIONA
L_OPERATOR', 7, 3); |
| 686 /** |
| 687 * A value used to indicate that the token type is an equality operator. |
| 688 */ |
| 689 static final TokenClass EQUALITY_OPERATOR = new TokenClass.con2('EQUALITY_OPER
ATOR', 8, 9); |
| 690 /** |
| 691 * A value used to indicate that the token type is a logical-and operator. |
| 692 */ |
| 693 static final TokenClass LOGICAL_AND_OPERATOR = new TokenClass.con2('LOGICAL_AN
D_OPERATOR', 9, 5); |
| 694 /** |
| 695 * A value used to indicate that the token type is a logical-or operator. |
| 696 */ |
| 697 static final TokenClass LOGICAL_OR_OPERATOR = new TokenClass.con2('LOGICAL_OR_
OPERATOR', 10, 4); |
| 698 /** |
| 699 * A value used to indicate that the token type is a multiplicative operator. |
| 700 */ |
| 701 static final TokenClass MULTIPLICATIVE_OPERATOR = new TokenClass.con2('MULTIPL
ICATIVE_OPERATOR', 11, 13); |
| 702 /** |
| 703 * A value used to indicate that the token type is a relational operator. |
| 704 */ |
| 705 static final TokenClass RELATIONAL_OPERATOR = new TokenClass.con2('RELATIONAL_
OPERATOR', 12, 10); |
| 706 /** |
| 707 * A value used to indicate that the token type is a shift operator. |
| 708 */ |
| 709 static final TokenClass SHIFT_OPERATOR = new TokenClass.con2('SHIFT_OPERATOR',
13, 11); |
| 710 /** |
| 711 * A value used to indicate that the token type is a unary operator. |
| 712 */ |
| 713 static final TokenClass UNARY_POSTFIX_OPERATOR = new TokenClass.con2('UNARY_PO
STFIX_OPERATOR', 14, 15); |
| 714 /** |
| 715 * A value used to indicate that the token type is a unary operator. |
| 716 */ |
| 717 static final TokenClass UNARY_PREFIX_OPERATOR = new TokenClass.con2('UNARY_PRE
FIX_OPERATOR', 15, 14); |
| 718 static final List<TokenClass> values = [NO_CLASS, ADDITIVE_OPERATOR, ASSIGNMEN
T_OPERATOR, BITWISE_AND_OPERATOR, BITWISE_OR_OPERATOR, BITWISE_XOR_OPERATOR, CAS
CADE_OPERATOR, CONDITIONAL_OPERATOR, EQUALITY_OPERATOR, LOGICAL_AND_OPERATOR, LO
GICAL_OR_OPERATOR, MULTIPLICATIVE_OPERATOR, RELATIONAL_OPERATOR, SHIFT_OPERATOR,
UNARY_POSTFIX_OPERATOR, UNARY_PREFIX_OPERATOR]; |
| 719 String __name; |
| 720 int __ordinal = 0; |
| 721 /** |
| 722 * The precedence of tokens of this class, or {@code 0} if the such tokens do
not represent an |
| 723 * operator. |
| 724 */ |
| 725 int _precedence = 0; |
| 726 TokenClass.con1(String ___name, int ___ordinal) { |
| 727 _jtd_constructor_225_impl(___name, ___ordinal); |
| 728 } |
| 729 _jtd_constructor_225_impl(String ___name, int ___ordinal) { |
| 730 _jtd_constructor_226_impl(___name, ___ordinal, 0); |
| 731 } |
| 732 TokenClass.con2(String ___name, int ___ordinal, int precedence) { |
| 733 _jtd_constructor_226_impl(___name, ___ordinal, precedence); |
| 734 } |
| 735 _jtd_constructor_226_impl(String ___name, int ___ordinal, int precedence) { |
| 736 __name = ___name; |
| 737 __ordinal = ___ordinal; |
| 738 this._precedence = precedence; |
| 739 } |
| 740 /** |
| 741 * Return the precedence of tokens of this class, or {@code 0} if the such tok
ens do not represent |
| 742 * an operator. |
| 743 * @return the precedence of tokens of this class |
| 744 */ |
| 745 int get precedence => _precedence; |
| 746 String toString() => __name; |
| 747 } |
| 748 /** |
| 749 * Instances of the class {@code StringScanner} implement a scanner that reads f
rom a string. The |
| 750 * scanning logic is in the superclass. |
| 751 */ |
| 752 class StringScanner extends AbstractScanner { |
| 753 /** |
| 754 * The offset from the beginning of the file to the beginning of the source be
ing scanned. |
| 755 */ |
| 756 int _offsetDelta = 0; |
| 757 /** |
| 758 * The string from which characters will be read. |
| 759 */ |
| 760 String _string; |
| 761 /** |
| 762 * The number of characters in the string. |
| 763 */ |
| 764 int _stringLength = 0; |
| 765 /** |
| 766 * The index, relative to the string, of the last character that was read. |
| 767 */ |
| 768 int _charOffset = 0; |
| 769 /** |
| 770 * Initialize a newly created scanner to scan the characters in the given stri
ng. |
| 771 * @param source the source being scanned |
| 772 * @param string the string from which characters will be read |
| 773 * @param errorListener the error listener that will be informed of any errors
that are found |
| 774 */ |
| 775 StringScanner(Source source, String string, AnalysisErrorListener errorListene
r) : super(source, errorListener) { |
| 776 this._offsetDelta = 0; |
| 777 this._string = string; |
| 778 this._stringLength = string.length; |
| 779 this._charOffset = -1; |
| 780 } |
| 781 int get offset => _offsetDelta + _charOffset; |
| 782 /** |
| 783 * Record that the source begins on the given line and column at the given off
set. The line starts |
| 784 * for lines before the given line will not be correct. |
| 785 * <p> |
| 786 * This method must be invoked at most one time and must be invoked before sca
nning begins. The |
| 787 * values provided must be sensible. The results are undefined if these condit
ions are violated. |
| 788 * @param line the one-based index of the line containing the first character
of the source |
| 789 * @param column the one-based index of the column in which the first characte
r of the source |
| 790 * occurs |
| 791 * @param offset the zero-based offset from the beginning of the larger contex
t to the first |
| 792 * character of the source |
| 793 */ |
| 794 void setSourceStart(int line, int column, int offset) { |
| 795 if (line < 1 || column < 1 || offset < 0 || (line + column - 2) >= offset) { |
| 796 return; |
| 797 } |
| 798 _offsetDelta = 1; |
| 799 for (int i = 2; i < line; i++) { |
| 800 recordStartOfLine(); |
| 801 } |
| 802 _offsetDelta = offset - column + 1; |
| 803 recordStartOfLine(); |
| 804 _offsetDelta = offset; |
| 805 } |
| 806 int advance() { |
| 807 if (_charOffset + 1 >= _stringLength) { |
| 808 return -1; |
| 809 } |
| 810 return _string.charCodeAt(++_charOffset); |
| 811 } |
| 812 String getString(int start, int endDelta) => _string.substring(start - _offset
Delta, _charOffset + 1 + endDelta); |
| 813 int peek() { |
| 814 if (_charOffset + 1 >= _string.length) { |
| 815 return -1; |
| 816 } |
| 817 return _string.charCodeAt(_charOffset + 1); |
| 818 } |
| 819 } |
| 820 /** |
| 821 * The abstract class {@code AbstractScanner} implements a scanner for Dart code
. Subclasses are |
| 822 * required to implement the interface used to access the characters being scann
ed. |
| 823 * <p> |
| 824 * The lexical structure of Dart is ambiguous without knowledge of the context i
n which a token is |
| 825 * being scanned. For example, without context we cannot determine whether sourc
e of the form "<<" |
| 826 * should be scanned as a single left-shift operator or as two left angle bracke
ts. This scanner |
| 827 * does not have any context, so it always resolves such conflicts by scanning t
he longest possible |
| 828 * token. |
| 829 */ |
| 830 abstract class AbstractScanner { |
| 831 /** |
| 832 * The source being scanned. |
| 833 */ |
| 834 Source _source; |
| 835 /** |
| 836 * The error listener that will be informed of any errors that are found durin
g the scan. |
| 837 */ |
| 838 AnalysisErrorListener _errorListener; |
| 839 /** |
| 840 * The token pointing to the head of the linked list of tokens. |
| 841 */ |
| 842 Token _tokens; |
| 843 /** |
| 844 * The last token that was scanned. |
| 845 */ |
| 846 Token _tail; |
| 847 /** |
| 848 * The first token in the list of comment tokens found since the last non-comm
ent token. |
| 849 */ |
| 850 Token _firstComment; |
| 851 /** |
| 852 * The last token in the list of comment tokens found since the last non-comme
nt token. |
| 853 */ |
| 854 Token _lastComment; |
| 855 /** |
| 856 * The index of the first character of the current token. |
| 857 */ |
| 858 int _tokenStart = 0; |
| 859 /** |
| 860 * A list containing the offsets of the first character of each line in the so
urce code. |
| 861 */ |
| 862 List<int> _lineStarts = new List<int>(); |
| 863 /** |
| 864 * A list, treated something like a stack, of tokens representing the beginnin
g of a matched pair. |
| 865 * It is used to pair the end tokens with the begin tokens. |
| 866 */ |
| 867 List<BeginToken> _groupingStack = new List<BeginToken>(); |
| 868 /** |
| 869 * A flag indicating whether any unmatched groups were found during the parse. |
| 870 */ |
| 871 bool _hasUnmatchedGroups2 = false; |
| 872 /** |
| 873 * A non-breaking space, which is allowed by this scanner as a white-space cha
racter. |
| 874 */ |
| 875 static int _$NBSP = 160; |
| 876 /** |
| 877 * Initialize a newly created scanner. |
| 878 * @param source the source being scanned |
| 879 * @param errorListener the error listener that will be informed of any errors
that are found |
| 880 */ |
| 881 AbstractScanner(Source source, AnalysisErrorListener errorListener) { |
| 882 this._source = source; |
| 883 this._errorListener = errorListener; |
| 884 _tokens = new Token(TokenType.EOF, -1); |
| 885 _tokens.setNext(_tokens); |
| 886 _tail = _tokens; |
| 887 _tokenStart = -1; |
| 888 _lineStarts.add(0); |
| 889 } |
| 890 /** |
| 891 * Return an array containing the offsets of the first character of each line
in the source code. |
| 892 * @return an array containing the offsets of the first character of each line
in the source code |
| 893 */ |
| 894 List<int> get lineStarts => _lineStarts; |
| 895 /** |
| 896 * Return the current offset relative to the beginning of the file. Return the
initial offset if |
| 897 * the scanner has not yet scanned the source code, and one (1) past the end o
f the source code if |
| 898 * the source code has been scanned. |
| 899 * @return the current offset of the scanner in the source |
| 900 */ |
| 901 int get offset; |
| 902 /** |
| 903 * Return {@code true} if any unmatched groups were found during the parse. |
| 904 * @return {@code true} if any unmatched groups were found during the parse |
| 905 */ |
| 906 bool hasUnmatchedGroups() => _hasUnmatchedGroups2; |
| 907 /** |
| 908 * Scan the source code to produce a list of tokens representing the source. |
| 909 * @return the first token in the list of tokens that were produced |
| 910 */ |
| 911 Token tokenize() { |
| 912 int startTime = System.currentTimeMillis(); |
| 913 int next = advance(); |
| 914 while (next != -1) { |
| 915 next = bigSwitch(next); |
| 916 } |
| 917 appendEofToken(); |
| 918 int endTime = System.currentTimeMillis(); |
| 919 Instrumentation.metric2("Engine-Scanner", endTime - startTime).with3("chars"
, offset).log(); |
| 920 return firstToken(); |
| 921 } |
| 922 /** |
| 923 * Advance the current position and return the character at the new current po
sition. |
| 924 * @return the character at the new current position |
| 925 */ |
| 926 int advance(); |
| 927 /** |
| 928 * Return the substring of the source code between the start offset and the mo
dified current |
| 929 * position. The current position is modified by adding the end delta. |
| 930 * @param start the offset to the beginning of the string, relative to the sta
rt of the file |
| 931 * @param endDelta the number of character after the current location to be in
cluded in the |
| 932 * string, or the number of characters before the current location to be exclu
ded if the |
| 933 * offset is negative |
| 934 * @return the specified substring of the source code |
| 935 */ |
| 936 String getString(int start, int endDelta); |
| 937 /** |
| 938 * Return the character at the current position without changing the current p
osition. |
| 939 * @return the character at the current position |
| 940 */ |
| 941 int peek(); |
| 942 /** |
| 943 * Record the fact that we are at the beginning of a new line in the source. |
| 944 */ |
| 945 void recordStartOfLine() { |
| 946 _lineStarts.add(offset); |
| 947 } |
| 948 void appendBeginToken(TokenType type) { |
| 949 BeginToken token; |
| 950 if (_firstComment == null) { |
| 951 token = new BeginToken(type, _tokenStart); |
| 952 } else { |
| 953 token = new BeginTokenWithComment(type, _tokenStart, _firstComment); |
| 954 _firstComment = null; |
| 955 _lastComment = null; |
| 956 } |
| 957 _tail = _tail.setNext(token); |
| 958 _groupingStack.add(token); |
| 959 } |
| 960 void appendCommentToken(TokenType type, String value) { |
| 961 if (_firstComment == null) { |
| 962 _firstComment = new StringToken(type, value, _tokenStart); |
| 963 _lastComment = _firstComment; |
| 964 } else { |
| 965 _lastComment = _lastComment.setNext(new StringToken(type, value, _tokenSta
rt)); |
| 966 } |
| 967 } |
| 968 void appendEndToken(TokenType type, TokenType beginType) { |
| 969 Token token; |
| 970 if (_firstComment == null) { |
| 971 token = new Token(type, _tokenStart); |
| 972 } else { |
| 973 token = new TokenWithComment(type, _tokenStart, _firstComment); |
| 974 _firstComment = null; |
| 975 _lastComment = null; |
| 976 } |
| 977 _tail = _tail.setNext(token); |
| 978 int last = _groupingStack.length - 1; |
| 979 if (last >= 0) { |
| 980 BeginToken begin = _groupingStack[last]; |
| 981 if (begin.type == beginType) { |
| 982 begin.endToken2 = token; |
| 983 _groupingStack.removeAt(last); |
| 984 } |
| 985 } |
| 986 } |
| 987 void appendEofToken() { |
| 988 Token eofToken; |
| 989 if (_firstComment == null) { |
| 990 eofToken = new Token(TokenType.EOF, offset + 1); |
| 991 } else { |
| 992 eofToken = new TokenWithComment(TokenType.EOF, offset + 1, _firstComment); |
| 993 _firstComment = null; |
| 994 _lastComment = null; |
| 995 } |
| 996 eofToken.setNext(eofToken); |
| 997 _tail = _tail.setNext(eofToken); |
| 998 if (!_groupingStack.isEmpty) { |
| 999 _hasUnmatchedGroups2 = true; |
| 1000 } |
| 1001 } |
| 1002 void appendKeywordToken(Keyword keyword) { |
| 1003 if (_firstComment == null) { |
| 1004 _tail = _tail.setNext(new KeywordToken(keyword, _tokenStart)); |
| 1005 } else { |
| 1006 _tail = _tail.setNext(new KeywordTokenWithComment(keyword, _tokenStart, _f
irstComment)); |
| 1007 _firstComment = null; |
| 1008 _lastComment = null; |
| 1009 } |
| 1010 } |
| 1011 void appendStringToken(TokenType type, String value) { |
| 1012 if (_firstComment == null) { |
| 1013 _tail = _tail.setNext(new StringToken(type, value, _tokenStart)); |
| 1014 } else { |
| 1015 _tail = _tail.setNext(new StringTokenWithComment(type, value, _tokenStart,
_firstComment)); |
| 1016 _firstComment = null; |
| 1017 _lastComment = null; |
| 1018 } |
| 1019 } |
| 1020 void appendStringToken2(TokenType type, String value, int offset) { |
| 1021 if (_firstComment == null) { |
| 1022 _tail = _tail.setNext(new StringToken(type, value, _tokenStart + offset)); |
| 1023 } else { |
| 1024 _tail = _tail.setNext(new StringTokenWithComment(type, value, _tokenStart
+ offset, _firstComment)); |
| 1025 _firstComment = null; |
| 1026 _lastComment = null; |
| 1027 } |
| 1028 } |
| 1029 void appendToken(TokenType type) { |
| 1030 if (_firstComment == null) { |
| 1031 _tail = _tail.setNext(new Token(type, _tokenStart)); |
| 1032 } else { |
| 1033 _tail = _tail.setNext(new TokenWithComment(type, _tokenStart, _firstCommen
t)); |
| 1034 _firstComment = null; |
| 1035 _lastComment = null; |
| 1036 } |
| 1037 } |
| 1038 void appendToken2(TokenType type, int offset) { |
| 1039 if (_firstComment == null) { |
| 1040 _tail = _tail.setNext(new Token(type, offset)); |
| 1041 } else { |
| 1042 _tail = _tail.setNext(new TokenWithComment(type, offset, _firstComment)); |
| 1043 _firstComment = null; |
| 1044 _lastComment = null; |
| 1045 } |
| 1046 } |
| 1047 void beginToken() { |
| 1048 _tokenStart = offset; |
| 1049 } |
| 1050 int bigSwitch(int next) { |
| 1051 beginToken(); |
| 1052 if (next == 0xd) { |
| 1053 next = advance(); |
| 1054 if (next == 0xa) { |
| 1055 next = advance(); |
| 1056 } |
| 1057 recordStartOfLine(); |
| 1058 return next; |
| 1059 } else if (next == 0xa) { |
| 1060 recordStartOfLine(); |
| 1061 return advance(); |
| 1062 } else if (next == 0x9 || next == 0x20) { |
| 1063 return advance(); |
| 1064 } |
| 1065 if (next == 0x72) { |
| 1066 int peek3 = peek(); |
| 1067 if (peek3 == 0x22 || peek3 == 0x27) { |
| 1068 int start = offset; |
| 1069 return tokenizeString(advance(), start, true); |
| 1070 } |
| 1071 } |
| 1072 if (0x61 <= next && next <= 0x7a) { |
| 1073 return tokenizeKeywordOrIdentifier(next, true); |
| 1074 } |
| 1075 if ((0x41 <= next && next <= 0x5a) || next == 0x5f || next == 0x24) { |
| 1076 return tokenizeIdentifier(next, offset, true); |
| 1077 } |
| 1078 if (next == 0x3c) { |
| 1079 return tokenizeLessThan(next); |
| 1080 } |
| 1081 if (next == 0x3e) { |
| 1082 return tokenizeGreaterThan(next); |
| 1083 } |
| 1084 if (next == 0x3d) { |
| 1085 return tokenizeEquals(next); |
| 1086 } |
| 1087 if (next == 0x21) { |
| 1088 return tokenizeExclamation(next); |
| 1089 } |
| 1090 if (next == 0x2b) { |
| 1091 return tokenizePlus(next); |
| 1092 } |
| 1093 if (next == 0x2d) { |
| 1094 return tokenizeMinus(next); |
| 1095 } |
| 1096 if (next == 0x2a) { |
| 1097 return tokenizeMultiply(next); |
| 1098 } |
| 1099 if (next == 0x25) { |
| 1100 return tokenizePercent(next); |
| 1101 } |
| 1102 if (next == 0x26) { |
| 1103 return tokenizeAmpersand(next); |
| 1104 } |
| 1105 if (next == 0x7c) { |
| 1106 return tokenizeBar(next); |
| 1107 } |
| 1108 if (next == 0x5e) { |
| 1109 return tokenizeCaret(next); |
| 1110 } |
| 1111 if (next == 0x5b) { |
| 1112 return tokenizeOpenSquareBracket(next); |
| 1113 } |
| 1114 if (next == 0x7e) { |
| 1115 return tokenizeTilde(next); |
| 1116 } |
| 1117 if (next == 0x5c) { |
| 1118 appendToken(TokenType.BACKSLASH); |
| 1119 return advance(); |
| 1120 } |
| 1121 if (next == 0x23) { |
| 1122 return tokenizeTag(next); |
| 1123 } |
| 1124 if (next == 0x28) { |
| 1125 appendBeginToken(TokenType.OPEN_PAREN); |
| 1126 return advance(); |
| 1127 } |
| 1128 if (next == 0x29) { |
| 1129 appendEndToken(TokenType.CLOSE_PAREN, TokenType.OPEN_PAREN); |
| 1130 return advance(); |
| 1131 } |
| 1132 if (next == 0x2c) { |
| 1133 appendToken(TokenType.COMMA); |
| 1134 return advance(); |
| 1135 } |
| 1136 if (next == 0x3a) { |
| 1137 appendToken(TokenType.COLON); |
| 1138 return advance(); |
| 1139 } |
| 1140 if (next == 0x3b) { |
| 1141 appendToken(TokenType.SEMICOLON); |
| 1142 return advance(); |
| 1143 } |
| 1144 if (next == 0x3f) { |
| 1145 appendToken(TokenType.QUESTION); |
| 1146 return advance(); |
| 1147 } |
| 1148 if (next == 0x5d) { |
| 1149 appendEndToken(TokenType.CLOSE_SQUARE_BRACKET, TokenType.OPEN_SQUARE_BRACK
ET); |
| 1150 return advance(); |
| 1151 } |
| 1152 if (next == 0x60) { |
| 1153 appendToken(TokenType.BACKPING); |
| 1154 return advance(); |
| 1155 } |
| 1156 if (next == 0x7b) { |
| 1157 appendBeginToken(TokenType.OPEN_CURLY_BRACKET); |
| 1158 return advance(); |
| 1159 } |
| 1160 if (next == 0x7d) { |
| 1161 appendEndToken(TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET
); |
| 1162 return advance(); |
| 1163 } |
| 1164 if (next == 0x2f) { |
| 1165 return tokenizeSlashOrComment(next); |
| 1166 } |
| 1167 if (next == 0x40) { |
| 1168 appendToken(TokenType.AT); |
| 1169 return advance(); |
| 1170 } |
| 1171 if (next == 0x22 || next == 0x27) { |
| 1172 return tokenizeString(next, offset, false); |
| 1173 } |
| 1174 if (next == 0x2e) { |
| 1175 return tokenizeDotOrNumber(next); |
| 1176 } |
| 1177 if (next == 0x30) { |
| 1178 return tokenizeHexOrNumber(next); |
| 1179 } |
| 1180 if (0x31 <= next && next <= 0x39) { |
| 1181 return tokenizeNumber(next); |
| 1182 } |
| 1183 if (next == -1) { |
| 1184 return -1; |
| 1185 } |
| 1186 if (Character.isLetter(next)) { |
| 1187 return tokenizeIdentifier(next, offset, true); |
| 1188 } |
| 1189 if (next == AbstractScanner._$NBSP) { |
| 1190 return advance(); |
| 1191 } |
| 1192 reportError(ScannerErrorCode.ILLEGAL_CHARACTER, [next]); |
| 1193 return advance(); |
| 1194 } |
| 1195 /** |
| 1196 * Return the beginning token corresponding to a closing brace that was found
while scanning |
| 1197 * inside a string interpolation expression. Tokens that cannot be matched wit
h the closing brace |
| 1198 * will be dropped from the stack. |
| 1199 * @return the token to be paired with the closing brace |
| 1200 */ |
| 1201 BeginToken findTokenMatchingClosingBraceInInterpolationExpression() { |
| 1202 int last = _groupingStack.length - 1; |
| 1203 while (last >= 0) { |
| 1204 BeginToken begin = _groupingStack[last]; |
| 1205 if (begin.type == TokenType.OPEN_CURLY_BRACKET || begin.type == TokenType.
STRING_INTERPOLATION_EXPRESSION) { |
| 1206 return begin; |
| 1207 } |
| 1208 _hasUnmatchedGroups2 = true; |
| 1209 _groupingStack.removeAt(last); |
| 1210 last--; |
| 1211 } |
| 1212 return null; |
| 1213 } |
| 1214 Token firstToken() => _tokens.next; |
| 1215 /** |
| 1216 * Return the source being scanned. |
| 1217 * @return the source being scanned |
| 1218 */ |
| 1219 Source get source => _source; |
| 1220 /** |
| 1221 * Report an error at the current offset. |
| 1222 * @param errorCode the error code indicating the nature of the error |
| 1223 * @param arguments any arguments needed to complete the error message |
| 1224 */ |
| 1225 void reportError(ScannerErrorCode errorCode, List<Object> arguments) { |
| 1226 _errorListener.onError(new AnalysisError.con2(source, offset, 1, errorCode,
[arguments])); |
| 1227 } |
| 1228 int select(int choice, TokenType yesType, TokenType noType) { |
| 1229 int next = advance(); |
| 1230 if (next == choice) { |
| 1231 appendToken(yesType); |
| 1232 return advance(); |
| 1233 } else { |
| 1234 appendToken(noType); |
| 1235 return next; |
| 1236 } |
| 1237 } |
| 1238 int select2(int choice, TokenType yesType, TokenType noType, int offset) { |
| 1239 int next = advance(); |
| 1240 if (next == choice) { |
| 1241 appendToken2(yesType, offset); |
| 1242 return advance(); |
| 1243 } else { |
| 1244 appendToken2(noType, offset); |
| 1245 return next; |
| 1246 } |
| 1247 } |
| 1248 int tokenizeAmpersand(int next) { |
| 1249 next = advance(); |
| 1250 if (next == 0x26) { |
| 1251 appendToken(TokenType.AMPERSAND_AMPERSAND); |
| 1252 return advance(); |
| 1253 } else if (next == 0x3d) { |
| 1254 appendToken(TokenType.AMPERSAND_EQ); |
| 1255 return advance(); |
| 1256 } else { |
| 1257 appendToken(TokenType.AMPERSAND); |
| 1258 return next; |
| 1259 } |
| 1260 } |
| 1261 int tokenizeBar(int next) { |
| 1262 next = advance(); |
| 1263 if (next == 0x7c) { |
| 1264 appendToken(TokenType.BAR_BAR); |
| 1265 return advance(); |
| 1266 } else if (next == 0x3d) { |
| 1267 appendToken(TokenType.BAR_EQ); |
| 1268 return advance(); |
| 1269 } else { |
| 1270 appendToken(TokenType.BAR); |
| 1271 return next; |
| 1272 } |
| 1273 } |
| 1274 int tokenizeCaret(int next) => select(0x3d, TokenType.CARET_EQ, TokenType.CARE
T); |
| 1275 int tokenizeDotOrNumber(int next) { |
| 1276 int start = offset; |
| 1277 next = advance(); |
| 1278 if ((0x30 <= next && next <= 0x39)) { |
| 1279 return tokenizeFractionPart(next, start); |
| 1280 } else if (0x2e == next) { |
| 1281 return select(0x2e, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIO
D); |
| 1282 } else { |
| 1283 appendToken(TokenType.PERIOD); |
| 1284 return next; |
| 1285 } |
| 1286 } |
| 1287 int tokenizeEquals(int next) { |
| 1288 next = advance(); |
| 1289 if (next == 0x3d) { |
| 1290 appendToken(TokenType.EQ_EQ); |
| 1291 return advance(); |
| 1292 } else if (next == 0x3e) { |
| 1293 appendToken(TokenType.FUNCTION); |
| 1294 return advance(); |
| 1295 } |
| 1296 appendToken(TokenType.EQ); |
| 1297 return next; |
| 1298 } |
| 1299 int tokenizeExclamation(int next) { |
| 1300 next = advance(); |
| 1301 if (next == 0x3d) { |
| 1302 appendToken(TokenType.BANG_EQ); |
| 1303 return advance(); |
| 1304 } |
| 1305 appendToken(TokenType.BANG); |
| 1306 return next; |
| 1307 } |
| 1308 int tokenizeExponent(int next) { |
| 1309 if (next == 0x2b || next == 0x2d) { |
| 1310 next = advance(); |
| 1311 } |
| 1312 bool hasDigits = false; |
| 1313 while (true) { |
| 1314 if (0x30 <= next && next <= 0x39) { |
| 1315 hasDigits = true; |
| 1316 } else { |
| 1317 if (!hasDigits) { |
| 1318 reportError(ScannerErrorCode.MISSING_DIGIT, []); |
| 1319 } |
| 1320 return next; |
| 1321 } |
| 1322 next = advance(); |
| 1323 } |
| 1324 } |
| 1325 int tokenizeFractionPart(int next, int start) { |
| 1326 bool done = false; |
| 1327 bool hasDigit = false; |
| 1328 LOOP: while (!done) { |
| 1329 if (0x30 <= next && next <= 0x39) { |
| 1330 hasDigit = true; |
| 1331 } else if (0x65 == next || 0x45 == next) { |
| 1332 hasDigit = true; |
| 1333 next = tokenizeExponent(advance()); |
| 1334 done = true; |
| 1335 continue LOOP; |
| 1336 } else { |
| 1337 done = true; |
| 1338 continue LOOP; |
| 1339 } |
| 1340 next = advance(); |
| 1341 } |
| 1342 if (!hasDigit) { |
| 1343 appendStringToken(TokenType.INT, getString(start, -2)); |
| 1344 if (0x2e == next) { |
| 1345 return select2(0x2e, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PE
RIOD, offset - 1); |
| 1346 } |
| 1347 appendToken2(TokenType.PERIOD, offset - 1); |
| 1348 return bigSwitch(next); |
| 1349 } |
| 1350 if (next == 0x64 || next == 0x44) { |
| 1351 next = advance(); |
| 1352 } |
| 1353 appendStringToken(TokenType.DOUBLE, getString(start, next < 0 ? 0 : -1)); |
| 1354 return next; |
| 1355 } |
| 1356 int tokenizeGreaterThan(int next) { |
| 1357 next = advance(); |
| 1358 if (0x3d == next) { |
| 1359 appendToken(TokenType.GT_EQ); |
| 1360 return advance(); |
| 1361 } else if (0x3e == next) { |
| 1362 next = advance(); |
| 1363 if (0x3d == next) { |
| 1364 appendToken(TokenType.GT_GT_EQ); |
| 1365 return advance(); |
| 1366 } else { |
| 1367 appendToken(TokenType.GT_GT); |
| 1368 return next; |
| 1369 } |
| 1370 } else { |
| 1371 appendToken(TokenType.GT); |
| 1372 return next; |
| 1373 } |
| 1374 } |
| 1375 int tokenizeHex(int next) { |
| 1376 int start = offset - 1; |
| 1377 bool hasDigits = false; |
| 1378 while (true) { |
| 1379 next = advance(); |
| 1380 if ((0x30 <= next && next <= 0x39) || (0x41 <= next && next <= 0x46) || (0
x61 <= next && next <= 0x66)) { |
| 1381 hasDigits = true; |
| 1382 } else { |
| 1383 if (!hasDigits) { |
| 1384 reportError(ScannerErrorCode.MISSING_HEX_DIGIT, []); |
| 1385 } |
| 1386 appendStringToken(TokenType.HEXADECIMAL, getString(start, next < 0 ? 0 :
-1)); |
| 1387 return next; |
| 1388 } |
| 1389 } |
| 1390 } |
| 1391 int tokenizeHexOrNumber(int next) { |
| 1392 int x = peek(); |
| 1393 if (x == 0x78 || x == 0x58) { |
| 1394 advance(); |
| 1395 return tokenizeHex(x); |
| 1396 } |
| 1397 return tokenizeNumber(next); |
| 1398 } |
| 1399 int tokenizeIdentifier(int next, int start, bool allowDollar) { |
| 1400 while ((0x61 <= next && next <= 0x7a) || (0x41 <= next && next <= 0x5a) || (
0x30 <= next && next <= 0x39) || next == 0x5f || (next == 0x24 && allowDollar) |
| Character.isLetterOrDigit(next)) { |
| 1401 next = advance(); |
| 1402 } |
| 1403 appendStringToken(TokenType.IDENTIFIER, getString(start, next < 0 ? 0 : -1))
; |
| 1404 return next; |
| 1405 } |
| 1406 int tokenizeInterpolatedExpression(int next, int start) { |
| 1407 appendBeginToken(TokenType.STRING_INTERPOLATION_EXPRESSION); |
| 1408 next = advance(); |
| 1409 while (next != -1) { |
| 1410 if (next == 0x7d) { |
| 1411 BeginToken begin = findTokenMatchingClosingBraceInInterpolationExpressio
n(); |
| 1412 if (begin == null) { |
| 1413 beginToken(); |
| 1414 appendToken(TokenType.CLOSE_CURLY_BRACKET); |
| 1415 next = advance(); |
| 1416 beginToken(); |
| 1417 return next; |
| 1418 } else if (begin.type == TokenType.OPEN_CURLY_BRACKET) { |
| 1419 beginToken(); |
| 1420 appendEndToken(TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRA
CKET); |
| 1421 next = advance(); |
| 1422 beginToken(); |
| 1423 } else if (begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) { |
| 1424 beginToken(); |
| 1425 appendEndToken(TokenType.CLOSE_CURLY_BRACKET, TokenType.STRING_INTERPO
LATION_EXPRESSION); |
| 1426 next = advance(); |
| 1427 beginToken(); |
| 1428 return next; |
| 1429 } |
| 1430 } else { |
| 1431 next = bigSwitch(next); |
| 1432 } |
| 1433 } |
| 1434 if (next == -1) { |
| 1435 return next; |
| 1436 } |
| 1437 next = advance(); |
| 1438 beginToken(); |
| 1439 return next; |
| 1440 } |
| 1441 int tokenizeInterpolatedIdentifier(int next, int start) { |
| 1442 appendStringToken2(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 0); |
| 1443 beginToken(); |
| 1444 next = tokenizeKeywordOrIdentifier(next, false); |
| 1445 beginToken(); |
| 1446 return next; |
| 1447 } |
| 1448 int tokenizeKeywordOrIdentifier(int next, bool allowDollar) { |
| 1449 KeywordState state = KeywordState.KEYWORD_STATE; |
| 1450 int start = offset; |
| 1451 while (state != null && 0x61 <= next && next <= 0x7a) { |
| 1452 state = state.next(next as int); |
| 1453 next = advance(); |
| 1454 } |
| 1455 if (state == null || state.keyword() == null) { |
| 1456 return tokenizeIdentifier(next, start, allowDollar); |
| 1457 } |
| 1458 if ((0x41 <= next && next <= 0x5a) || (0x30 <= next && next <= 0x39) || next
== 0x5f || next == 0x24) { |
| 1459 return tokenizeIdentifier(next, start, allowDollar); |
| 1460 } else if (next < 128) { |
| 1461 appendKeywordToken(state.keyword()); |
| 1462 return next; |
| 1463 } else { |
| 1464 return tokenizeIdentifier(next, start, allowDollar); |
| 1465 } |
| 1466 } |
| 1467 int tokenizeLessThan(int next) { |
| 1468 next = advance(); |
| 1469 if (0x3d == next) { |
| 1470 appendToken(TokenType.LT_EQ); |
| 1471 return advance(); |
| 1472 } else if (0x3c == next) { |
| 1473 return select(0x3d, TokenType.LT_LT_EQ, TokenType.LT_LT); |
| 1474 } else { |
| 1475 appendToken(TokenType.LT); |
| 1476 return next; |
| 1477 } |
| 1478 } |
| 1479 int tokenizeMinus(int next) { |
| 1480 next = advance(); |
| 1481 if (next == 0x2d) { |
| 1482 appendToken(TokenType.MINUS_MINUS); |
| 1483 return advance(); |
| 1484 } else if (next == 0x3d) { |
| 1485 appendToken(TokenType.MINUS_EQ); |
| 1486 return advance(); |
| 1487 } else { |
| 1488 appendToken(TokenType.MINUS); |
| 1489 return next; |
| 1490 } |
| 1491 } |
| 1492 int tokenizeMultiLineComment(int next) { |
| 1493 int nesting = 1; |
| 1494 next = advance(); |
| 1495 while (true) { |
| 1496 if (-1 == next) { |
| 1497 reportError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT, []); |
| 1498 appendCommentToken(TokenType.MULTI_LINE_COMMENT, getString(_tokenStart,
0)); |
| 1499 return next; |
| 1500 } else if (0x2a == next) { |
| 1501 next = advance(); |
| 1502 if (0x2f == next) { |
| 1503 --nesting; |
| 1504 if (0 == nesting) { |
| 1505 appendCommentToken(TokenType.MULTI_LINE_COMMENT, getString(_tokenSta
rt, 0)); |
| 1506 return advance(); |
| 1507 } else { |
| 1508 next = advance(); |
| 1509 } |
| 1510 } |
| 1511 } else if (0x2f == next) { |
| 1512 next = advance(); |
| 1513 if (0x2a == next) { |
| 1514 next = advance(); |
| 1515 ++nesting; |
| 1516 } |
| 1517 } else { |
| 1518 next = advance(); |
| 1519 } |
| 1520 } |
| 1521 } |
| 1522 int tokenizeMultiLineRawString(int quoteChar, int start) { |
| 1523 int next = advance(); |
| 1524 outer: while (next != -1) { |
| 1525 while (next != quoteChar) { |
| 1526 next = advance(); |
| 1527 if (next == -1) { |
| 1528 break outer; |
| 1529 } |
| 1530 } |
| 1531 next = advance(); |
| 1532 if (next == quoteChar) { |
| 1533 next = advance(); |
| 1534 if (next == quoteChar) { |
| 1535 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1536 return advance(); |
| 1537 } |
| 1538 } |
| 1539 } |
| 1540 reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, []); |
| 1541 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1542 return advance(); |
| 1543 } |
| 1544 int tokenizeMultiLineString(int quoteChar, int start, bool raw) { |
| 1545 if (raw) { |
| 1546 return tokenizeMultiLineRawString(quoteChar, start); |
| 1547 } |
| 1548 int next = advance(); |
| 1549 while (next != -1) { |
| 1550 if (next == 0x24) { |
| 1551 appendStringToken(TokenType.STRING, getString(start, -1)); |
| 1552 beginToken(); |
| 1553 next = tokenizeStringInterpolation(start); |
| 1554 start = offset; |
| 1555 continue; |
| 1556 } |
| 1557 if (next == quoteChar) { |
| 1558 next = advance(); |
| 1559 if (next == quoteChar) { |
| 1560 next = advance(); |
| 1561 if (next == quoteChar) { |
| 1562 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1563 return advance(); |
| 1564 } |
| 1565 } |
| 1566 continue; |
| 1567 } |
| 1568 if (next == 0x5c) { |
| 1569 next = advance(); |
| 1570 if (next == -1) { |
| 1571 break; |
| 1572 } |
| 1573 } |
| 1574 next = advance(); |
| 1575 } |
| 1576 reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, []); |
| 1577 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1578 return advance(); |
| 1579 } |
| 1580 int tokenizeMultiply(int next) => select(0x3d, TokenType.STAR_EQ, TokenType.ST
AR); |
| 1581 int tokenizeNumber(int next) { |
| 1582 int start = offset; |
| 1583 while (true) { |
| 1584 next = advance(); |
| 1585 if (0x30 <= next && next <= 0x39) { |
| 1586 continue; |
| 1587 } else if (next == 0x2e) { |
| 1588 return tokenizeFractionPart(advance(), start); |
| 1589 } else if (next == 0x64 || next == 0x44) { |
| 1590 appendStringToken(TokenType.DOUBLE, getString(start, 0)); |
| 1591 return advance(); |
| 1592 } else if (next == 0x65 || next == 0x45) { |
| 1593 return tokenizeFractionPart(next, start); |
| 1594 } else { |
| 1595 appendStringToken(TokenType.INT, getString(start, next < 0 ? 0 : -1)); |
| 1596 return next; |
| 1597 } |
| 1598 } |
| 1599 } |
| 1600 int tokenizeOpenSquareBracket(int next) { |
| 1601 next = advance(); |
| 1602 if (next == 0x5d) { |
| 1603 return select(0x3d, TokenType.INDEX_EQ, TokenType.INDEX); |
| 1604 } else { |
| 1605 appendBeginToken(TokenType.OPEN_SQUARE_BRACKET); |
| 1606 return next; |
| 1607 } |
| 1608 } |
| 1609 int tokenizePercent(int next) => select(0x3d, TokenType.PERCENT_EQ, TokenType.
PERCENT); |
| 1610 int tokenizePlus(int next) { |
| 1611 next = advance(); |
| 1612 if (0x2b == next) { |
| 1613 appendToken(TokenType.PLUS_PLUS); |
| 1614 return advance(); |
| 1615 } else if (0x3d == next) { |
| 1616 appendToken(TokenType.PLUS_EQ); |
| 1617 return advance(); |
| 1618 } else { |
| 1619 appendToken(TokenType.PLUS); |
| 1620 return next; |
| 1621 } |
| 1622 } |
| 1623 int tokenizeSingleLineComment(int next) { |
| 1624 while (true) { |
| 1625 next = advance(); |
| 1626 if (0xa == next || 0xd == next || -1 == next) { |
| 1627 appendCommentToken(TokenType.SINGLE_LINE_COMMENT, getString(_tokenStart,
0)); |
| 1628 return next; |
| 1629 } |
| 1630 } |
| 1631 } |
| 1632 int tokenizeSingleLineRawString(int next, int quoteChar, int start) { |
| 1633 next = advance(); |
| 1634 while (next != -1) { |
| 1635 if (next == quoteChar) { |
| 1636 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1637 return advance(); |
| 1638 } else if (next == 0xd || next == 0xa) { |
| 1639 reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, []); |
| 1640 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1641 return advance(); |
| 1642 } |
| 1643 next = advance(); |
| 1644 } |
| 1645 reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, []); |
| 1646 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1647 return advance(); |
| 1648 } |
| 1649 int tokenizeSingleLineString(int next, int quoteChar, int start) { |
| 1650 while (next != quoteChar) { |
| 1651 if (next == 0x5c) { |
| 1652 next = advance(); |
| 1653 } else if (next == 0x24) { |
| 1654 appendStringToken(TokenType.STRING, getString(start, -1)); |
| 1655 beginToken(); |
| 1656 next = tokenizeStringInterpolation(start); |
| 1657 start = offset; |
| 1658 continue; |
| 1659 } |
| 1660 if (next <= 0xd && (next == 0xa || next == 0xd || next == -1)) { |
| 1661 reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, []); |
| 1662 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1663 return advance(); |
| 1664 } |
| 1665 next = advance(); |
| 1666 } |
| 1667 appendStringToken(TokenType.STRING, getString(start, 0)); |
| 1668 return advance(); |
| 1669 } |
| 1670 int tokenizeSlashOrComment(int next) { |
| 1671 next = advance(); |
| 1672 if (0x2a == next) { |
| 1673 return tokenizeMultiLineComment(next); |
| 1674 } else if (0x2f == next) { |
| 1675 return tokenizeSingleLineComment(next); |
| 1676 } else if (0x3d == next) { |
| 1677 appendToken(TokenType.SLASH_EQ); |
| 1678 return advance(); |
| 1679 } else { |
| 1680 appendToken(TokenType.SLASH); |
| 1681 return next; |
| 1682 } |
| 1683 } |
| 1684 int tokenizeString(int next, int start, bool raw) { |
| 1685 int quoteChar = next; |
| 1686 next = advance(); |
| 1687 if (quoteChar == next) { |
| 1688 next = advance(); |
| 1689 if (quoteChar == next) { |
| 1690 return tokenizeMultiLineString(quoteChar, start, raw); |
| 1691 } else { |
| 1692 appendStringToken(TokenType.STRING, getString(start, -1)); |
| 1693 return next; |
| 1694 } |
| 1695 } |
| 1696 if (raw) { |
| 1697 return tokenizeSingleLineRawString(next, quoteChar, start); |
| 1698 } else { |
| 1699 return tokenizeSingleLineString(next, quoteChar, start); |
| 1700 } |
| 1701 } |
| 1702 int tokenizeStringInterpolation(int start) { |
| 1703 beginToken(); |
| 1704 int next = advance(); |
| 1705 if (next == 0x7b) { |
| 1706 return tokenizeInterpolatedExpression(next, start); |
| 1707 } else { |
| 1708 return tokenizeInterpolatedIdentifier(next, start); |
| 1709 } |
| 1710 } |
| 1711 int tokenizeTag(int next) { |
| 1712 if (offset == 0) { |
| 1713 if (peek() == 0x21) { |
| 1714 do { |
| 1715 next = advance(); |
| 1716 } while (next != 0xa && next != 0xd && next > 0); |
| 1717 appendStringToken(TokenType.SCRIPT_TAG, getString(_tokenStart, 0)); |
| 1718 return next; |
| 1719 } |
| 1720 } |
| 1721 appendToken(TokenType.HASH); |
| 1722 return advance(); |
| 1723 } |
| 1724 int tokenizeTilde(int next) { |
| 1725 next = advance(); |
| 1726 if (next == 0x2f) { |
| 1727 return select(0x3d, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH); |
| 1728 } else { |
| 1729 appendToken(TokenType.TILDE); |
| 1730 return next; |
| 1731 } |
| 1732 } |
| 1733 } |
| 1734 /** |
| 1735 * Instances of the class {@code KeywordTokenWithComment} implement a keyword to
ken that is preceded |
| 1736 * by comments. |
| 1737 */ |
| 1738 class KeywordTokenWithComment extends KeywordToken { |
| 1739 /** |
| 1740 * The first comment in the list of comments that precede this token. |
| 1741 */ |
| 1742 Token _precedingComment; |
| 1743 /** |
| 1744 * Initialize a newly created token to to represent the given keyword and to b
e preceded by the |
| 1745 * comments reachable from the given comment. |
| 1746 * @param keyword the keyword being represented by this token |
| 1747 * @param offset the offset from the beginning of the file to the first charac
ter in the token |
| 1748 * @param precedingComment the first comment in the list of comments that prec
ede this token |
| 1749 */ |
| 1750 KeywordTokenWithComment(Keyword keyword, int offset, Token precedingComment) :
super(keyword, offset) { |
| 1751 this._precedingComment = precedingComment; |
| 1752 } |
| 1753 Token get precedingComments => _precedingComment; |
| 1754 } |
| 1755 /** |
| 1756 * Instances of the abstract class {@code KeywordState} represent a state in a s
tate machine used to |
| 1757 * scan keywords. |
| 1758 */ |
| 1759 class KeywordState { |
| 1760 /** |
| 1761 * An empty transition table used by leaf states. |
| 1762 */ |
| 1763 static List<KeywordState> _EMPTY_TABLE = new List<KeywordState>.fixedLength(26
); |
| 1764 /** |
| 1765 * The initial state in the state machine. |
| 1766 */ |
| 1767 static KeywordState KEYWORD_STATE = createKeywordStateTable(); |
| 1768 /** |
| 1769 * Create the next state in the state machine where we have already recognized
the subset of |
| 1770 * strings in the given array of strings starting at the given offset and havi
ng the given length. |
| 1771 * All of these strings have a common prefix and the next character is at the
given start index. |
| 1772 * @param start the index of the character in the strings used to transition t
o a new state |
| 1773 * @param strings an array containing all of the strings that will be recogniz
ed by the state |
| 1774 * machine |
| 1775 * @param offset the offset of the first string in the array that has the pref
ix that is assumed |
| 1776 * to have been recognized by the time we reach the state being built |
| 1777 * @param length the number of strings in the array that pass through the stat
e being built |
| 1778 * @return the state that was created |
| 1779 */ |
| 1780 static KeywordState computeKeywordStateTable(int start, List<String> strings,
int offset, int length) { |
| 1781 List<KeywordState> result = new List<KeywordState>.fixedLength(26); |
| 1782 assert(length != 0); |
| 1783 int chunk = 0x0; |
| 1784 int chunkStart = -1; |
| 1785 bool isLeaf = false; |
| 1786 for (int i = offset; i < offset + length; i++) { |
| 1787 if (strings[i].length == start) { |
| 1788 isLeaf = true; |
| 1789 } |
| 1790 if (strings[i].length > start) { |
| 1791 int c = strings[i].charCodeAt(start); |
| 1792 if (chunk != c) { |
| 1793 if (chunkStart != -1) { |
| 1794 result[chunk - 0x61] = computeKeywordStateTable(start + 1, strings,
chunkStart, i - chunkStart); |
| 1795 } |
| 1796 chunkStart = i; |
| 1797 chunk = c; |
| 1798 } |
| 1799 } |
| 1800 } |
| 1801 if (chunkStart != -1) { |
| 1802 assert(result[chunk - 0x61] == null); |
| 1803 result[chunk - 0x61] = computeKeywordStateTable(start + 1, strings, chunkS
tart, offset + length - chunkStart); |
| 1804 } else { |
| 1805 assert(length == 1); |
| 1806 return new KeywordState(_EMPTY_TABLE, strings[offset]); |
| 1807 } |
| 1808 if (isLeaf) { |
| 1809 return new KeywordState(result, strings[offset]); |
| 1810 } else { |
| 1811 return new KeywordState(result, null); |
| 1812 } |
| 1813 } |
| 1814 /** |
| 1815 * Create the initial state in the state machine. |
| 1816 * @return the state that was created |
| 1817 */ |
| 1818 static KeywordState createKeywordStateTable() { |
| 1819 List<Keyword> values2 = Keyword.values; |
| 1820 List<String> strings = new List<String>.fixedLength(values2.length); |
| 1821 for (int i = 0; i < values2.length; i++) { |
| 1822 strings[i] = values2[i].syntax; |
| 1823 } |
| 1824 strings.sort(); |
| 1825 return computeKeywordStateTable(0, strings, 0, strings.length); |
| 1826 } |
| 1827 /** |
| 1828 * A table mapping characters to the states to which those characters will tra
nsition. (The index |
| 1829 * into the array is the offset from the character {@code 'a'} to the transiti
oning character.) |
| 1830 */ |
| 1831 List<KeywordState> _table; |
| 1832 /** |
| 1833 * The keyword that is recognized by this state, or {@code null} if this state
is not a terminal |
| 1834 * state. |
| 1835 */ |
| 1836 Keyword _keyword2; |
| 1837 /** |
| 1838 * Initialize a newly created state to have the given transitions and to recog
nize the keyword |
| 1839 * with the given syntax. |
| 1840 * @param table a table mapping characters to the states to which those charac
ters will transition |
| 1841 * @param syntax the syntax of the keyword that is recognized by the state |
| 1842 */ |
| 1843 KeywordState(List<KeywordState> table, String syntax) { |
| 1844 this._table = table; |
| 1845 this._keyword2 = (syntax == null) ? null : Keyword.keywords[syntax]; |
| 1846 } |
| 1847 /** |
| 1848 * Return the keyword that was recognized by this state, or {@code null} if th
is state does not |
| 1849 * recognized a keyword. |
| 1850 * @return the keyword that was matched by reaching this state |
| 1851 */ |
| 1852 Keyword keyword() => _keyword2; |
| 1853 /** |
| 1854 * Return the state that follows this state on a transition of the given chara
cter, or{@code null} if there is no valid state reachable from this state with s
uch a transition. |
| 1855 * @param c the character used to transition from this state to another state |
| 1856 * @return the state that follows this state on a transition of the given char
acter |
| 1857 */ |
| 1858 KeywordState next(int c) => _table[c - 0x61]; |
| 1859 } |
| OLD | NEW |