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

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

Issue 692513002: Remove old dart2js code. (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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698