Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/scanner/parser.dart

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

Powered by Google App Engine
This is Rietveld 408576698