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