OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of scanner; | |
6 | |
7 class FormalParameterType { | |
8 final String type; | |
9 const FormalParameterType(this.type); | |
10 bool get isRequired => this == REQUIRED; | |
11 bool get isPositional => this == POSITIONAL; | |
12 bool get isNamed => this == NAMED; | |
13 static final REQUIRED = const FormalParameterType('required'); | |
14 static final POSITIONAL = const FormalParameterType('positional'); | |
15 static final NAMED = const FormalParameterType('named'); | |
16 } | |
17 | |
18 /** | |
19 * An event generating parser of Dart programs. This parser expects | |
20 * all tokens in a linked list (aka a token stream). | |
21 * | |
22 * The class [Scanner] is used to generate a token stream. See the | |
23 * file scanner.dart. | |
24 * | |
25 * Subclasses of the class [Listener] are used to listen to events. | |
26 * | |
27 * Most methods of this class belong in one of two major categories: | |
28 * parse metods and peek methods. Parse methods all have the prefix | |
29 * parse, and peek methods all have the prefix peek. | |
30 * | |
31 * Parse methods generate events (by calling methods on [listener]) | |
32 * and return the next token to parse. Peek methods do not generate | |
33 * events (except for errors) and may return null. | |
34 * | |
35 * Parse methods are generally named parseGrammarProductionSuffix. The | |
36 * suffix can be one of "opt", or "star". "opt" means zero or one | |
37 * matches, "star" means zero or more matches. For example, | |
38 * [parseMetadataStar] corresponds to this grammar snippet: [: | |
39 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. | |
40 */ | |
41 class Parser { | |
42 final Listener listener; | |
43 bool mayParseFunctionExpressions = true; | |
44 | |
45 Parser(this.listener); | |
46 | |
47 Token parseUnit(Token token) { | |
48 listener.beginCompilationUnit(token); | |
49 int count = 0; | |
50 while (!identical(token.kind, EOF_TOKEN)) { | |
51 token = parseTopLevelDeclaration(token); | |
52 listener.endTopLevelDeclaration(token); | |
53 count++; | |
54 } | |
55 listener.endCompilationUnit(count, token); | |
56 return token; | |
57 } | |
58 | |
59 Token parseTopLevelDeclaration(Token token) { | |
60 token = parseMetadataStar(token); | |
61 final String value = token.stringValue; | |
62 if ((identical(value, 'abstract') && optional('class', token.next)) | |
63 || identical(value, 'class')) { | |
64 return parseClassOrNamedMixinApplication(token); | |
65 } else if (identical(value, 'typedef')) { | |
66 return parseTypedef(token); | |
67 } else if (identical(value, 'library')) { | |
68 return parseLibraryName(token); | |
69 } else if (identical(value, 'import')) { | |
70 return parseImport(token); | |
71 } else if (identical(value, 'export')) { | |
72 return parseExport(token); | |
73 } else if (identical(value, 'part')) { | |
74 return parsePartOrPartOf(token); | |
75 } else { | |
76 return parseTopLevelMember(token); | |
77 } | |
78 } | |
79 | |
80 /// library qualified ';' | |
81 Token parseLibraryName(Token token) { | |
82 Token libraryKeyword = token; | |
83 listener.beginLibraryName(libraryKeyword); | |
84 assert(optional('library', token)); | |
85 token = parseQualified(token.next); | |
86 Token semicolon = token; | |
87 token = expect(';', token); | |
88 listener.endLibraryName(libraryKeyword, semicolon); | |
89 return token; | |
90 } | |
91 | |
92 /// import uri (as identifier)? combinator* ';' | |
93 Token parseImport(Token token) { | |
94 Token importKeyword = token; | |
95 listener.beginImport(importKeyword); | |
96 assert(optional('import', token)); | |
97 token = parseLiteralStringOrRecoverExpression(token.next); | |
98 Token deferredKeyword; | |
99 if (optional('deferred', token)) { | |
100 deferredKeyword = token; | |
101 token = token.next; | |
102 } | |
103 Token asKeyword; | |
104 if (optional('as', token)) { | |
105 asKeyword = token; | |
106 token = parseIdentifier(token.next); | |
107 } | |
108 token = parseCombinators(token); | |
109 Token semicolon = token; | |
110 token = expect(';', token); | |
111 listener.endImport(importKeyword, deferredKeyword, asKeyword, semicolon); | |
112 return token; | |
113 } | |
114 | |
115 /// export uri combinator* ';' | |
116 Token parseExport(Token token) { | |
117 Token exportKeyword = token; | |
118 listener.beginExport(exportKeyword); | |
119 assert(optional('export', token)); | |
120 token = parseLiteralStringOrRecoverExpression(token.next); | |
121 token = parseCombinators(token); | |
122 Token semicolon = token; | |
123 token = expect(';', token); | |
124 listener.endExport(exportKeyword, semicolon); | |
125 return token; | |
126 } | |
127 | |
128 Token parseCombinators(Token token) { | |
129 listener.beginCombinators(token); | |
130 int count = 0; | |
131 while (true) { | |
132 String value = token.stringValue; | |
133 if (identical('hide', value)) { | |
134 token = parseHide(token); | |
135 } else if (identical('show', value)) { | |
136 token = parseShow(token); | |
137 } else { | |
138 listener.endCombinators(count); | |
139 break; | |
140 } | |
141 count++; | |
142 } | |
143 return token; | |
144 } | |
145 | |
146 /// hide identifierList | |
147 Token parseHide(Token token) { | |
148 Token hideKeyword = token; | |
149 listener.beginHide(hideKeyword); | |
150 assert(optional('hide', token)); | |
151 token = parseIdentifierList(token.next); | |
152 listener.endHide(hideKeyword); | |
153 return token; | |
154 } | |
155 | |
156 /// show identifierList | |
157 Token parseShow(Token token) { | |
158 Token showKeyword = token; | |
159 listener.beginShow(showKeyword); | |
160 assert(optional('show', token)); | |
161 token = parseIdentifierList(token.next); | |
162 listener.endShow(showKeyword); | |
163 return token; | |
164 } | |
165 | |
166 /// identifier (, identifier)* | |
167 Token parseIdentifierList(Token token) { | |
168 listener.beginIdentifierList(token); | |
169 token = parseIdentifier(token); | |
170 int count = 1; | |
171 while (optional(',', token)) { | |
172 token = parseIdentifier(token.next); | |
173 count++; | |
174 } | |
175 listener.endIdentifierList(count); | |
176 return token; | |
177 } | |
178 | |
179 /// type (, type)* | |
180 Token parseTypeList(Token token) { | |
181 listener.beginTypeList(token); | |
182 token = parseType(token); | |
183 int count = 1; | |
184 while (optional(',', token)) { | |
185 token = parseType(token.next); | |
186 count++; | |
187 } | |
188 listener.endTypeList(count); | |
189 return token; | |
190 } | |
191 | |
192 Token parsePartOrPartOf(Token token) { | |
193 assert(optional('part', token)); | |
194 if (optional('of', token.next)) { | |
195 return parsePartOf(token); | |
196 } else { | |
197 return parsePart(token); | |
198 } | |
199 } | |
200 | |
201 Token parsePart(Token token) { | |
202 Token partKeyword = token; | |
203 listener.beginPart(token); | |
204 assert(optional('part', token)); | |
205 token = parseLiteralStringOrRecoverExpression(token.next); | |
206 Token semicolon = token; | |
207 token = expect(';', token); | |
208 listener.endPart(partKeyword, semicolon); | |
209 return token; | |
210 } | |
211 | |
212 Token parsePartOf(Token token) { | |
213 listener.beginPartOf(token); | |
214 assert(optional('part', token)); | |
215 assert(optional('of', token.next)); | |
216 Token partKeyword = token; | |
217 token = parseQualified(token.next.next); | |
218 Token semicolon = token; | |
219 token = expect(';', token); | |
220 listener.endPartOf(partKeyword, semicolon); | |
221 return token; | |
222 } | |
223 | |
224 Token parseMetadataStar(Token token, {bool forParameter: false}) { | |
225 listener.beginMetadataStar(token); | |
226 int count = 0; | |
227 while (optional('@', token)) { | |
228 token = parseMetadata(token); | |
229 count++; | |
230 } | |
231 listener.endMetadataStar(count, forParameter); | |
232 return token; | |
233 } | |
234 | |
235 /** | |
236 * Parse | |
237 * [: '@' qualified (‘.’ identifier)? (arguments)? :] | |
238 */ | |
239 Token parseMetadata(Token token) { | |
240 listener.beginMetadata(token); | |
241 Token atToken = token; | |
242 assert(optional('@', token)); | |
243 token = parseIdentifier(token.next); | |
244 token = parseQualifiedRestOpt(token); | |
245 token = parseTypeArgumentsOpt(token); | |
246 Token period = null; | |
247 if (optional('.', token)) { | |
248 period = token; | |
249 token = parseIdentifier(token.next); | |
250 } | |
251 token = parseArgumentsOpt(token); | |
252 listener.endMetadata(atToken, period, token); | |
253 return token; | |
254 } | |
255 | |
256 Token parseTypedef(Token token) { | |
257 Token typedefKeyword = token; | |
258 if (optional('=', peekAfterType(token.next))) { | |
259 // TODO(aprelev@gmail.com): Remove deprecated 'typedef' mixin application, | |
260 // remove corresponding diagnostic from members.dart. | |
261 listener.beginNamedMixinApplication(token); | |
262 token = parseIdentifier(token.next); | |
263 token = parseTypeVariablesOpt(token); | |
264 token = expect('=', token); | |
265 token = parseModifiers(token); | |
266 token = parseMixinApplication(token); | |
267 Token implementsKeyword = null; | |
268 if (optional('implements', token)) { | |
269 implementsKeyword = token; | |
270 token = parseTypeList(token.next); | |
271 } | |
272 listener.endNamedMixinApplication( | |
273 typedefKeyword, implementsKeyword, token); | |
274 } else { | |
275 listener.beginFunctionTypeAlias(token); | |
276 token = parseReturnTypeOpt(token.next); | |
277 token = parseIdentifier(token); | |
278 token = parseTypeVariablesOpt(token); | |
279 token = parseFormalParameters(token); | |
280 listener.endFunctionTypeAlias(typedefKeyword, token); | |
281 } | |
282 return expect(';', token); | |
283 } | |
284 | |
285 Token parseMixinApplication(Token token) { | |
286 listener.beginMixinApplication(token); | |
287 token = parseType(token); | |
288 token = expect('with', token); | |
289 token = parseTypeList(token); | |
290 listener.endMixinApplication(); | |
291 return token; | |
292 } | |
293 | |
294 Token parseReturnTypeOpt(Token token) { | |
295 if (identical(token.stringValue, 'void')) { | |
296 listener.handleVoidKeyword(token); | |
297 return token.next; | |
298 } else { | |
299 return parseTypeOpt(token); | |
300 } | |
301 } | |
302 | |
303 Token parseFormalParametersOpt(Token token) { | |
304 if (optional('(', token)) { | |
305 return parseFormalParameters(token); | |
306 } else { | |
307 listener.handleNoFormalParameters(token); | |
308 return token; | |
309 } | |
310 } | |
311 | |
312 Token parseFormalParameters(Token token) { | |
313 Token begin = token; | |
314 listener.beginFormalParameters(begin); | |
315 expect('(', token); | |
316 int parameterCount = 0; | |
317 if (optional(')', token.next)) { | |
318 listener.endFormalParameters(parameterCount, begin, token.next); | |
319 return token.next.next; | |
320 } | |
321 do { | |
322 ++parameterCount; | |
323 token = token.next; | |
324 String value = token.stringValue; | |
325 if (identical(value, '[')) { | |
326 token = parseOptionalFormalParameters(token, false); | |
327 break; | |
328 } else if (identical(value, '{')) { | |
329 token = parseOptionalFormalParameters(token, true); | |
330 break; | |
331 } | |
332 token = parseFormalParameter(token, FormalParameterType.REQUIRED); | |
333 } while (optional(',', token)); | |
334 listener.endFormalParameters(parameterCount, begin, token); | |
335 return expect(')', token); | |
336 } | |
337 | |
338 Token parseFormalParameter(Token token, FormalParameterType type) { | |
339 token = parseMetadataStar(token, forParameter: true); | |
340 listener.beginFormalParameter(token); | |
341 token = parseModifiers(token); | |
342 // TODO(ahe): Validate that there are formal parameters if void. | |
343 token = parseReturnTypeOpt(token); | |
344 Token thisKeyword = null; | |
345 if (optional('this', token)) { | |
346 thisKeyword = token; | |
347 // TODO(ahe): Validate field initializers are only used in | |
348 // constructors, and not for function-typed arguments. | |
349 token = expect('.', token.next); | |
350 } | |
351 token = parseIdentifier(token); | |
352 if (optional('(', token)) { | |
353 token = parseFormalParameters(token); | |
354 listener.handleFunctionTypedFormalParameter(token); | |
355 } | |
356 String value = token.stringValue; | |
357 if ((identical('=', value)) || (identical(':', value))) { | |
358 // TODO(ahe): Validate that these are only used for optional parameters. | |
359 Token equal = token; | |
360 token = parseExpression(token.next); | |
361 listener.handleValuedFormalParameter(equal, token); | |
362 if (type.isRequired) { | |
363 listener.reportError(equal, | |
364 MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); | |
365 } else if (type.isNamed && identical('=', value)) { | |
366 listener.reportError(equal, MessageKind.NAMED_PARAMETER_WITH_EQUALS); | |
367 } else if (type.isPositional && identical(':', value)) { | |
368 listener.reportError(equal, | |
369 MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); | |
370 } | |
371 } | |
372 listener.endFormalParameter(thisKeyword); | |
373 return token; | |
374 } | |
375 | |
376 Token parseOptionalFormalParameters(Token token, bool isNamed) { | |
377 Token begin = token; | |
378 listener.beginOptionalFormalParameters(begin); | |
379 assert((isNamed && optional('{', token)) || optional('[', token)); | |
380 int parameterCount = 0; | |
381 do { | |
382 token = token.next; | |
383 var type = isNamed ? FormalParameterType.NAMED | |
384 : FormalParameterType.POSITIONAL; | |
385 token = parseFormalParameter(token, type); | |
386 ++parameterCount; | |
387 } while (optional(',', token)); | |
388 listener.endOptionalFormalParameters(parameterCount, begin, token); | |
389 if (isNamed) { | |
390 return expect('}', token); | |
391 } else { | |
392 return expect(']', token); | |
393 } | |
394 } | |
395 | |
396 Token parseTypeOpt(Token token) { | |
397 String value = token.stringValue; | |
398 Token peek = peekAfterIfType(token); | |
399 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | |
400 return parseType(token); | |
401 } | |
402 listener.handleNoType(token); | |
403 return token; | |
404 } | |
405 | |
406 bool isValidTypeReference(Token token) { | |
407 final kind = token.kind; | |
408 if (identical(kind, IDENTIFIER_TOKEN)) return true; | |
409 if (identical(kind, KEYWORD_TOKEN)) { | |
410 Keyword keyword = (token as KeywordToken).keyword; | |
411 String value = keyword.syntax; | |
412 return keyword.isPseudo | |
413 || (identical(value, 'dynamic')) | |
414 || (identical(value, 'void')); | |
415 } | |
416 return false; | |
417 } | |
418 | |
419 Token parseQualified(Token token) { | |
420 token = parseIdentifier(token); | |
421 while (optional('.', token)) { | |
422 token = parseQualifiedRest(token); | |
423 } | |
424 return token; | |
425 } | |
426 | |
427 Token parseQualifiedRestOpt(Token token) { | |
428 if (optional('.', token)) { | |
429 return parseQualifiedRest(token); | |
430 } else { | |
431 return token; | |
432 } | |
433 } | |
434 | |
435 Token parseQualifiedRest(Token token) { | |
436 assert(optional('.', token)); | |
437 Token period = token; | |
438 token = parseIdentifier(token.next); | |
439 listener.handleQualified(period); | |
440 return token; | |
441 } | |
442 | |
443 Token skipBlock(Token token) { | |
444 if (!optional('{', token)) { | |
445 return listener.expectedBlockToSkip(token); | |
446 } | |
447 BeginGroupToken beginGroupToken = token; | |
448 Token endGroup = beginGroupToken.endGroup; | |
449 if (endGroup == null) { | |
450 return listener.unmatched(beginGroupToken); | |
451 } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) { | |
452 return listener.unmatched(beginGroupToken); | |
453 } | |
454 return beginGroupToken.endGroup; | |
455 } | |
456 | |
457 Token parseClassOrNamedMixinApplication(Token token) { | |
458 Token begin = token; | |
459 Token abstractKeyword; | |
460 if (optional('abstract', token)) { | |
461 abstractKeyword = token; | |
462 token = token.next; | |
463 } | |
464 Token classKeyword = token; | |
465 var isMixinApplication = optional('=', peekAfterType(token.next)); | |
466 if (isMixinApplication) { | |
467 listener.beginNamedMixinApplication(begin); | |
468 token = parseIdentifier(token.next); | |
469 token = parseTypeVariablesOpt(token); | |
470 token = expect('=', token); | |
471 } else { | |
472 listener.beginClassDeclaration(begin); | |
473 } | |
474 | |
475 // TODO(aprelev@gmail.com): Once 'typedef' named mixin application is | |
476 // removed, move modifiers for named mixin application to the bottom of | |
477 // listener stack. This is so stacks for class declaration and named | |
478 // mixin application look similar. | |
479 int modifierCount = 0; | |
480 if (abstractKeyword != null) { | |
481 parseModifier(abstractKeyword); | |
482 modifierCount++; | |
483 } | |
484 listener.handleModifiers(modifierCount); | |
485 | |
486 if (isMixinApplication) { | |
487 return parseNamedMixinApplication(token, classKeyword); | |
488 } else { | |
489 return parseClass(begin, classKeyword); | |
490 } | |
491 } | |
492 | |
493 Token parseNamedMixinApplication(Token token, Token classKeyword) { | |
494 token = parseMixinApplication(token); | |
495 Token implementsKeyword = null; | |
496 if (optional('implements', token)) { | |
497 implementsKeyword = token; | |
498 token = parseTypeList(token.next); | |
499 } | |
500 listener.endNamedMixinApplication( | |
501 classKeyword, implementsKeyword, token); | |
502 return expect(';', token); | |
503 } | |
504 | |
505 Token parseClass(Token begin, Token classKeyword) { | |
506 Token token = parseIdentifier(classKeyword.next); | |
507 token = parseTypeVariablesOpt(token); | |
508 Token extendsKeyword; | |
509 if (optional('extends', token)) { | |
510 extendsKeyword = token; | |
511 if (optional('with', peekAfterType(token.next))) { | |
512 token = parseMixinApplication(token.next); | |
513 } else { | |
514 token = parseType(token.next); | |
515 } | |
516 } else { | |
517 extendsKeyword = null; | |
518 listener.handleNoType(token); | |
519 } | |
520 Token implementsKeyword; | |
521 int interfacesCount = 0; | |
522 if (optional('implements', token)) { | |
523 implementsKeyword = token; | |
524 do { | |
525 token = parseType(token.next); | |
526 ++interfacesCount; | |
527 } while (optional(',', token)); | |
528 } | |
529 token = parseClassBody(token); | |
530 listener.endClassDeclaration(interfacesCount, begin, extendsKeyword, | |
531 implementsKeyword, token); | |
532 return token.next; | |
533 } | |
534 | |
535 Token parseStringPart(Token token) { | |
536 if (identical(token.kind, STRING_TOKEN)) { | |
537 listener.handleStringPart(token); | |
538 return token.next; | |
539 } else { | |
540 return listener.expected('string', token); | |
541 } | |
542 } | |
543 | |
544 Token parseIdentifier(Token token) { | |
545 if (!token.isIdentifier()) { | |
546 token = listener.expectedIdentifier(token); | |
547 } | |
548 listener.handleIdentifier(token); | |
549 return token.next; | |
550 } | |
551 | |
552 Token expect(String string, Token token) { | |
553 if (!identical(string, token.stringValue)) { | |
554 return listener.expected(string, token); | |
555 } | |
556 return token.next; | |
557 } | |
558 | |
559 Token parseTypeVariable(Token token) { | |
560 listener.beginTypeVariable(token); | |
561 token = parseIdentifier(token); | |
562 if (optional('extends', token)) { | |
563 token = parseType(token.next); | |
564 } else { | |
565 listener.handleNoType(token); | |
566 } | |
567 listener.endTypeVariable(token); | |
568 return token; | |
569 } | |
570 | |
571 /** | |
572 * Returns true if the stringValue of the [token] is [value]. | |
573 */ | |
574 bool optional(String value, Token token) { | |
575 return identical(value, token.stringValue); | |
576 } | |
577 | |
578 /** | |
579 * Returns true if the stringValue of the [token] is either [value1], | |
580 * [value2], [value3], or [value4]. | |
581 */ | |
582 bool isOneOf4(Token token, | |
583 String value1, String value2, String value3, String value4) { | |
584 String stringValue = token.stringValue; | |
585 return identical(value1, stringValue) || | |
586 identical(value2, stringValue) || | |
587 identical(value3, stringValue) || | |
588 identical(value4, stringValue); | |
589 } | |
590 | |
591 bool notEofOrValue(String value, Token token) { | |
592 return !identical(token.kind, EOF_TOKEN) && | |
593 !identical(value, token.stringValue); | |
594 } | |
595 | |
596 Token parseType(Token token) { | |
597 Token begin = token; | |
598 if (isValidTypeReference(token)) { | |
599 token = parseIdentifier(token); | |
600 token = parseQualifiedRestOpt(token); | |
601 } else { | |
602 token = listener.expectedType(token); | |
603 } | |
604 token = parseTypeArgumentsOpt(token); | |
605 listener.endType(begin, token); | |
606 return token; | |
607 } | |
608 | |
609 Token parseTypeArgumentsOpt(Token token) { | |
610 return parseStuff(token, | |
611 (t) => listener.beginTypeArguments(t), | |
612 (t) => parseType(t), | |
613 (c, bt, et) => listener.endTypeArguments(c, bt, et), | |
614 (t) => listener.handleNoTypeArguments(t)); | |
615 } | |
616 | |
617 Token parseTypeVariablesOpt(Token token) { | |
618 return parseStuff(token, | |
619 (t) => listener.beginTypeVariables(t), | |
620 (t) => parseTypeVariable(t), | |
621 (c, bt, et) => listener.endTypeVariables(c, bt, et), | |
622 (t) => listener.handleNoTypeVariables(t)); | |
623 } | |
624 | |
625 // TODO(ahe): Clean this up. | |
626 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | |
627 Function endStuff, Function handleNoStuff) { | |
628 if (optional('<', token)) { | |
629 Token begin = token; | |
630 beginStuff(begin); | |
631 int count = 0; | |
632 do { | |
633 token = stuffParser(token.next); | |
634 ++count; | |
635 } while (optional(',', token)); | |
636 Token next = token.next; | |
637 if (identical(token.stringValue, '>>')) { | |
638 token = new SymbolToken(GT_INFO, token.charOffset); | |
639 token.next = new SymbolToken(GT_INFO, token.charOffset + 1); | |
640 token.next.next = next; | |
641 } else if (identical(token.stringValue, '>>>')) { | |
642 token = new SymbolToken(GT_INFO, token.charOffset); | |
643 token.next = new SymbolToken(GT_GT_INFO, token.charOffset + 1); | |
644 token.next.next = next; | |
645 } | |
646 endStuff(count, begin, token); | |
647 return expect('>', token); | |
648 } | |
649 handleNoStuff(token); | |
650 return token; | |
651 } | |
652 | |
653 Token parseTopLevelMember(Token token) { | |
654 Token start = token; | |
655 listener.beginTopLevelMember(token); | |
656 | |
657 Link<Token> identifiers = findMemberName(token); | |
658 if (identifiers.isEmpty) { | |
659 return listener.expectedDeclaration(start); | |
660 } | |
661 Token name = identifiers.head; | |
662 identifiers = identifiers.tail; | |
663 Token getOrSet; | |
664 if (!identifiers.isEmpty) { | |
665 String value = identifiers.head.stringValue; | |
666 if ((identical(value, 'get')) || (identical(value, 'set'))) { | |
667 getOrSet = identifiers.head; | |
668 identifiers = identifiers.tail; | |
669 } | |
670 } | |
671 Token type; | |
672 if (!identifiers.isEmpty) { | |
673 if (isValidTypeReference(identifiers.head)) { | |
674 type = identifiers.head; | |
675 identifiers = identifiers.tail; | |
676 } | |
677 } | |
678 | |
679 token = name.next; | |
680 bool isField; | |
681 while (true) { | |
682 // Loop to allow the listener to rewrite the token stream for | |
683 // error handling. | |
684 final String value = token.stringValue; | |
685 if ((identical(value, '(')) || (identical(value, '{')) | |
686 || (identical(value, '=>'))) { | |
687 isField = false; | |
688 break; | |
689 } else if ((identical(value, '=')) || (identical(value, ','))) { | |
690 isField = true; | |
691 break; | |
692 } else if (identical(value, ';')) { | |
693 if (getOrSet != null) { | |
694 // If we found a "get" keyword, this must be an abstract | |
695 // getter. | |
696 isField = (!identical(getOrSet.stringValue, 'get')); | |
697 // TODO(ahe): This feels like a hack. | |
698 } else { | |
699 isField = true; | |
700 } | |
701 break; | |
702 } else { | |
703 token = listener.unexpected(token); | |
704 if (identical(token.kind, EOF_TOKEN)) return token; | |
705 } | |
706 } | |
707 var modifiers = identifiers.reverse(); | |
708 return isField | |
709 ? parseFields(start, modifiers, type, getOrSet, name, true) | |
710 : parseTopLevelMethod(start, modifiers, type, getOrSet, name); | |
711 } | |
712 | |
713 bool isVarFinalOrConst(Token token) { | |
714 String value = token.stringValue; | |
715 return identical('var', value) | |
716 || identical('final', value) | |
717 || identical('const', value); | |
718 } | |
719 | |
720 Token expectVarFinalOrConst(Link<Token> modifiers, | |
721 bool hasType, | |
722 bool allowStatic) { | |
723 int modifierCount = 0; | |
724 Token staticModifier; | |
725 if (allowStatic && !modifiers.isEmpty | |
726 && optional('static', modifiers.head)) { | |
727 staticModifier = modifiers.head; | |
728 modifierCount++; | |
729 parseModifier(staticModifier); | |
730 modifiers = modifiers.tail; | |
731 } | |
732 if (modifiers.isEmpty) { | |
733 listener.handleModifiers(modifierCount); | |
734 return null; | |
735 } | |
736 if (modifiers.tail.isEmpty) { | |
737 Token modifier = modifiers.head; | |
738 if (isVarFinalOrConst(modifier)) { | |
739 modifierCount++; | |
740 parseModifier(modifier); | |
741 listener.handleModifiers(modifierCount); | |
742 // TODO(ahe): The caller checks for "var Type name", perhaps we should | |
743 // check here instead. | |
744 return modifier; | |
745 } | |
746 } | |
747 | |
748 // Slow case to report errors. | |
749 List<Token> modifierList = modifiers.toList(); | |
750 Token varFinalOrConst = | |
751 modifierList.firstWhere(isVarFinalOrConst, orElse: () => null); | |
752 if (allowStatic && staticModifier == null) { | |
753 staticModifier = | |
754 modifierList.firstWhere( | |
755 (modifier) => optional('static', modifier), orElse: () => null); | |
756 if (staticModifier != null) { | |
757 modifierCount++; | |
758 parseModifier(staticModifier); | |
759 modifierList.remove(staticModifier); | |
760 } | |
761 } | |
762 bool hasTypeOrModifier = hasType; | |
763 if (varFinalOrConst != null) { | |
764 parseModifier(varFinalOrConst); | |
765 modifierCount++; | |
766 hasTypeOrModifier = true; | |
767 modifierList.remove(varFinalOrConst); | |
768 } | |
769 listener.handleModifiers(modifierCount); | |
770 var kind = hasTypeOrModifier | |
771 ? MessageKind.EXTRANEOUS_MODIFIER | |
772 : MessageKind.EXTRANEOUS_MODIFIER_REPLACE; | |
773 for (Token modifier in modifierList) { | |
774 listener.reportError(modifier, kind, {'modifier': modifier}); | |
775 } | |
776 return null; | |
777 } | |
778 | |
779 Token parseFields(Token start, | |
780 Link<Token> modifiers, | |
781 Token type, | |
782 Token getOrSet, | |
783 Token name, | |
784 bool isTopLevel) { | |
785 bool hasType = type != null; | |
786 Token varFinalOrConst = | |
787 expectVarFinalOrConst(modifiers, hasType, !isTopLevel); | |
788 bool isVar = false; | |
789 bool hasModifier = false; | |
790 if (varFinalOrConst != null) { | |
791 hasModifier = true; | |
792 isVar = optional('var', varFinalOrConst); | |
793 } | |
794 | |
795 if (getOrSet != null) { | |
796 var kind = (hasModifier || hasType) | |
797 ? MessageKind.EXTRANEOUS_MODIFIER | |
798 : MessageKind.EXTRANEOUS_MODIFIER_REPLACE; | |
799 listener.reportError(getOrSet, kind, {'modifier': getOrSet}); | |
800 } | |
801 | |
802 if (!hasType) { | |
803 listener.handleNoType(name); | |
804 } else if (optional('void', type)) { | |
805 listener.handleNoType(name); | |
806 // TODO(ahe): This error is reported twice, second time is from | |
807 // [parseVariablesDeclarationMaybeSemicolon] via | |
808 // [PartialFieldListElement.parseNode]. | |
809 listener.reportError(type, MessageKind.VOID_NOT_ALLOWED); | |
810 } else { | |
811 parseType(type); | |
812 if (isVar) { | |
813 listener.reportError( | |
814 modifiers.head, MessageKind.EXTRANEOUS_MODIFIER, | |
815 {'modifier': modifiers.head}); | |
816 } | |
817 } | |
818 | |
819 Token token = parseIdentifier(name); | |
820 | |
821 int fieldCount = 1; | |
822 token = parseVariableInitializerOpt(token); | |
823 while (optional(',', token)) { | |
824 token = parseIdentifier(token.next); | |
825 token = parseVariableInitializerOpt(token); | |
826 ++fieldCount; | |
827 } | |
828 Token semicolon = token; | |
829 token = expectSemicolon(token); | |
830 if (isTopLevel) { | |
831 listener.endTopLevelFields(fieldCount, start, semicolon); | |
832 } else { | |
833 listener.endFields(fieldCount, start, semicolon); | |
834 } | |
835 return token; | |
836 } | |
837 | |
838 Token parseTopLevelMethod(Token start, | |
839 Link<Token> modifiers, | |
840 Token type, | |
841 Token getOrSet, | |
842 Token name) { | |
843 Token externalModifier; | |
844 for (Token modifier in modifiers) { | |
845 if (externalModifier == null && optional('external', modifier)) { | |
846 externalModifier = modifier; | |
847 } else { | |
848 listener.reportError( | |
849 modifier, MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier}); | |
850 } | |
851 } | |
852 if (externalModifier != null) { | |
853 parseModifier(externalModifier); | |
854 listener.handleModifiers(1); | |
855 } else { | |
856 listener.handleModifiers(0); | |
857 } | |
858 | |
859 if (type == null) { | |
860 listener.handleNoType(name); | |
861 } else { | |
862 parseReturnTypeOpt(type); | |
863 } | |
864 Token token = parseIdentifier(name); | |
865 | |
866 token = parseFormalParametersOpt(token); | |
867 token = parseFunctionBody(token, false, externalModifier != null); | |
868 listener.endTopLevelMethod(start, getOrSet, token); | |
869 return token.next; | |
870 } | |
871 | |
872 Link<Token> findMemberName(Token token) { | |
873 Token start = token; | |
874 Link<Token> identifiers = const Link<Token>(); | |
875 while (!identical(token.kind, EOF_TOKEN)) { | |
876 String value = token.stringValue; | |
877 if ((identical(value, '(')) || (identical(value, '{')) | |
878 || (identical(value, '=>'))) { | |
879 // A method. | |
880 return identifiers; | |
881 } else if ((identical(value, '=')) || (identical(value, ';')) | |
882 || (identical(value, ','))) { | |
883 // A field or abstract getter. | |
884 return identifiers; | |
885 } | |
886 identifiers = identifiers.prepend(token); | |
887 if (isValidTypeReference(token)) { | |
888 // type ... | |
889 if (optional('.', token.next)) { | |
890 // type '.' ... | |
891 if (token.next.next.isIdentifier()) { | |
892 // type '.' identifier | |
893 token = token.next.next; | |
894 } | |
895 } | |
896 if (optional('<', token.next)) { | |
897 if (token.next is BeginGroupToken) { | |
898 BeginGroupToken beginGroup = token.next; | |
899 if (beginGroup.endGroup == null) { | |
900 listener.unmatched(beginGroup); | |
901 } | |
902 token = beginGroup.endGroup; | |
903 } | |
904 } | |
905 } | |
906 token = token.next; | |
907 } | |
908 return const Link<Token>(); | |
909 } | |
910 | |
911 Token parseVariableInitializerOpt(Token token) { | |
912 if (optional('=', token)) { | |
913 Token assignment = token; | |
914 listener.beginInitializer(token); | |
915 token = parseExpression(token.next); | |
916 listener.endInitializer(assignment); | |
917 } | |
918 return token; | |
919 } | |
920 | |
921 Token parseInitializersOpt(Token token) { | |
922 if (optional(':', token)) { | |
923 return parseInitializers(token); | |
924 } else { | |
925 listener.handleNoInitializers(); | |
926 return token; | |
927 } | |
928 } | |
929 | |
930 Token parseInitializers(Token token) { | |
931 Token begin = token; | |
932 listener.beginInitializers(begin); | |
933 expect(':', token); | |
934 int count = 0; | |
935 bool old = mayParseFunctionExpressions; | |
936 mayParseFunctionExpressions = false; | |
937 do { | |
938 token = parseExpression(token.next); | |
939 ++count; | |
940 } while (optional(',', token)); | |
941 mayParseFunctionExpressions = old; | |
942 listener.endInitializers(count, begin, token); | |
943 return token; | |
944 } | |
945 | |
946 Token parseLiteralStringOrRecoverExpression(Token token) { | |
947 if (identical(token.kind, STRING_TOKEN)) { | |
948 return parseLiteralString(token); | |
949 } else { | |
950 listener.recoverableError(token, "unexpected"); | |
951 return parseExpression(token); | |
952 } | |
953 } | |
954 | |
955 Token expectSemicolon(Token token) { | |
956 return expect(';', token); | |
957 } | |
958 | |
959 bool isModifier(Token token) { | |
960 final String value = token.stringValue; | |
961 return (identical('final', value)) || | |
962 (identical('var', value)) || | |
963 (identical('const', value)) || | |
964 (identical('abstract', value)) || | |
965 (identical('static', value)) || | |
966 (identical('external', value)); | |
967 } | |
968 | |
969 Token parseModifier(Token token) { | |
970 assert(isModifier(token)); | |
971 listener.handleModifier(token); | |
972 return token.next; | |
973 } | |
974 | |
975 void parseModifierList(Link<Token> tokens) { | |
976 int count = 0; | |
977 for (; !tokens.isEmpty; tokens = tokens.tail) { | |
978 Token token = tokens.head; | |
979 if (isModifier(token)) { | |
980 parseModifier(token); | |
981 } else { | |
982 listener.unexpected(token); | |
983 } | |
984 count++; | |
985 } | |
986 listener.handleModifiers(count); | |
987 } | |
988 | |
989 Token parseModifiers(Token token) { | |
990 int count = 0; | |
991 while (identical(token.kind, KEYWORD_TOKEN)) { | |
992 if (!isModifier(token)) | |
993 break; | |
994 token = parseModifier(token); | |
995 count++; | |
996 } | |
997 listener.handleModifiers(count); | |
998 return token; | |
999 } | |
1000 | |
1001 /** | |
1002 * Returns the first token after the type starting at [token]. | |
1003 * This method assumes that [token] is an identifier (or void). | |
1004 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | |
1005 */ | |
1006 Token peekAfterType(Token token) { | |
1007 // We are looking at "identifier ...". | |
1008 Token peek = token.next; | |
1009 if (identical(peek.kind, PERIOD_TOKEN)) { | |
1010 if (peek.next.isIdentifier()) { | |
1011 // Look past a library prefix. | |
1012 peek = peek.next.next; | |
1013 } | |
1014 } | |
1015 // We are looking at "qualified ...". | |
1016 if (identical(peek.kind, LT_TOKEN)) { | |
1017 // Possibly generic type. | |
1018 // We are looking at "qualified '<'". | |
1019 BeginGroupToken beginGroupToken = peek; | |
1020 Token gtToken = beginGroupToken.endGroup; | |
1021 if (gtToken != null) { | |
1022 // We are looking at "qualified '<' ... '>' ...". | |
1023 return gtToken.next; | |
1024 } | |
1025 } | |
1026 return peek; | |
1027 } | |
1028 | |
1029 /** | |
1030 * If [token] is the start of a type, returns the token after that type. | |
1031 * If [token] is not the start of a type, null is returned. | |
1032 */ | |
1033 Token peekAfterIfType(Token token) { | |
1034 if (!optional('void', token) && !token.isIdentifier()) { | |
1035 return null; | |
1036 } | |
1037 return peekAfterType(token); | |
1038 } | |
1039 | |
1040 Token parseClassBody(Token token) { | |
1041 Token begin = token; | |
1042 listener.beginClassBody(token); | |
1043 if (!optional('{', token)) { | |
1044 token = listener.expectedClassBody(token); | |
1045 } | |
1046 token = token.next; | |
1047 int count = 0; | |
1048 while (notEofOrValue('}', token)) { | |
1049 token = parseMember(token); | |
1050 ++count; | |
1051 } | |
1052 expect('}', token); | |
1053 listener.endClassBody(count, begin, token); | |
1054 return token; | |
1055 } | |
1056 | |
1057 bool isGetOrSet(Token token) { | |
1058 final String value = token.stringValue; | |
1059 return (identical(value, 'get')) || (identical(value, 'set')); | |
1060 } | |
1061 | |
1062 bool isFactoryDeclaration(Token token) { | |
1063 if (optional('external', token)) token = token.next; | |
1064 if (optional('const', token)) token = token.next; | |
1065 return optional('factory', token); | |
1066 } | |
1067 | |
1068 Token parseMember(Token token) { | |
1069 token = parseMetadataStar(token); | |
1070 String value = token.stringValue; | |
1071 if (isFactoryDeclaration(token)) { | |
1072 return parseFactoryMethod(token); | |
1073 } | |
1074 Token start = token; | |
1075 listener.beginMember(token); | |
1076 | |
1077 Link<Token> identifiers = findMemberName(token); | |
1078 if (identifiers.isEmpty) { | |
1079 return listener.expectedDeclaration(start); | |
1080 } | |
1081 Token name = identifiers.head; | |
1082 Token afterName = name.next; | |
1083 identifiers = identifiers.tail; | |
1084 if (!identifiers.isEmpty) { | |
1085 if (optional('operator', identifiers.head)) { | |
1086 name = identifiers.head; | |
1087 identifiers = identifiers.tail; | |
1088 } | |
1089 } | |
1090 Token getOrSet; | |
1091 if (!identifiers.isEmpty) { | |
1092 if (isGetOrSet(identifiers.head)) { | |
1093 getOrSet = identifiers.head; | |
1094 identifiers = identifiers.tail; | |
1095 } | |
1096 } | |
1097 Token type; | |
1098 if (!identifiers.isEmpty) { | |
1099 if (isValidTypeReference(identifiers.head)) { | |
1100 type = identifiers.head; | |
1101 identifiers = identifiers.tail; | |
1102 } | |
1103 } | |
1104 | |
1105 token = afterName; | |
1106 bool isField; | |
1107 while (true) { | |
1108 // Loop to allow the listener to rewrite the token stream for | |
1109 // error handling. | |
1110 final String value = token.stringValue; | |
1111 if ((identical(value, '(')) || (identical(value, '.')) | |
1112 || (identical(value, '{')) || (identical(value, '=>'))) { | |
1113 isField = false; | |
1114 break; | |
1115 } else if (identical(value, ';')) { | |
1116 if (getOrSet != null) { | |
1117 // If we found a "get" keyword, this must be an abstract | |
1118 // getter. | |
1119 isField = (!identical(getOrSet.stringValue, 'get')); | |
1120 // TODO(ahe): This feels like a hack. | |
1121 } else { | |
1122 isField = true; | |
1123 } | |
1124 break; | |
1125 } else if ((identical(value, '=')) || (identical(value, ','))) { | |
1126 isField = true; | |
1127 break; | |
1128 } else { | |
1129 token = listener.unexpected(token); | |
1130 if (identical(token.kind, EOF_TOKEN)) { | |
1131 // TODO(ahe): This is a hack, see parseTopLevelMember. | |
1132 listener.endFields(1, start, token); | |
1133 return token; | |
1134 } | |
1135 } | |
1136 } | |
1137 | |
1138 var modifiers = identifiers.reverse(); | |
1139 return isField | |
1140 ? parseFields(start, modifiers, type, getOrSet, name, false) | |
1141 : parseMethod(start, modifiers, type, getOrSet, name); | |
1142 | |
1143 } | |
1144 | |
1145 Token parseMethod(Token start, | |
1146 Link<Token> modifiers, | |
1147 Token type, | |
1148 Token getOrSet, | |
1149 Token name) { | |
1150 Token externalModifier; | |
1151 Token staticModifier; | |
1152 Token constModifier; | |
1153 int modifierCount = 0; | |
1154 int allowedModifierCount = 1; | |
1155 for (Token modifier in modifiers) { | |
1156 if (externalModifier == null && optional('external', modifier)) { | |
1157 modifierCount++; | |
1158 externalModifier = modifier; | |
1159 if (modifierCount != allowedModifierCount) { | |
1160 listener.reportError( | |
1161 modifier, | |
1162 MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier}); | |
1163 } | |
1164 allowedModifierCount++; | |
1165 } else if (staticModifier == null && optional('static', modifier)) { | |
1166 modifierCount++; | |
1167 staticModifier = modifier; | |
1168 if (modifierCount != allowedModifierCount) { | |
1169 listener.reportError( | |
1170 modifier, | |
1171 MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier}); | |
1172 } | |
1173 } else if (constModifier == null && optional('const', modifier)) { | |
1174 modifierCount++; | |
1175 constModifier = modifier; | |
1176 if (modifierCount != allowedModifierCount) { | |
1177 listener.reportError( | |
1178 modifier, | |
1179 MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier}); | |
1180 } | |
1181 } else { | |
1182 listener.reportError( | |
1183 modifier, MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier}); | |
1184 } | |
1185 } | |
1186 parseModifierList(modifiers); | |
1187 | |
1188 if (type == null) { | |
1189 listener.handleNoType(name); | |
1190 } else { | |
1191 parseReturnTypeOpt(type); | |
1192 } | |
1193 Token token; | |
1194 if (optional('operator', name)) { | |
1195 token = parseOperatorName(name); | |
1196 if (staticModifier != null) { | |
1197 // TODO(ahe): Consider a more specific error message. | |
1198 listener.reportError( | |
1199 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, | |
1200 {'modifier': staticModifier}); | |
1201 } | |
1202 } else { | |
1203 token = parseIdentifier(name); | |
1204 } | |
1205 | |
1206 token = parseQualifiedRestOpt(token); | |
1207 token = parseFormalParametersOpt(token); | |
1208 token = parseInitializersOpt(token); | |
1209 if (optional('=', token)) { | |
1210 token = parseRedirectingFactoryBody(token); | |
1211 } else { | |
1212 token = parseFunctionBody( | |
1213 token, false, staticModifier == null || externalModifier != null); | |
1214 } | |
1215 listener.endMethod(getOrSet, start, token); | |
1216 return token.next; | |
1217 } | |
1218 | |
1219 Token parseFactoryMethod(Token token) { | |
1220 assert(isFactoryDeclaration(token)); | |
1221 Token start = token; | |
1222 Token externalModifier; | |
1223 if (identical(token.stringValue, 'external')) { | |
1224 externalModifier = token; | |
1225 token = token.next; | |
1226 } | |
1227 Token constKeyword = null; | |
1228 if (optional('const', token)) { | |
1229 constKeyword = token; | |
1230 token = token.next; | |
1231 } | |
1232 Token factoryKeyword = token; | |
1233 listener.beginFactoryMethod(factoryKeyword); | |
1234 token = token.next; // Skip 'factory'. | |
1235 token = parseConstructorReference(token); | |
1236 token = parseFormalParameters(token); | |
1237 if (optional('=', token)) { | |
1238 token = parseRedirectingFactoryBody(token); | |
1239 } else { | |
1240 token = parseFunctionBody(token, false, externalModifier != null); | |
1241 } | |
1242 listener.endFactoryMethod(start, token); | |
1243 return token.next; | |
1244 } | |
1245 | |
1246 Token parseOperatorName(Token token) { | |
1247 assert(optional('operator', token)); | |
1248 if (isUserDefinableOperator(token.next.stringValue)) { | |
1249 Token operator = token; | |
1250 token = token.next; | |
1251 listener.handleOperatorName(operator, token); | |
1252 return token.next; | |
1253 } else { | |
1254 return parseIdentifier(token); | |
1255 } | |
1256 } | |
1257 | |
1258 Token parseFunction(Token token, Token getOrSet) { | |
1259 listener.beginFunction(token); | |
1260 token = parseModifiers(token); | |
1261 if (identical(getOrSet, token)) token = token.next; | |
1262 if (optional('operator', token)) { | |
1263 listener.handleNoType(token); | |
1264 listener.beginFunctionName(token); | |
1265 token = parseOperatorName(token); | |
1266 } else { | |
1267 token = parseReturnTypeOpt(token); | |
1268 if (identical(getOrSet, token)) token = token.next; | |
1269 listener.beginFunctionName(token); | |
1270 if (optional('operator', token)) { | |
1271 token = parseOperatorName(token); | |
1272 } else { | |
1273 token = parseIdentifier(token); | |
1274 } | |
1275 } | |
1276 token = parseQualifiedRestOpt(token); | |
1277 listener.endFunctionName(token); | |
1278 token = parseFormalParametersOpt(token); | |
1279 token = parseInitializersOpt(token); | |
1280 if (optional('=', token)) { | |
1281 token = parseRedirectingFactoryBody(token); | |
1282 } else { | |
1283 token = parseFunctionBody(token, false, true); | |
1284 } | |
1285 listener.endFunction(getOrSet, token); | |
1286 return token.next; | |
1287 } | |
1288 | |
1289 Token parseUnamedFunction(Token token) { | |
1290 listener.beginUnamedFunction(token); | |
1291 token = parseFormalParameters(token); | |
1292 bool isBlock = optional('{', token); | |
1293 token = parseFunctionBody(token, true, false); | |
1294 listener.endUnamedFunction(token); | |
1295 return isBlock ? token.next : token; | |
1296 } | |
1297 | |
1298 Token parseFunctionDeclaration(Token token) { | |
1299 listener.beginFunctionDeclaration(token); | |
1300 token = parseFunction(token, null); | |
1301 listener.endFunctionDeclaration(token); | |
1302 return token; | |
1303 } | |
1304 | |
1305 Token parseFunctionExpression(Token token) { | |
1306 listener.beginFunction(token); | |
1307 listener.handleModifiers(0); | |
1308 token = parseReturnTypeOpt(token); | |
1309 listener.beginFunctionName(token); | |
1310 token = parseIdentifier(token); | |
1311 listener.endFunctionName(token); | |
1312 token = parseFormalParameters(token); | |
1313 listener.handleNoInitializers(); | |
1314 bool isBlock = optional('{', token); | |
1315 token = parseFunctionBody(token, true, false); | |
1316 listener.endFunction(null, token); | |
1317 return isBlock ? token.next : token; | |
1318 } | |
1319 | |
1320 Token parseConstructorReference(Token token) { | |
1321 Token start = token; | |
1322 listener.beginConstructorReference(start); | |
1323 token = parseIdentifier(token); | |
1324 token = parseQualifiedRestOpt(token); | |
1325 token = parseTypeArgumentsOpt(token); | |
1326 Token period = null; | |
1327 if (optional('.', token)) { | |
1328 period = token; | |
1329 token = parseIdentifier(token.next); | |
1330 } | |
1331 listener.endConstructorReference(start, period, token); | |
1332 return token; | |
1333 } | |
1334 | |
1335 Token parseRedirectingFactoryBody(Token token) { | |
1336 listener.beginRedirectingFactoryBody(token); | |
1337 assert(optional('=', token)); | |
1338 Token equals = token; | |
1339 token = parseConstructorReference(token.next); | |
1340 Token semicolon = token; | |
1341 expectSemicolon(token); | |
1342 listener.endRedirectingFactoryBody(equals, semicolon); | |
1343 return token; | |
1344 } | |
1345 | |
1346 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { | |
1347 if (optional(';', token)) { | |
1348 if (!allowAbstract) { | |
1349 listener.reportError(token, MessageKind.BODY_EXPECTED); | |
1350 } | |
1351 listener.endFunctionBody(0, null, token); | |
1352 return token; | |
1353 } else if (optional('=>', token)) { | |
1354 Token begin = token; | |
1355 token = parseExpression(token.next); | |
1356 if (!isExpression) { | |
1357 expectSemicolon(token); | |
1358 listener.endReturnStatement(true, begin, token); | |
1359 } else { | |
1360 listener.endReturnStatement(true, begin, null); | |
1361 } | |
1362 return token; | |
1363 } | |
1364 Token begin = token; | |
1365 int statementCount = 0; | |
1366 if (!optional('{', token)) { | |
1367 return listener.expectedFunctionBody(token); | |
1368 } | |
1369 | |
1370 listener.beginFunctionBody(begin); | |
1371 token = token.next; | |
1372 while (notEofOrValue('}', token)) { | |
1373 token = parseStatement(token); | |
1374 ++statementCount; | |
1375 } | |
1376 listener.endFunctionBody(statementCount, begin, token); | |
1377 expect('}', token); | |
1378 return token; | |
1379 } | |
1380 | |
1381 Token parseStatement(Token token) { | |
1382 final value = token.stringValue; | |
1383 if (identical(token.kind, IDENTIFIER_TOKEN)) { | |
1384 return parseExpressionStatementOrDeclaration(token); | |
1385 } else if (identical(value, '{')) { | |
1386 return parseBlock(token); | |
1387 } else if (identical(value, 'return')) { | |
1388 return parseReturnStatement(token); | |
1389 } else if (identical(value, 'var') || identical(value, 'final')) { | |
1390 return parseVariablesDeclaration(token); | |
1391 } else if (identical(value, 'if')) { | |
1392 return parseIfStatement(token); | |
1393 } else if (identical(value, 'for')) { | |
1394 return parseForStatement(token); | |
1395 } else if (identical(value, 'rethrow')) { | |
1396 return parseRethrowStatement(token); | |
1397 } else if (identical(value, 'throw') && optional(';', token.next)) { | |
1398 // TODO(kasperl): Stop dealing with throw here. | |
1399 return parseRethrowStatement(token); | |
1400 } else if (identical(value, 'void')) { | |
1401 return parseExpressionStatementOrDeclaration(token); | |
1402 } else if (identical(value, 'while')) { | |
1403 return parseWhileStatement(token); | |
1404 } else if (identical(value, 'do')) { | |
1405 return parseDoWhileStatement(token); | |
1406 } else if (identical(value, 'try')) { | |
1407 return parseTryStatement(token); | |
1408 } else if (identical(value, 'switch')) { | |
1409 return parseSwitchStatement(token); | |
1410 } else if (identical(value, 'break')) { | |
1411 return parseBreakStatement(token); | |
1412 } else if (identical(value, 'continue')) { | |
1413 return parseContinueStatement(token); | |
1414 } else if (identical(value, 'assert')) { | |
1415 return parseAssertStatement(token); | |
1416 } else if (identical(value, ';')) { | |
1417 return parseEmptyStatement(token); | |
1418 } else if (identical(value, 'const')) { | |
1419 return parseExpressionStatementOrConstDeclaration(token); | |
1420 } else if (token.isIdentifier()) { | |
1421 return parseExpressionStatementOrDeclaration(token); | |
1422 } else { | |
1423 return parseExpressionStatement(token); | |
1424 } | |
1425 } | |
1426 | |
1427 Token parseReturnStatement(Token token) { | |
1428 Token begin = token; | |
1429 listener.beginReturnStatement(begin); | |
1430 assert(identical('return', token.stringValue)); | |
1431 token = token.next; | |
1432 if (optional(';', token)) { | |
1433 listener.endReturnStatement(false, begin, token); | |
1434 } else { | |
1435 token = parseExpression(token); | |
1436 listener.endReturnStatement(true, begin, token); | |
1437 } | |
1438 return expectSemicolon(token); | |
1439 } | |
1440 | |
1441 Token peekIdentifierAfterType(Token token) { | |
1442 Token peek = peekAfterType(token); | |
1443 if (peek != null && peek.isIdentifier()) { | |
1444 // We are looking at "type identifier". | |
1445 return peek; | |
1446 } else { | |
1447 return null; | |
1448 } | |
1449 } | |
1450 | |
1451 Token peekIdentifierAfterOptionalType(Token token) { | |
1452 Token peek = peekIdentifierAfterType(token); | |
1453 if (peek != null) { | |
1454 // We are looking at "type identifier". | |
1455 return peek; | |
1456 } else if (token.isIdentifier()) { | |
1457 // We are looking at "identifier". | |
1458 return token; | |
1459 } else { | |
1460 return null; | |
1461 } | |
1462 } | |
1463 | |
1464 Token parseExpressionStatementOrDeclaration(Token token) { | |
1465 assert(token.isIdentifier() || identical(token.stringValue, 'void')); | |
1466 Token identifier = peekIdentifierAfterType(token); | |
1467 if (identifier != null) { | |
1468 assert(identifier.isIdentifier()); | |
1469 Token afterId = identifier.next; | |
1470 int afterIdKind = afterId.kind; | |
1471 if (identical(afterIdKind, EQ_TOKEN) || | |
1472 identical(afterIdKind, SEMICOLON_TOKEN) || | |
1473 identical(afterIdKind, COMMA_TOKEN)) { | |
1474 // We are looking at "type identifier" followed by '=', ';', ','. | |
1475 return parseVariablesDeclaration(token); | |
1476 } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) { | |
1477 // We are looking at "type identifier '('". | |
1478 BeginGroupToken beginParen = afterId; | |
1479 Token endParen = beginParen.endGroup; | |
1480 Token afterParens = endParen.next; | |
1481 if (optional('{', afterParens) || optional('=>', afterParens)) { | |
1482 // We are looking at "type identifier '(' ... ')'" followed | |
1483 // by '=>' or '{'. | |
1484 return parseFunctionDeclaration(token); | |
1485 } | |
1486 } | |
1487 // Fall-through to expression statement. | |
1488 } else { | |
1489 if (optional(':', token.next)) { | |
1490 return parseLabeledStatement(token); | |
1491 } else if (optional('(', token.next)) { | |
1492 BeginGroupToken begin = token.next; | |
1493 String afterParens = begin.endGroup.next.stringValue; | |
1494 if (identical(afterParens, '{') || identical(afterParens, '=>')) { | |
1495 return parseFunctionDeclaration(token); | |
1496 } | |
1497 } | |
1498 } | |
1499 return parseExpressionStatement(token); | |
1500 } | |
1501 | |
1502 Token parseExpressionStatementOrConstDeclaration(Token token) { | |
1503 assert(identical(token.stringValue, 'const')); | |
1504 if (isModifier(token.next)) { | |
1505 return parseVariablesDeclaration(token); | |
1506 } | |
1507 Token identifier = peekIdentifierAfterOptionalType(token.next); | |
1508 if (identifier != null) { | |
1509 assert(identifier.isIdentifier()); | |
1510 Token afterId = identifier.next; | |
1511 int afterIdKind = afterId.kind; | |
1512 if (identical(afterIdKind, EQ_TOKEN) || | |
1513 identical(afterIdKind, SEMICOLON_TOKEN) || | |
1514 identical(afterIdKind, COMMA_TOKEN)) { | |
1515 // We are looking at "const type identifier" followed by '=', ';', or | |
1516 // ','. | |
1517 return parseVariablesDeclaration(token); | |
1518 } | |
1519 // Fall-through to expression statement. | |
1520 } | |
1521 | |
1522 return parseExpressionStatement(token); | |
1523 } | |
1524 | |
1525 Token parseLabel(Token token) { | |
1526 token = parseIdentifier(token); | |
1527 Token colon = token; | |
1528 token = expect(':', token); | |
1529 listener.handleLabel(colon); | |
1530 return token; | |
1531 } | |
1532 | |
1533 Token parseLabeledStatement(Token token) { | |
1534 int labelCount = 0; | |
1535 do { | |
1536 token = parseLabel(token); | |
1537 labelCount++; | |
1538 } while (token.isIdentifier() && optional(':', token.next)); | |
1539 listener.beginLabeledStatement(token, labelCount); | |
1540 token = parseStatement(token); | |
1541 listener.endLabeledStatement(labelCount); | |
1542 return token; | |
1543 } | |
1544 | |
1545 Token parseExpressionStatement(Token token) { | |
1546 listener.beginExpressionStatement(token); | |
1547 token = parseExpression(token); | |
1548 listener.endExpressionStatement(token); | |
1549 return expectSemicolon(token); | |
1550 } | |
1551 | |
1552 Token parseExpression(Token token) { | |
1553 return optional('throw', token) | |
1554 ? parseThrowExpression(token, true) | |
1555 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true); | |
1556 } | |
1557 | |
1558 Token parseExpressionWithoutCascade(Token token) { | |
1559 return optional('throw', token) | |
1560 ? parseThrowExpression(token, false) | |
1561 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false); | |
1562 } | |
1563 | |
1564 Token parseConditionalExpressionRest(Token token) { | |
1565 assert(optional('?', token)); | |
1566 Token question = token; | |
1567 token = parseExpressionWithoutCascade(token.next); | |
1568 Token colon = token; | |
1569 token = expect(':', token); | |
1570 token = parseExpressionWithoutCascade(token); | |
1571 listener.handleConditionalExpression(question, colon); | |
1572 return token; | |
1573 } | |
1574 | |
1575 Token parsePrecedenceExpression(Token token, int precedence, | |
1576 bool allowCascades) { | |
1577 assert(precedence >= 1); | |
1578 assert(precedence <= POSTFIX_PRECEDENCE); | |
1579 token = parseUnaryExpression(token, allowCascades); | |
1580 PrecedenceInfo info = token.info; | |
1581 int tokenLevel = info.precedence; | |
1582 for (int level = tokenLevel; level >= precedence; --level) { | |
1583 while (identical(tokenLevel, level)) { | |
1584 Token operator = token; | |
1585 if (identical(tokenLevel, CASCADE_PRECEDENCE)) { | |
1586 if (!allowCascades) { | |
1587 return token; | |
1588 } | |
1589 token = parseCascadeExpression(token); | |
1590 } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) { | |
1591 // Right associative, so we recurse at the same precedence | |
1592 // level. | |
1593 token = parsePrecedenceExpression(token.next, level, allowCascades); | |
1594 listener.handleAssignmentExpression(operator); | |
1595 } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) { | |
1596 if (identical(info, PERIOD_INFO)) { | |
1597 // Left associative, so we recurse at the next higher | |
1598 // precedence level. However, POSTFIX_PRECEDENCE is the | |
1599 // highest level, so we just call parseUnaryExpression | |
1600 // directly. | |
1601 token = parseUnaryExpression(token.next, allowCascades); | |
1602 listener.handleBinaryExpression(operator); | |
1603 } else if ((identical(info, OPEN_PAREN_INFO)) || | |
1604 (identical(info, OPEN_SQUARE_BRACKET_INFO))) { | |
1605 token = parseArgumentOrIndexStar(token); | |
1606 } else if ((identical(info, PLUS_PLUS_INFO)) || | |
1607 (identical(info, MINUS_MINUS_INFO))) { | |
1608 listener.handleUnaryPostfixAssignmentExpression(token); | |
1609 token = token.next; | |
1610 } else { | |
1611 token = listener.unexpected(token); | |
1612 } | |
1613 } else if (identical(info, IS_INFO)) { | |
1614 token = parseIsOperatorRest(token); | |
1615 } else if (identical(info, AS_INFO)) { | |
1616 token = parseAsOperatorRest(token); | |
1617 } else if (identical(info, QUESTION_INFO)) { | |
1618 token = parseConditionalExpressionRest(token); | |
1619 } else { | |
1620 // Left associative, so we recurse at the next higher | |
1621 // precedence level. | |
1622 token = parsePrecedenceExpression(token.next, level + 1, | |
1623 allowCascades); | |
1624 listener.handleBinaryExpression(operator); | |
1625 } | |
1626 info = token.info; | |
1627 tokenLevel = info.precedence; | |
1628 if (level == EQUALITY_PRECEDENCE || level == RELATIONAL_PRECEDENCE) { | |
1629 // We don't allow (a == b == c) or (a < b < c). | |
1630 // Continue the outer loop if we have matched one equality or | |
1631 // relational operator. | |
1632 break; | |
1633 } | |
1634 } | |
1635 } | |
1636 return token; | |
1637 } | |
1638 | |
1639 Token parseCascadeExpression(Token token) { | |
1640 listener.beginCascade(token); | |
1641 assert(optional('..', token)); | |
1642 Token cascadeOperator = token; | |
1643 token = token.next; | |
1644 if (optional('[', token)) { | |
1645 token = parseArgumentOrIndexStar(token); | |
1646 } else if (token.isIdentifier()) { | |
1647 token = parseSend(token); | |
1648 listener.handleBinaryExpression(cascadeOperator); | |
1649 } else { | |
1650 return listener.unexpected(token); | |
1651 } | |
1652 Token mark; | |
1653 do { | |
1654 mark = token; | |
1655 if (optional('.', token)) { | |
1656 Token period = token; | |
1657 token = parseSend(token.next); | |
1658 listener.handleBinaryExpression(period); | |
1659 } | |
1660 token = parseArgumentOrIndexStar(token); | |
1661 } while (!identical(mark, token)); | |
1662 | |
1663 if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) { | |
1664 Token assignment = token; | |
1665 token = parseExpressionWithoutCascade(token.next); | |
1666 listener.handleAssignmentExpression(assignment); | |
1667 } | |
1668 listener.endCascade(); | |
1669 return token; | |
1670 } | |
1671 | |
1672 Token parseUnaryExpression(Token token, bool allowCascades) { | |
1673 String value = token.stringValue; | |
1674 // Prefix: | |
1675 if (identical(value, '+')) { | |
1676 // Dart no longer allows prefix-plus. | |
1677 listener.reportError(token, MessageKind.UNSUPPORTED_PREFIX_PLUS); | |
1678 return parseUnaryExpression(token.next, allowCascades); | |
1679 } else if ((identical(value, '!')) || | |
1680 (identical(value, '-')) || | |
1681 (identical(value, '~'))) { | |
1682 Token operator = token; | |
1683 // Right associative, so we recurse at the same precedence | |
1684 // level. | |
1685 token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE, | |
1686 allowCascades); | |
1687 listener.handleUnaryPrefixExpression(operator); | |
1688 } else if ((identical(value, '++')) || identical(value, '--')) { | |
1689 // TODO(ahe): Validate this is used correctly. | |
1690 Token operator = token; | |
1691 // Right associative, so we recurse at the same precedence | |
1692 // level. | |
1693 token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE, | |
1694 allowCascades); | |
1695 listener.handleUnaryPrefixAssignmentExpression(operator); | |
1696 } else { | |
1697 token = parsePrimary(token); | |
1698 } | |
1699 return token; | |
1700 } | |
1701 | |
1702 Token parseArgumentOrIndexStar(Token token) { | |
1703 while (true) { | |
1704 if (optional('[', token)) { | |
1705 Token openSquareBracket = token; | |
1706 bool old = mayParseFunctionExpressions; | |
1707 mayParseFunctionExpressions = true; | |
1708 token = parseExpression(token.next); | |
1709 mayParseFunctionExpressions = old; | |
1710 listener.handleIndexedExpression(openSquareBracket, token); | |
1711 token = expect(']', token); | |
1712 } else if (optional('(', token)) { | |
1713 token = parseArguments(token); | |
1714 listener.endSend(token); | |
1715 } else { | |
1716 break; | |
1717 } | |
1718 } | |
1719 return token; | |
1720 } | |
1721 | |
1722 Token parsePrimary(Token token) { | |
1723 final kind = token.kind; | |
1724 if (identical(kind, IDENTIFIER_TOKEN)) { | |
1725 return parseSendOrFunctionLiteral(token); | |
1726 } else if (identical(kind, INT_TOKEN) | |
1727 || identical(kind, HEXADECIMAL_TOKEN)) { | |
1728 return parseLiteralInt(token); | |
1729 } else if (identical(kind, DOUBLE_TOKEN)) { | |
1730 return parseLiteralDouble(token); | |
1731 } else if (identical(kind, STRING_TOKEN)) { | |
1732 return parseLiteralString(token); | |
1733 } else if (identical(kind, HASH_TOKEN)) { | |
1734 return parseLiteralSymbol(token); | |
1735 } else if (identical(kind, KEYWORD_TOKEN)) { | |
1736 final value = token.stringValue; | |
1737 if ((identical(value, 'true')) || (identical(value, 'false'))) { | |
1738 return parseLiteralBool(token); | |
1739 } else if (identical(value, 'null')) { | |
1740 return parseLiteralNull(token); | |
1741 } else if (identical(value, 'this')) { | |
1742 return parseThisExpression(token); | |
1743 } else if (identical(value, 'super')) { | |
1744 return parseSuperExpression(token); | |
1745 } else if (identical(value, 'new')) { | |
1746 return parseNewExpression(token); | |
1747 } else if (identical(value, 'const')) { | |
1748 return parseConstExpression(token); | |
1749 } else if (identical(value, 'void')) { | |
1750 return parseFunctionExpression(token); | |
1751 } else if (token.isIdentifier()) { | |
1752 return parseSendOrFunctionLiteral(token); | |
1753 } else { | |
1754 return listener.expectedExpression(token); | |
1755 } | |
1756 } else if (identical(kind, OPEN_PAREN_TOKEN)) { | |
1757 return parseParenthesizedExpressionOrFunctionLiteral(token); | |
1758 } else if ((identical(kind, LT_TOKEN)) || | |
1759 (identical(kind, OPEN_SQUARE_BRACKET_TOKEN)) || | |
1760 (identical(kind, OPEN_CURLY_BRACKET_TOKEN)) || | |
1761 identical(token.stringValue, '[]')) { | |
1762 return parseLiteralListOrMap(token); | |
1763 } else { | |
1764 return listener.expectedExpression(token); | |
1765 } | |
1766 } | |
1767 | |
1768 Token parseParenthesizedExpressionOrFunctionLiteral(Token token) { | |
1769 BeginGroupToken beginGroup = token; | |
1770 int kind = beginGroup.endGroup.next.kind; | |
1771 if (mayParseFunctionExpressions && | |
1772 (identical(kind, FUNCTION_TOKEN) | |
1773 || identical(kind, OPEN_CURLY_BRACKET_TOKEN))) { | |
1774 return parseUnamedFunction(token); | |
1775 } else { | |
1776 bool old = mayParseFunctionExpressions; | |
1777 mayParseFunctionExpressions = true; | |
1778 token = parseParenthesizedExpression(token); | |
1779 mayParseFunctionExpressions = old; | |
1780 return token; | |
1781 } | |
1782 } | |
1783 | |
1784 Token parseParenthesizedExpression(Token token) { | |
1785 // We expect [begin] to be of type [BeginGroupToken], but we don't know for | |
1786 // sure until after calling expect. | |
1787 var begin = token; | |
1788 token = expect('(', token); | |
1789 // [begin] is now known to have type [BeginGroupToken]. | |
1790 token = parseExpression(token); | |
1791 if (!identical(begin.endGroup, token)) { | |
1792 listener.unexpected(token); | |
1793 token = begin.endGroup; | |
1794 } | |
1795 listener.handleParenthesizedExpression(begin); | |
1796 return expect(')', token); | |
1797 } | |
1798 | |
1799 Token parseThisExpression(Token token) { | |
1800 listener.handleThisExpression(token); | |
1801 token = token.next; | |
1802 if (optional('(', token)) { | |
1803 // Constructor forwarding. | |
1804 token = parseArguments(token); | |
1805 listener.endSend(token); | |
1806 } | |
1807 return token; | |
1808 } | |
1809 | |
1810 Token parseSuperExpression(Token token) { | |
1811 listener.handleSuperExpression(token); | |
1812 token = token.next; | |
1813 if (optional('(', token)) { | |
1814 // Super constructor. | |
1815 token = parseArguments(token); | |
1816 listener.endSend(token); | |
1817 } | |
1818 return token; | |
1819 } | |
1820 | |
1821 Token parseLiteralListOrMap(Token token) { | |
1822 Token constKeyword = null; | |
1823 if (optional('const', token)) { | |
1824 constKeyword = token; | |
1825 token = token.next; | |
1826 } | |
1827 token = parseTypeArgumentsOpt(token); | |
1828 Token beginToken = token; | |
1829 int count = 0; | |
1830 if (optional('{', token)) { | |
1831 bool old = mayParseFunctionExpressions; | |
1832 mayParseFunctionExpressions = true; | |
1833 do { | |
1834 if (optional('}', token.next)) { | |
1835 token = token.next; | |
1836 break; | |
1837 } | |
1838 token = parseMapLiteralEntry(token.next); | |
1839 ++count; | |
1840 } while (optional(',', token)); | |
1841 mayParseFunctionExpressions = old; | |
1842 listener.handleLiteralMap(count, beginToken, constKeyword, token); | |
1843 return expect('}', token); | |
1844 } else if (optional('[', token)) { | |
1845 bool old = mayParseFunctionExpressions; | |
1846 mayParseFunctionExpressions = true; | |
1847 do { | |
1848 if (optional(']', token.next)) { | |
1849 token = token.next; | |
1850 break; | |
1851 } | |
1852 token = parseExpression(token.next); | |
1853 ++count; | |
1854 } while (optional(',', token)); | |
1855 mayParseFunctionExpressions = old; | |
1856 listener.handleLiteralList(count, beginToken, constKeyword, token); | |
1857 return expect(']', token); | |
1858 } else if (optional('[]', token)) { | |
1859 listener.handleLiteralList(0, token, constKeyword, token); | |
1860 return token.next; | |
1861 } else { | |
1862 listener.unexpected(token); | |
1863 return null; | |
1864 } | |
1865 } | |
1866 | |
1867 Token parseMapLiteralEntry(Token token) { | |
1868 listener.beginLiteralMapEntry(token); | |
1869 // Assume the listener rejects non-string keys. | |
1870 token = parseExpression(token); | |
1871 Token colon = token; | |
1872 token = expect(':', token); | |
1873 token = parseExpression(token); | |
1874 listener.endLiteralMapEntry(colon, token); | |
1875 return token; | |
1876 } | |
1877 | |
1878 Token parseSendOrFunctionLiteral(Token token) { | |
1879 if (!mayParseFunctionExpressions) return parseSend(token); | |
1880 Token peek = peekAfterIfType(token); | |
1881 if (peek != null && | |
1882 identical(peek.kind, IDENTIFIER_TOKEN) && | |
1883 isFunctionDeclaration(peek.next)) { | |
1884 return parseFunctionExpression(token); | |
1885 } else if (isFunctionDeclaration(token.next)) { | |
1886 return parseFunctionExpression(token); | |
1887 } else { | |
1888 return parseSend(token); | |
1889 } | |
1890 } | |
1891 | |
1892 bool isFunctionDeclaration(Token token) { | |
1893 if (optional('(', token)) { | |
1894 BeginGroupToken begin = token; | |
1895 String afterParens = begin.endGroup.next.stringValue; | |
1896 if (identical(afterParens, '{') || identical(afterParens, '=>')) { | |
1897 return true; | |
1898 } | |
1899 } | |
1900 return false; | |
1901 } | |
1902 | |
1903 Token parseRequiredArguments(Token token) { | |
1904 if (optional('(', token)) { | |
1905 token = parseArguments(token); | |
1906 } else { | |
1907 listener.handleNoArguments(token); | |
1908 token = listener.unexpected(token); | |
1909 } | |
1910 return token; | |
1911 } | |
1912 | |
1913 Token parseNewExpression(Token token) { | |
1914 Token newKeyword = token; | |
1915 token = expect('new', token); | |
1916 token = parseConstructorReference(token); | |
1917 token = parseRequiredArguments(token); | |
1918 listener.handleNewExpression(newKeyword); | |
1919 return token; | |
1920 } | |
1921 | |
1922 Token parseConstExpression(Token token) { | |
1923 Token constKeyword = token; | |
1924 token = expect('const', token); | |
1925 final String value = token.stringValue; | |
1926 if ((identical(value, '<')) || | |
1927 (identical(value, '[')) || | |
1928 (identical(value, '[]')) || | |
1929 (identical(value, '{'))) { | |
1930 return parseLiteralListOrMap(constKeyword); | |
1931 } | |
1932 token = parseConstructorReference(token); | |
1933 token = parseRequiredArguments(token); | |
1934 listener.handleConstExpression(constKeyword); | |
1935 return token; | |
1936 } | |
1937 | |
1938 Token parseLiteralInt(Token token) { | |
1939 listener.handleLiteralInt(token); | |
1940 return token.next; | |
1941 } | |
1942 | |
1943 Token parseLiteralDouble(Token token) { | |
1944 listener.handleLiteralDouble(token); | |
1945 return token.next; | |
1946 } | |
1947 | |
1948 Token parseLiteralString(Token token) { | |
1949 bool old = mayParseFunctionExpressions; | |
1950 mayParseFunctionExpressions = true; | |
1951 token = parseSingleLiteralString(token); | |
1952 int count = 1; | |
1953 while (identical(token.kind, STRING_TOKEN)) { | |
1954 token = parseSingleLiteralString(token); | |
1955 count++; | |
1956 } | |
1957 if (count > 1) { | |
1958 listener.handleStringJuxtaposition(count); | |
1959 } | |
1960 mayParseFunctionExpressions = old; | |
1961 return token; | |
1962 } | |
1963 | |
1964 Token parseLiteralSymbol(Token token) { | |
1965 Token hashToken = token; | |
1966 listener.beginLiteralSymbol(hashToken); | |
1967 token = token.next; | |
1968 if (isUserDefinableOperator(token.stringValue)) { | |
1969 listener.handleOperator(token); | |
1970 listener.endLiteralSymbol(hashToken, 1); | |
1971 return token.next; | |
1972 } else { | |
1973 int count = 1; | |
1974 token = parseIdentifier(token); | |
1975 while (identical(token.stringValue, '.')) { | |
1976 count++; | |
1977 token = parseIdentifier(token.next); | |
1978 } | |
1979 listener.endLiteralSymbol(hashToken, count); | |
1980 return token; | |
1981 } | |
1982 } | |
1983 | |
1984 /** | |
1985 * Only called when [:token.kind === STRING_TOKEN:]. | |
1986 */ | |
1987 Token parseSingleLiteralString(Token token) { | |
1988 listener.beginLiteralString(token); | |
1989 // Parsing the prefix, for instance 'x of 'x${id}y${id}z' | |
1990 token = token.next; | |
1991 int interpolationCount = 0; | |
1992 var kind = token.kind; | |
1993 while (kind != EOF_TOKEN) { | |
1994 if (identical(kind, STRING_INTERPOLATION_TOKEN)) { | |
1995 // Parsing ${expression}. | |
1996 token = token.next; | |
1997 token = parseExpression(token); | |
1998 token = expect('}', token); | |
1999 } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) { | |
2000 // Parsing $identifier. | |
2001 token = token.next; | |
2002 token = parseExpression(token); | |
2003 } else { | |
2004 break; | |
2005 } | |
2006 ++interpolationCount; | |
2007 // Parsing the infix/suffix, for instance y and z' of 'x${id}y${id}z' | |
2008 token = parseStringPart(token); | |
2009 kind = token.kind; | |
2010 } | |
2011 listener.endLiteralString(interpolationCount); | |
2012 return token; | |
2013 } | |
2014 | |
2015 Token parseLiteralBool(Token token) { | |
2016 listener.handleLiteralBool(token); | |
2017 return token.next; | |
2018 } | |
2019 | |
2020 Token parseLiteralNull(Token token) { | |
2021 listener.handleLiteralNull(token); | |
2022 return token.next; | |
2023 } | |
2024 | |
2025 Token parseSend(Token token) { | |
2026 listener.beginSend(token); | |
2027 token = parseIdentifier(token); | |
2028 token = parseArgumentsOpt(token); | |
2029 listener.endSend(token); | |
2030 return token; | |
2031 } | |
2032 | |
2033 Token parseArgumentsOpt(Token token) { | |
2034 if (!optional('(', token)) { | |
2035 listener.handleNoArguments(token); | |
2036 return token; | |
2037 } else { | |
2038 return parseArguments(token); | |
2039 } | |
2040 } | |
2041 | |
2042 Token parseArguments(Token token) { | |
2043 Token begin = token; | |
2044 listener.beginArguments(begin); | |
2045 assert(identical('(', token.stringValue)); | |
2046 int argumentCount = 0; | |
2047 if (optional(')', token.next)) { | |
2048 listener.endArguments(argumentCount, begin, token.next); | |
2049 return token.next.next; | |
2050 } | |
2051 bool old = mayParseFunctionExpressions; | |
2052 mayParseFunctionExpressions = true; | |
2053 do { | |
2054 Token colon = null; | |
2055 if (optional(':', token.next.next)) { | |
2056 token = parseIdentifier(token.next); | |
2057 colon = token; | |
2058 } | |
2059 token = parseExpression(token.next); | |
2060 if (colon != null) listener.handleNamedArgument(colon); | |
2061 ++argumentCount; | |
2062 } while (optional(',', token)); | |
2063 mayParseFunctionExpressions = old; | |
2064 listener.endArguments(argumentCount, begin, token); | |
2065 return expect(')', token); | |
2066 } | |
2067 | |
2068 Token parseIsOperatorRest(Token token) { | |
2069 assert(optional('is', token)); | |
2070 Token operator = token; | |
2071 Token not = null; | |
2072 if (optional('!', token.next)) { | |
2073 token = token.next; | |
2074 not = token; | |
2075 } | |
2076 token = parseType(token.next); | |
2077 listener.handleIsOperator(operator, not, token); | |
2078 String value = token.stringValue; | |
2079 if (identical(value, 'is') || identical(value, 'as')) { | |
2080 // The is- and as-operators cannot be chained, but they can take part of | |
2081 // expressions like: foo is Foo || foo is Bar. | |
2082 listener.unexpected(token); | |
2083 } | |
2084 return token; | |
2085 } | |
2086 | |
2087 Token parseAsOperatorRest(Token token) { | |
2088 assert(optional('as', token)); | |
2089 Token operator = token; | |
2090 token = parseType(token.next); | |
2091 listener.handleAsOperator(operator, token); | |
2092 String value = token.stringValue; | |
2093 if (identical(value, 'is') || identical(value, 'as')) { | |
2094 // The is- and as-operators cannot be chained. | |
2095 listener.unexpected(token); | |
2096 } | |
2097 return token; | |
2098 } | |
2099 | |
2100 Token parseVariablesDeclaration(Token token) { | |
2101 return parseVariablesDeclarationMaybeSemicolon(token, true); | |
2102 } | |
2103 | |
2104 Token parseVariablesDeclarationNoSemicolon(Token token) { | |
2105 // Only called when parsing a for loop, so this is for parsing locals. | |
2106 return parseVariablesDeclarationMaybeSemicolon(token, false); | |
2107 } | |
2108 | |
2109 Token parseVariablesDeclarationMaybeSemicolon(Token token, | |
2110 bool endWithSemicolon) { | |
2111 int count = 1; | |
2112 listener.beginVariablesDeclaration(token); | |
2113 token = parseModifiers(token); | |
2114 token = parseTypeOpt(token); | |
2115 token = parseOptionallyInitializedIdentifier(token); | |
2116 while (optional(',', token)) { | |
2117 token = parseOptionallyInitializedIdentifier(token.next); | |
2118 ++count; | |
2119 } | |
2120 if (endWithSemicolon) { | |
2121 Token semicolon = token; | |
2122 token = expectSemicolon(semicolon); | |
2123 listener.endVariablesDeclaration(count, semicolon); | |
2124 return token; | |
2125 } else { | |
2126 listener.endVariablesDeclaration(count, null); | |
2127 return token; | |
2128 } | |
2129 } | |
2130 | |
2131 Token parseOptionallyInitializedIdentifier(Token token) { | |
2132 listener.beginInitializedIdentifier(token); | |
2133 token = parseIdentifier(token); | |
2134 token = parseVariableInitializerOpt(token); | |
2135 listener.endInitializedIdentifier(); | |
2136 return token; | |
2137 } | |
2138 | |
2139 Token parseIfStatement(Token token) { | |
2140 Token ifToken = token; | |
2141 listener.beginIfStatement(ifToken); | |
2142 token = expect('if', token); | |
2143 token = parseParenthesizedExpression(token); | |
2144 token = parseStatement(token); | |
2145 Token elseToken = null; | |
2146 if (optional('else', token)) { | |
2147 elseToken = token; | |
2148 token = parseStatement(token.next); | |
2149 } | |
2150 listener.endIfStatement(ifToken, elseToken); | |
2151 return token; | |
2152 } | |
2153 | |
2154 Token parseForStatement(Token token) { | |
2155 Token forToken = token; | |
2156 listener.beginForStatement(forToken); | |
2157 token = expect('for', token); | |
2158 token = expect('(', token); | |
2159 token = parseVariablesDeclarationOrExpressionOpt(token); | |
2160 if (optional('in', token)) { | |
2161 return parseForInRest(forToken, token); | |
2162 } else { | |
2163 return parseForRest(forToken, token); | |
2164 } | |
2165 } | |
2166 | |
2167 Token parseVariablesDeclarationOrExpressionOpt(Token token) { | |
2168 final String value = token.stringValue; | |
2169 if (identical(value, ';')) { | |
2170 listener.handleNoExpression(token); | |
2171 return token; | |
2172 } else if ((identical(value, 'var')) || (identical(value, 'final'))) { | |
2173 return parseVariablesDeclarationNoSemicolon(token); | |
2174 } | |
2175 Token identifier = peekIdentifierAfterType(token); | |
2176 if (identifier != null) { | |
2177 assert(identifier.isIdentifier()); | |
2178 if (isOneOf4(identifier.next, '=', ';', ',', 'in')) { | |
2179 return parseVariablesDeclarationNoSemicolon(token); | |
2180 } | |
2181 } | |
2182 return parseExpression(token); | |
2183 } | |
2184 | |
2185 Token parseForRest(Token forToken, Token token) { | |
2186 token = expectSemicolon(token); | |
2187 if (optional(';', token)) { | |
2188 token = parseEmptyStatement(token); | |
2189 } else { | |
2190 token = parseExpressionStatement(token); | |
2191 } | |
2192 int expressionCount = 0; | |
2193 while (true) { | |
2194 if (optional(')', token)) break; | |
2195 token = parseExpression(token); | |
2196 ++expressionCount; | |
2197 if (optional(',', token)) { | |
2198 token = token.next; | |
2199 } else { | |
2200 break; | |
2201 } | |
2202 } | |
2203 token = expect(')', token); | |
2204 token = parseStatement(token); | |
2205 listener.endForStatement(expressionCount, forToken, token); | |
2206 return token; | |
2207 } | |
2208 | |
2209 Token parseForInRest(Token forToken, Token token) { | |
2210 assert(optional('in', token)); | |
2211 Token inKeyword = token; | |
2212 token = parseExpression(token.next); | |
2213 token = expect(')', token); | |
2214 token = parseStatement(token); | |
2215 listener.endForIn(forToken, inKeyword, token); | |
2216 return token; | |
2217 } | |
2218 | |
2219 Token parseWhileStatement(Token token) { | |
2220 Token whileToken = token; | |
2221 listener.beginWhileStatement(whileToken); | |
2222 token = expect('while', token); | |
2223 token = parseParenthesizedExpression(token); | |
2224 token = parseStatement(token); | |
2225 listener.endWhileStatement(whileToken, token); | |
2226 return token; | |
2227 } | |
2228 | |
2229 Token parseDoWhileStatement(Token token) { | |
2230 Token doToken = token; | |
2231 listener.beginDoWhileStatement(doToken); | |
2232 token = expect('do', token); | |
2233 token = parseStatement(token); | |
2234 Token whileToken = token; | |
2235 token = expect('while', token); | |
2236 token = parseParenthesizedExpression(token); | |
2237 listener.endDoWhileStatement(doToken, whileToken, token); | |
2238 return expectSemicolon(token); | |
2239 } | |
2240 | |
2241 Token parseBlock(Token token) { | |
2242 Token begin = token; | |
2243 listener.beginBlock(begin); | |
2244 int statementCount = 0; | |
2245 token = expect('{', token); | |
2246 while (notEofOrValue('}', token)) { | |
2247 token = parseStatement(token); | |
2248 ++statementCount; | |
2249 } | |
2250 listener.endBlock(statementCount, begin, token); | |
2251 return expect('}', token); | |
2252 } | |
2253 | |
2254 Token parseThrowExpression(Token token, bool allowCascades) { | |
2255 Token throwToken = token; | |
2256 listener.beginThrowExpression(throwToken); | |
2257 token = expect('throw', token); | |
2258 token = allowCascades | |
2259 ? parseExpression(token) | |
2260 : parseExpressionWithoutCascade(token); | |
2261 listener.endThrowExpression(throwToken, token); | |
2262 return token; | |
2263 } | |
2264 | |
2265 Token parseRethrowStatement(Token token) { | |
2266 Token throwToken = token; | |
2267 listener.beginRethrowStatement(throwToken); | |
2268 // TODO(kasperl): Disallow throw here. | |
2269 if (identical(throwToken.stringValue, 'throw')) { | |
2270 token = expect('throw', token); | |
2271 } else { | |
2272 token = expect('rethrow', token); | |
2273 } | |
2274 listener.endRethrowStatement(throwToken, token); | |
2275 return expectSemicolon(token); | |
2276 } | |
2277 | |
2278 Token parseTryStatement(Token token) { | |
2279 assert(optional('try', token)); | |
2280 Token tryKeyword = token; | |
2281 listener.beginTryStatement(tryKeyword); | |
2282 token = parseBlock(token.next); | |
2283 int catchCount = 0; | |
2284 | |
2285 String value = token.stringValue; | |
2286 while (identical(value, 'catch') || identical(value, 'on')) { | |
2287 var onKeyword = null; | |
2288 if (identical(value, 'on')) { | |
2289 // on qualified catchPart? | |
2290 onKeyword = token; | |
2291 token = parseType(token.next); | |
2292 value = token.stringValue; | |
2293 } | |
2294 Token catchKeyword = null; | |
2295 if (identical(value, 'catch')) { | |
2296 catchKeyword = token; | |
2297 // TODO(ahe): Validate the "parameters". | |
2298 token = parseFormalParameters(token.next); | |
2299 } | |
2300 token = parseBlock(token); | |
2301 ++catchCount; | |
2302 listener.handleCatchBlock(onKeyword, catchKeyword); | |
2303 value = token.stringValue; // while condition | |
2304 } | |
2305 | |
2306 Token finallyKeyword = null; | |
2307 if (optional('finally', token)) { | |
2308 finallyKeyword = token; | |
2309 token = parseBlock(token.next); | |
2310 listener.handleFinallyBlock(finallyKeyword); | |
2311 } | |
2312 listener.endTryStatement(catchCount, tryKeyword, finallyKeyword); | |
2313 return token; | |
2314 } | |
2315 | |
2316 Token parseSwitchStatement(Token token) { | |
2317 assert(optional('switch', token)); | |
2318 Token switchKeyword = token; | |
2319 listener.beginSwitchStatement(switchKeyword); | |
2320 token = parseParenthesizedExpression(token.next); | |
2321 token = parseSwitchBlock(token); | |
2322 listener.endSwitchStatement(switchKeyword, token); | |
2323 return token.next; | |
2324 } | |
2325 | |
2326 Token parseSwitchBlock(Token token) { | |
2327 Token begin = token; | |
2328 listener.beginSwitchBlock(begin); | |
2329 token = expect('{', token); | |
2330 int caseCount = 0; | |
2331 while (!identical(token.kind, EOF_TOKEN)) { | |
2332 if (optional('}', token)) { | |
2333 break; | |
2334 } | |
2335 token = parseSwitchCase(token); | |
2336 ++caseCount; | |
2337 } | |
2338 listener.endSwitchBlock(caseCount, begin, token); | |
2339 expect('}', token); | |
2340 return token; | |
2341 } | |
2342 | |
2343 /** | |
2344 * Peek after the following labels (if any). The following token | |
2345 * is used to determine if the labels belong to a statement or a | |
2346 * switch case. | |
2347 */ | |
2348 Token peekPastLabels(Token token) { | |
2349 while (token.isIdentifier() && optional(':', token.next)) { | |
2350 token = token.next.next; | |
2351 } | |
2352 return token; | |
2353 } | |
2354 | |
2355 /** | |
2356 * Parse a group of labels, cases and possibly a default keyword and | |
2357 * the statements that they select. | |
2358 */ | |
2359 Token parseSwitchCase(Token token) { | |
2360 Token begin = token; | |
2361 Token defaultKeyword = null; | |
2362 int expressionCount = 0; | |
2363 int labelCount = 0; | |
2364 Token peek = peekPastLabels(token); | |
2365 while (true) { | |
2366 // Loop until we find something that can't be part of a switch case. | |
2367 String value = peek.stringValue; | |
2368 if (identical(value, 'default')) { | |
2369 while (!identical(token, peek)) { | |
2370 token = parseLabel(token); | |
2371 labelCount++; | |
2372 } | |
2373 defaultKeyword = token; | |
2374 token = expect(':', token.next); | |
2375 peek = token; | |
2376 break; | |
2377 } else if (identical(value, 'case')) { | |
2378 while (!identical(token, peek)) { | |
2379 token = parseLabel(token); | |
2380 labelCount++; | |
2381 } | |
2382 Token caseKeyword = token; | |
2383 token = parseExpression(token.next); | |
2384 Token colonToken = token; | |
2385 token = expect(':', token); | |
2386 listener.handleCaseMatch(caseKeyword, colonToken); | |
2387 expressionCount++; | |
2388 peek = peekPastLabels(token); | |
2389 } else { | |
2390 if (expressionCount == 0) { | |
2391 listener.expected("case", token); | |
2392 } | |
2393 break; | |
2394 } | |
2395 } | |
2396 // Finally zero or more statements. | |
2397 int statementCount = 0; | |
2398 while (!identical(token.kind, EOF_TOKEN)) { | |
2399 String value = peek.stringValue; | |
2400 if ((identical(value, 'case')) || | |
2401 (identical(value, 'default')) || | |
2402 ((identical(value, '}')) && (identical(token, peek)))) { | |
2403 // A label just before "}" will be handled as a statement error. | |
2404 break; | |
2405 } else { | |
2406 token = parseStatement(token); | |
2407 } | |
2408 statementCount++; | |
2409 peek = peekPastLabels(token); | |
2410 } | |
2411 listener.handleSwitchCase(labelCount, expressionCount, defaultKeyword, | |
2412 statementCount, begin, token); | |
2413 return token; | |
2414 } | |
2415 | |
2416 Token parseBreakStatement(Token token) { | |
2417 assert(optional('break', token)); | |
2418 Token breakKeyword = token; | |
2419 token = token.next; | |
2420 bool hasTarget = false; | |
2421 if (token.isIdentifier()) { | |
2422 token = parseIdentifier(token); | |
2423 hasTarget = true; | |
2424 } | |
2425 listener.handleBreakStatement(hasTarget, breakKeyword, token); | |
2426 return expectSemicolon(token); | |
2427 } | |
2428 | |
2429 Token parseAssertStatement(Token token) { | |
2430 Token assertKeyword = token; | |
2431 token = expect('assert', token); | |
2432 expect('(', token); | |
2433 token = parseArguments(token); | |
2434 listener.handleAssertStatement(assertKeyword, token); | |
2435 return expectSemicolon(token); | |
2436 } | |
2437 | |
2438 Token parseContinueStatement(Token token) { | |
2439 assert(optional('continue', token)); | |
2440 Token continueKeyword = token; | |
2441 token = token.next; | |
2442 bool hasTarget = false; | |
2443 if (token.isIdentifier()) { | |
2444 token = parseIdentifier(token); | |
2445 hasTarget = true; | |
2446 } | |
2447 listener.handleContinueStatement(hasTarget, continueKeyword, token); | |
2448 return expectSemicolon(token); | |
2449 } | |
2450 | |
2451 Token parseEmptyStatement(Token token) { | |
2452 listener.handleEmptyStatement(token); | |
2453 return expectSemicolon(token); | |
2454 } | |
2455 } | |
OLD | NEW |