OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library fasta.parser.parser; | 5 library fasta.parser.parser; |
6 | 6 |
7 import '../fasta_codes.dart' | 7 import '../fasta_codes.dart' |
8 show | 8 show |
9 FastaCode, | 9 FastaCode, |
10 FastaMessage, | 10 FastaMessage, |
(...skipping 12 matching lines...) Expand all Loading... | |
23 codeExpectedBody, | 23 codeExpectedBody, |
24 codeExpectedButGot, | 24 codeExpectedButGot, |
25 codeExpectedClassBody, | 25 codeExpectedClassBody, |
26 codeExpectedClassBodyToSkip, | 26 codeExpectedClassBodyToSkip, |
27 codeExpectedDeclaration, | 27 codeExpectedDeclaration, |
28 codeExpectedExpression, | 28 codeExpectedExpression, |
29 codeExpectedFunctionBody, | 29 codeExpectedFunctionBody, |
30 codeExpectedIdentifier, | 30 codeExpectedIdentifier, |
31 codeExpectedOpenParens, | 31 codeExpectedOpenParens, |
32 codeExpectedString, | 32 codeExpectedString, |
33 codeExpectedType, | |
34 codeExtraneousModifier, | 33 codeExtraneousModifier, |
35 codeExtraneousModifierReplace, | |
36 codeFactoryNotSync, | 34 codeFactoryNotSync, |
37 codeGeneratorReturnsValue, | 35 codeGeneratorReturnsValue, |
38 codeInvalidAwaitFor, | 36 codeInvalidAwaitFor, |
39 codeInvalidInlineFunctionType, | 37 codeInvalidInlineFunctionType, |
40 codeInvalidSyncModifier, | 38 codeInvalidSyncModifier, |
41 codeInvalidVoid, | 39 codeInvalidVoid, |
42 codeNonAsciiIdentifier, | 40 codeNonAsciiIdentifier, |
43 codeNonAsciiWhitespace, | 41 codeNonAsciiWhitespace, |
44 codeOnlyTry, | 42 codeOnlyTry, |
45 codePositionalParameterWithEquals, | 43 codePositionalParameterWithEquals, |
46 codeRequiredParameterWithDefault, | 44 codeRequiredParameterWithDefault, |
47 codeSetterNotSync, | 45 codeSetterNotSync, |
48 codeStackOverflow, | 46 codeStackOverflow, |
47 codeTypeAfterVar, | |
48 codeTypeRequired, | |
49 codeUnexpectedToken, | 49 codeUnexpectedToken, |
50 codeUnmatchedToken, | 50 codeUnmatchedToken, |
51 codeUnspecified, | 51 codeUnspecified, |
52 codeUnsupportedPrefixPlus, | 52 codeUnsupportedPrefixPlus, |
53 codeUnterminatedString, | 53 codeUnterminatedString, |
54 codeYieldAsIdentifier, | 54 codeYieldAsIdentifier, |
55 codeYieldNotGenerator; | 55 codeYieldNotGenerator; |
56 | 56 |
57 import '../scanner.dart' show ErrorToken; | 57 import '../scanner.dart' show ErrorToken; |
58 | 58 |
59 import '../scanner/recover.dart' show closeBraceFor, skipToEof; | 59 import '../scanner/recover.dart' show closeBraceFor, skipToEof; |
60 | 60 |
61 import '../../scanner/token.dart' | 61 import '../../scanner/token.dart' |
62 show | 62 show |
63 ASSIGNMENT_PRECEDENCE, | 63 ASSIGNMENT_PRECEDENCE, |
64 CASCADE_PRECEDENCE, | 64 CASCADE_PRECEDENCE, |
65 EQUALITY_PRECEDENCE, | 65 EQUALITY_PRECEDENCE, |
66 Keyword, | |
67 POSTFIX_PRECEDENCE, | 66 POSTFIX_PRECEDENCE, |
68 RELATIONAL_PRECEDENCE, | 67 RELATIONAL_PRECEDENCE, |
69 TokenType; | 68 TokenType; |
70 | 69 |
71 import '../scanner/token.dart' | 70 import '../scanner/token.dart' |
72 show | 71 show BeginGroupToken, SymbolToken, Token, isUserDefinableOperator; |
73 BeginGroupToken, | |
74 KeywordToken, | |
75 SymbolToken, | |
76 Token, | |
77 isUserDefinableOperator; | |
78 | 72 |
79 import '../scanner/token_constants.dart' | 73 import '../scanner/token_constants.dart' |
80 show | 74 show |
81 COMMA_TOKEN, | 75 COMMA_TOKEN, |
82 DOUBLE_TOKEN, | 76 DOUBLE_TOKEN, |
83 EOF_TOKEN, | 77 EOF_TOKEN, |
84 EQ_TOKEN, | 78 EQ_TOKEN, |
85 FUNCTION_TOKEN, | 79 FUNCTION_TOKEN, |
86 GT_TOKEN, | 80 GT_TOKEN, |
87 GT_GT_TOKEN, | 81 GT_GT_TOKEN, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
119 final String type; | 113 final String type; |
120 const FormalParameterType(this.type); | 114 const FormalParameterType(this.type); |
121 bool get isRequired => this == REQUIRED; | 115 bool get isRequired => this == REQUIRED; |
122 bool get isPositional => this == POSITIONAL; | 116 bool get isPositional => this == POSITIONAL; |
123 bool get isNamed => this == NAMED; | 117 bool get isNamed => this == NAMED; |
124 static final REQUIRED = const FormalParameterType('required'); | 118 static final REQUIRED = const FormalParameterType('required'); |
125 static final POSITIONAL = const FormalParameterType('positional'); | 119 static final POSITIONAL = const FormalParameterType('positional'); |
126 static final NAMED = const FormalParameterType('named'); | 120 static final NAMED = const FormalParameterType('named'); |
127 } | 121 } |
128 | 122 |
123 enum MemberKind { | |
124 /// A catch block, not a real member. | |
125 Catch, | |
126 | |
127 /// A factory | |
128 Factory, | |
129 | |
130 /// Old-style typedef. | |
131 FunctionTypeAlias, | |
132 | |
133 /// Old-style function-typed parameter, not a real member. | |
134 FunctionTypedParameter, | |
135 | |
136 /// A generalized function type, not a real member. | |
137 GeneralizedFunctionType, | |
138 | |
139 /// A local function. | |
140 Local, | |
141 | |
142 /// A non-static method in a class (including constructors). | |
143 NonStaticMethod, | |
144 | |
145 /// A static method in a class. | |
146 StaticMethod, | |
147 | |
148 /// A top-level method. | |
149 TopLevelMethod, | |
150 | |
151 /// An instance field in a class. | |
152 NonStaticField, | |
153 | |
154 /// A static field in a class. | |
155 StaticField, | |
156 | |
157 /// A top-level field. | |
158 TopLevelField, | |
159 } | |
160 | |
129 /// An event generating parser of Dart programs. This parser expects all tokens | 161 /// An event generating parser of Dart programs. This parser expects all tokens |
130 /// in a linked list (aka a token stream). | 162 /// in a linked list (aka a token stream). |
131 /// | 163 /// |
132 /// The class [Scanner] is used to generate a token stream. See the file | 164 /// The class [Scanner] is used to generate a token stream. See the file |
133 /// [scanner.dart](../scanner.dart). | 165 /// [scanner.dart](../scanner.dart). |
134 /// | 166 /// |
135 /// Subclasses of the class [Listener] are used to listen to events. | 167 /// Subclasses of the class [Listener] are used to listen to events. |
136 /// | 168 /// |
137 /// Most methods of this class belong in one of three major categories: parse | 169 /// Most methods of this class belong in one of three major categories: parse |
138 /// methods, peek methods, and skip methods. Parse methods all have the prefix | 170 /// methods, peek methods, and skip methods. Parse methods all have the prefix |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 if (identical(token.type, TokenType.SCRIPT_TAG)) { | 328 if (identical(token.type, TokenType.SCRIPT_TAG)) { |
297 return parseScript(token); | 329 return parseScript(token); |
298 } | 330 } |
299 token = parseMetadataStar(token); | 331 token = parseMetadataStar(token); |
300 final String value = token.stringValue; | 332 final String value = token.stringValue; |
301 if ((identical(value, 'abstract') && optional('class', token.next)) || | 333 if ((identical(value, 'abstract') && optional('class', token.next)) || |
302 identical(value, 'class')) { | 334 identical(value, 'class')) { |
303 return parseClassOrNamedMixinApplication(token); | 335 return parseClassOrNamedMixinApplication(token); |
304 } else if (identical(value, 'enum')) { | 336 } else if (identical(value, 'enum')) { |
305 return parseEnum(token); | 337 return parseEnum(token); |
306 } else if (identical(value, 'typedef')) { | 338 } else if (identical(value, 'typedef') && |
339 (token.next.isIdentifier || optional("void", token.next))) { | |
307 return parseTypedef(token); | 340 return parseTypedef(token); |
308 } else if (identical(value, 'library')) { | 341 } else if (identical(value, 'library')) { |
309 return parseLibraryName(token); | 342 return parseLibraryName(token); |
310 } else if (identical(value, 'import')) { | 343 } else if (identical(value, 'import')) { |
311 return parseImport(token); | 344 return parseImport(token); |
312 } else if (identical(value, 'export')) { | 345 } else if (identical(value, 'export')) { |
313 return parseExport(token); | 346 return parseExport(token); |
314 } else if (identical(value, 'part')) { | 347 } else if (identical(value, 'part')) { |
315 return parsePartOrPartOf(token); | 348 return parsePartOrPartOf(token); |
316 } else { | 349 } else { |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
560 if (optional('=', peekAfterNominalType(token.next))) { | 593 if (optional('=', peekAfterNominalType(token.next))) { |
561 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); | 594 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); |
562 token = parseTypeVariablesOpt(token); | 595 token = parseTypeVariablesOpt(token); |
563 equals = token; | 596 equals = token; |
564 token = expect('=', token); | 597 token = expect('=', token); |
565 token = parseType(token); | 598 token = parseType(token); |
566 } else { | 599 } else { |
567 token = parseReturnTypeOpt(token.next); | 600 token = parseReturnTypeOpt(token.next); |
568 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); | 601 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); |
569 token = parseTypeVariablesOpt(token); | 602 token = parseTypeVariablesOpt(token); |
570 token = parseFormalParameters(token); | 603 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); |
571 } | 604 } |
572 listener.endFunctionTypeAlias(typedefKeyword, equals, token); | 605 listener.endFunctionTypeAlias(typedefKeyword, equals, token); |
573 return expect(';', token); | 606 return expect(';', token); |
574 } | 607 } |
575 | 608 |
576 Token parseMixinApplication(Token token) { | 609 Token parseMixinApplication(Token token) { |
577 listener.beginMixinApplication(token); | 610 listener.beginMixinApplication(token); |
578 token = parseType(token); | 611 token = parseType(token); |
579 Token withKeyword = token; | 612 Token withKeyword = token; |
580 token = expect('with', token); | 613 token = expect('with', token); |
581 token = parseTypeList(token); | 614 token = parseTypeList(token); |
582 listener.endMixinApplication(withKeyword); | 615 listener.endMixinApplication(withKeyword); |
583 return token; | 616 return token; |
584 } | 617 } |
585 | 618 |
586 Token parseReturnTypeOpt(Token token) { | 619 Token parseReturnTypeOpt(Token token) { |
587 if (identical(token.stringValue, 'void')) { | 620 if (identical(token.stringValue, 'void')) { |
588 if (isGeneralizedFunctionType(token.next)) { | 621 if (isGeneralizedFunctionType(token.next)) { |
589 return parseType(token); | 622 return parseType(token); |
590 } else { | 623 } else { |
591 listener.handleVoidKeyword(token); | 624 listener.handleVoidKeyword(token); |
592 return token.next; | 625 return token.next; |
593 } | 626 } |
594 } else { | 627 } else { |
595 return parseTypeOpt(token); | 628 return parseTypeOpt(token); |
596 } | 629 } |
597 } | 630 } |
598 | 631 |
599 Token parseFormalParametersOpt(Token token) { | 632 Token parseFormalParametersOpt(Token token, MemberKind kind) { |
600 if (optional('(', token)) { | 633 if (optional('(', token)) { |
601 return parseFormalParameters(token); | 634 return parseFormalParameters(token, kind); |
602 } else { | 635 } else { |
603 listener.handleNoFormalParameters(token); | 636 listener.handleNoFormalParameters(token, kind); |
604 return token; | 637 return token; |
605 } | 638 } |
606 } | 639 } |
607 | 640 |
608 Token skipFormalParameters(Token token) { | 641 Token skipFormalParameters(Token token, MemberKind kind) { |
609 // TODO(ahe): Shouldn't this be `beginFormalParameters`? | 642 // TODO(ahe): Shouldn't this be `beginFormalParameters`? |
610 listener.beginOptionalFormalParameters(token); | 643 listener.beginOptionalFormalParameters(token); |
611 if (!optional('(', token)) { | 644 if (!optional('(', token)) { |
612 if (optional(';', token)) { | 645 if (optional(';', token)) { |
613 reportRecoverableErrorCode(token, codeExpectedOpenParens); | 646 reportRecoverableErrorCode(token, codeExpectedOpenParens); |
614 return token; | 647 return token; |
615 } | 648 } |
616 return reportUnrecoverableErrorCodeWithString( | 649 return reportUnrecoverableErrorCodeWithString( |
617 token, codeExpectedButGot, "(") | 650 token, codeExpectedButGot, "(") |
618 .next; | 651 .next; |
619 } | 652 } |
620 BeginGroupToken beginGroupToken = token; | 653 BeginGroupToken beginGroupToken = token; |
621 Token endToken = beginGroupToken.endGroup; | 654 Token endToken = beginGroupToken.endGroup; |
622 listener.endFormalParameters(0, token, endToken); | 655 listener.endFormalParameters(0, token, endToken, kind); |
623 return endToken.next; | 656 return endToken.next; |
624 } | 657 } |
625 | 658 |
626 /// Parses the formal parameter list of a function. | 659 /// Parses the formal parameter list of a function. |
627 /// | 660 /// |
628 /// If [inFunctionType] is true, then the names may be omitted (except for | 661 /// If `kind == MemberKind.GeneralizedFunctionType`, then names may be |
629 /// named arguments). If it is false, then the types may be omitted. | 662 /// omitted (except for named arguments). Otherwise, types may be omitted. |
630 Token parseFormalParameters(Token token, {bool inFunctionType: false}) { | 663 Token parseFormalParameters(Token token, MemberKind kind) { |
631 Token begin = token; | 664 Token begin = token; |
632 listener.beginFormalParameters(begin); | 665 listener.beginFormalParameters(begin, kind); |
633 expect('(', token); | 666 expect('(', token); |
634 int parameterCount = 0; | 667 int parameterCount = 0; |
635 do { | 668 do { |
636 token = token.next; | 669 token = token.next; |
637 if (optional(')', token)) { | 670 if (optional(')', token)) { |
638 break; | 671 break; |
639 } | 672 } |
640 ++parameterCount; | 673 ++parameterCount; |
641 String value = token.stringValue; | 674 String value = token.stringValue; |
642 if (identical(value, '[')) { | 675 if (identical(value, '[')) { |
643 token = parseOptionalFormalParameters(token, false, | 676 token = parseOptionalFormalParameters(token, false, kind); |
644 inFunctionType: inFunctionType); | |
645 break; | 677 break; |
646 } else if (identical(value, '{')) { | 678 } else if (identical(value, '{')) { |
647 token = parseOptionalFormalParameters(token, true, | 679 token = parseOptionalFormalParameters(token, true, kind); |
648 inFunctionType: inFunctionType); | |
649 break; | 680 break; |
650 } else if (identical(value, '[]')) { | 681 } else if (identical(value, '[]')) { |
651 --parameterCount; | 682 --parameterCount; |
652 reportRecoverableErrorCode(token, codeEmptyOptionalParameterList); | 683 reportRecoverableErrorCode(token, codeEmptyOptionalParameterList); |
653 token = token.next; | 684 token = token.next; |
654 break; | 685 break; |
655 } | 686 } |
656 token = parseFormalParameter(token, FormalParameterType.REQUIRED, | 687 token = parseFormalParameter(token, FormalParameterType.REQUIRED, kind); |
657 inFunctionType: inFunctionType); | |
658 } while (optional(',', token)); | 688 } while (optional(',', token)); |
659 listener.endFormalParameters(parameterCount, begin, token); | 689 listener.endFormalParameters(parameterCount, begin, token, kind); |
660 return expect(')', token); | 690 return expect(')', token); |
661 } | 691 } |
662 | 692 |
663 Token parseFormalParameter(Token token, FormalParameterType kind, | 693 Token parseFormalParameter( |
664 {bool inFunctionType: false}) { | 694 Token token, FormalParameterType kind, MemberKind memberKind) { |
Johnni Winther
2017/05/19 08:23:39
Rename [kind] to [parameterKind]
ahe
2017/05/19 09:02:47
Done.
| |
665 token = parseMetadataStar(token, forParameter: true); | 695 token = parseMetadataStar(token, forParameter: true); |
666 listener.beginFormalParameter(token); | 696 listener.beginFormalParameter(token, memberKind); |
667 | 697 |
668 // Skip over `covariant` token, if the next token is an identifier or | 698 bool inFunctionType = memberKind == MemberKind.GeneralizedFunctionType; |
669 // modifier. | 699 token = parseModifiers(token, memberKind, parameterKind: kind); |
670 // This enables the case where `covariant` is the name of the parameter: | |
671 // void foo(covariant); | |
672 Token covariantKeyword; | |
673 if (identical(token.stringValue, 'covariant') && | |
674 (token.next.isIdentifier || isModifier(token.next))) { | |
675 covariantKeyword = token; | |
676 token = token.next; | |
677 } | |
678 token = parseModifiers(token); | |
679 bool isNamedParameter = kind == FormalParameterType.NAMED; | 700 bool isNamedParameter = kind == FormalParameterType.NAMED; |
680 | 701 |
681 Token thisKeyword = null; | 702 Token thisKeyword = null; |
682 Token nameToken; | 703 Token nameToken; |
683 if (inFunctionType && isNamedParameter) { | 704 if (inFunctionType) { |
684 token = parseType(token); | 705 if (isNamedParameter || token.isIdentifier) { |
685 token = | |
686 parseIdentifier(token, IdentifierContext.formalParameterDeclaration); | |
687 } else if (inFunctionType) { | |
688 token = parseType(token); | |
689 if (token.isIdentifier) { | |
690 token = parseIdentifier( | 706 token = parseIdentifier( |
691 token, IdentifierContext.formalParameterDeclaration); | 707 token, IdentifierContext.formalParameterDeclaration); |
692 } else { | 708 } else { |
693 listener.handleNoName(token); | 709 listener.handleNoName(token); |
694 } | 710 } |
695 } else { | 711 } else { |
696 token = parseReturnTypeOpt(token); | |
697 if (optional('this', token)) { | 712 if (optional('this', token)) { |
698 thisKeyword = token; | 713 thisKeyword = token; |
699 token = expect('.', token.next); | 714 token = expect('.', token.next); |
700 nameToken = token; | 715 nameToken = token; |
701 token = parseIdentifier(token, IdentifierContext.fieldInitializer); | 716 token = parseIdentifier(token, IdentifierContext.fieldInitializer); |
702 } else { | 717 } else { |
703 nameToken = token; | 718 nameToken = token; |
704 token = parseIdentifier( | 719 token = parseIdentifier( |
705 token, IdentifierContext.formalParameterDeclaration); | 720 token, IdentifierContext.formalParameterDeclaration); |
706 } | 721 } |
707 } | 722 } |
708 | 723 |
709 token = listener.injectGenericCommentTypeList(token); | 724 token = listener.injectGenericCommentTypeList(token); |
710 if (optional('(', token)) { | 725 if (optional('(', token)) { |
711 Token inlineFunctionTypeStart = token; | 726 Token inlineFunctionTypeStart = token; |
712 listener.beginFunctionTypedFormalParameter(token); | 727 listener.beginFunctionTypedFormalParameter(token); |
713 listener.handleNoTypeVariables(token); | 728 listener.handleNoTypeVariables(token); |
714 token = parseFormalParameters(token); | 729 token = parseFormalParameters(token, MemberKind.FunctionTypedParameter); |
715 listener.endFunctionTypedFormalParameter( | 730 listener.endFunctionTypedFormalParameter(thisKeyword, kind); |
716 covariantKeyword, thisKeyword, kind); | |
717 // Generalized function types don't allow inline function types. | 731 // Generalized function types don't allow inline function types. |
718 // The following isn't allowed: | 732 // The following isn't allowed: |
719 // int Function(int bar(String x)). | 733 // int Function(int bar(String x)). |
720 if (inFunctionType) { | 734 if (memberKind == MemberKind.GeneralizedFunctionType) { |
721 reportRecoverableErrorCode( | 735 reportRecoverableErrorCode( |
722 inlineFunctionTypeStart, codeInvalidInlineFunctionType); | 736 inlineFunctionTypeStart, codeInvalidInlineFunctionType); |
723 } | 737 } |
724 } else if (optional('<', token)) { | 738 } else if (optional('<', token)) { |
725 Token inlineFunctionTypeStart = token; | 739 Token inlineFunctionTypeStart = token; |
726 listener.beginFunctionTypedFormalParameter(token); | 740 listener.beginFunctionTypedFormalParameter(token); |
727 token = parseTypeVariablesOpt(token); | 741 token = parseTypeVariablesOpt(token); |
728 token = parseFormalParameters(token); | 742 token = parseFormalParameters(token, MemberKind.FunctionTypedParameter); |
729 listener.endFunctionTypedFormalParameter( | 743 listener.endFunctionTypedFormalParameter(thisKeyword, kind); |
730 covariantKeyword, thisKeyword, kind); | |
731 // Generalized function types don't allow inline function types. | 744 // Generalized function types don't allow inline function types. |
732 // The following isn't allowed: | 745 // The following isn't allowed: |
733 // int Function(int bar(String x)). | 746 // int Function(int bar(String x)). |
734 if (inFunctionType) { | 747 if (memberKind == MemberKind.GeneralizedFunctionType) { |
735 reportRecoverableErrorCode( | 748 reportRecoverableErrorCode( |
736 inlineFunctionTypeStart, codeInvalidInlineFunctionType); | 749 inlineFunctionTypeStart, codeInvalidInlineFunctionType); |
737 } | 750 } |
738 } | 751 } |
739 String value = token.stringValue; | 752 String value = token.stringValue; |
740 if ((identical('=', value)) || (identical(':', value))) { | 753 if ((identical('=', value)) || (identical(':', value))) { |
741 // TODO(ahe): Validate that these are only used for optional parameters. | 754 // TODO(ahe): Validate that these are only used for optional parameters. |
742 Token equal = token; | 755 Token equal = token; |
743 token = parseExpression(token.next); | 756 token = parseExpression(token.next); |
744 listener.handleValuedFormalParameter(equal, token); | 757 listener.handleValuedFormalParameter(equal, token); |
745 if (kind.isRequired) { | 758 if (kind.isRequired) { |
746 reportRecoverableErrorCode(equal, codeRequiredParameterWithDefault); | 759 reportRecoverableErrorCode(equal, codeRequiredParameterWithDefault); |
747 } else if (kind.isPositional && identical(':', value)) { | 760 } else if (kind.isPositional && identical(':', value)) { |
748 reportRecoverableErrorCode(equal, codePositionalParameterWithEquals); | 761 reportRecoverableErrorCode(equal, codePositionalParameterWithEquals); |
749 } | 762 } |
750 } else { | 763 } else { |
751 listener.handleFormalParameterWithoutValue(token); | 764 listener.handleFormalParameterWithoutValue(token); |
752 } | 765 } |
753 listener.endFormalParameter(covariantKeyword, thisKeyword, nameToken, kind); | 766 listener.endFormalParameter(thisKeyword, nameToken, kind, memberKind); |
754 return token; | 767 return token; |
755 } | 768 } |
756 | 769 |
757 Token parseOptionalFormalParameters(Token token, bool isNamed, | 770 Token parseOptionalFormalParameters( |
758 {bool inFunctionType: false}) { | 771 Token token, bool isNamed, MemberKind kind) { |
759 Token begin = token; | 772 Token begin = token; |
760 listener.beginOptionalFormalParameters(begin); | 773 listener.beginOptionalFormalParameters(begin); |
761 assert((isNamed && optional('{', token)) || optional('[', token)); | 774 assert((isNamed && optional('{', token)) || optional('[', token)); |
762 int parameterCount = 0; | 775 int parameterCount = 0; |
763 do { | 776 do { |
764 token = token.next; | 777 token = token.next; |
765 if (isNamed && optional('}', token)) { | 778 if (isNamed && optional('}', token)) { |
766 break; | 779 break; |
767 } else if (!isNamed && optional(']', token)) { | 780 } else if (!isNamed && optional(']', token)) { |
768 break; | 781 break; |
769 } | 782 } |
770 var type = | 783 var type = |
771 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | 784 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; |
772 token = parseFormalParameter(token, type, inFunctionType: inFunctionType); | 785 token = parseFormalParameter(token, type, kind); |
773 ++parameterCount; | 786 ++parameterCount; |
774 } while (optional(',', token)); | 787 } while (optional(',', token)); |
775 if (parameterCount == 0) { | 788 if (parameterCount == 0) { |
776 reportRecoverableErrorCode( | 789 reportRecoverableErrorCode( |
777 token, | 790 token, |
778 isNamed | 791 isNamed |
779 ? codeEmptyNamedParameterList | 792 ? codeEmptyNamedParameterList |
780 : codeEmptyOptionalParameterList); | 793 : codeEmptyOptionalParameterList); |
781 } | 794 } |
782 listener.endOptionalFormalParameters(parameterCount, begin, token); | 795 listener.endOptionalFormalParameters(parameterCount, begin, token); |
(...skipping 12 matching lines...) Expand all Loading... | |
795 token = listener.injectGenericCommentTypeAssign(token); | 808 token = listener.injectGenericCommentTypeAssign(token); |
796 Token peek = peekAfterIfType(token); | 809 Token peek = peekAfterIfType(token); |
797 if (peek != null && (peek.isIdentifier || optional('this', peek))) { | 810 if (peek != null && (peek.isIdentifier || optional('this', peek))) { |
798 return parseType(token); | 811 return parseType(token); |
799 } | 812 } |
800 listener.handleNoType(token); | 813 listener.handleNoType(token); |
801 return token; | 814 return token; |
802 } | 815 } |
803 | 816 |
804 bool isValidTypeReference(Token token) { | 817 bool isValidTypeReference(Token token) { |
805 final kind = token.kind; | 818 int kind = token.kind; |
806 if (identical(kind, IDENTIFIER_TOKEN)) return true; | 819 if (IDENTIFIER_TOKEN == kind) return true; |
807 if (identical(kind, KEYWORD_TOKEN)) { | 820 if (KEYWORD_TOKEN == kind) { |
808 Keyword keyword = (token as KeywordToken).keyword; | 821 String value = token.lexeme; |
809 String value = keyword.lexeme; | 822 return token.type.isPseudo || |
810 return keyword.isPseudo || | |
811 (identical(value, 'dynamic')) || | 823 (identical(value, 'dynamic')) || |
812 (identical(value, 'void')); | 824 (identical(value, 'void')); |
813 } | 825 } |
814 return false; | 826 return false; |
815 } | 827 } |
816 | 828 |
817 /// Returns true if [token] matches '<' type (',' type)* '>' '(', and | 829 /// Returns true if [token] matches '<' type (',' type)* '>' '(', and |
818 /// otherwise returns false. The final '(' is not part of the grammar | 830 /// otherwise returns false. The final '(' is not part of the grammar |
819 /// construct `typeArguments`, but it is required here such that type | 831 /// construct `typeArguments`, but it is required here such that type |
820 /// arguments in generic method invocations can be recognized, and as few as | 832 /// arguments in generic method invocations can be recognized, and as few as |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1033 if (token.kind != STRING_TOKEN) { | 1045 if (token.kind != STRING_TOKEN) { |
1034 token = | 1046 token = |
1035 reportUnrecoverableErrorCodeWithToken(token, codeExpectedString).next; | 1047 reportUnrecoverableErrorCodeWithToken(token, codeExpectedString).next; |
1036 } | 1048 } |
1037 listener.handleStringPart(token); | 1049 listener.handleStringPart(token); |
1038 return token.next; | 1050 return token.next; |
1039 } | 1051 } |
1040 | 1052 |
1041 Token parseIdentifier(Token token, IdentifierContext context) { | 1053 Token parseIdentifier(Token token, IdentifierContext context) { |
1042 if (!token.isIdentifier) { | 1054 if (!token.isIdentifier) { |
1043 token = | 1055 if (optional("void", token)) { |
1044 reportUnrecoverableErrorCodeWithToken(token, codeExpectedIdentifier) | 1056 reportRecoverableErrorCode(token, codeInvalidVoid); |
1045 .next; | 1057 } else { |
1058 token = | |
1059 reportUnrecoverableErrorCodeWithToken(token, codeExpectedIdentifier) | |
1060 .next; | |
1061 } | |
1046 } else if (token.isBuiltInIdentifier && | 1062 } else if (token.isBuiltInIdentifier && |
1047 !context.isBuiltInIdentifierAllowed) { | 1063 !context.isBuiltInIdentifierAllowed) { |
1048 if (context.inDeclaration) { | 1064 if (context.inDeclaration) { |
1049 reportRecoverableErrorCodeWithToken( | 1065 reportRecoverableErrorCodeWithToken( |
1050 token, codeBuiltInIdentifierInDeclaration); | 1066 token, codeBuiltInIdentifierInDeclaration); |
1051 } else if (!optional("dynamic", token)) { | 1067 } else if (!optional("dynamic", token)) { |
1052 reportRecoverableErrorCodeWithToken(token, codeBuiltInIdentifierAsType); | 1068 reportRecoverableErrorCodeWithToken(token, codeBuiltInIdentifierAsType); |
1053 } | 1069 } |
1054 } else if (!inPlainSync && token.type.isPseudo) { | 1070 } else if (!inPlainSync && token.type.isPseudo) { |
1055 if (optional('await', token)) { | 1071 if (optional('await', token)) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1118 (optional('<', token.next) || optional('(', token.next)); | 1134 (optional('<', token.next) || optional('(', token.next)); |
1119 } | 1135 } |
1120 | 1136 |
1121 Token parseType(Token token) { | 1137 Token parseType(Token token) { |
1122 Token begin = token; | 1138 Token begin = token; |
1123 if (isGeneralizedFunctionType(token)) { | 1139 if (isGeneralizedFunctionType(token)) { |
1124 // A function type without return type. | 1140 // A function type without return type. |
1125 // Push the non-existing return type first. The loop below will | 1141 // Push the non-existing return type first. The loop below will |
1126 // generate the full type. | 1142 // generate the full type. |
1127 listener.handleNoType(token); | 1143 listener.handleNoType(token); |
1128 } else if (identical(token.stringValue, 'void') && | 1144 } else if (optional("void", token) && |
1129 isGeneralizedFunctionType(token.next)) { | 1145 isGeneralizedFunctionType(token.next)) { |
1130 listener.handleVoidKeyword(token); | 1146 listener.handleVoidKeyword(token); |
1131 token = token.next; | 1147 token = token.next; |
1132 } else { | 1148 } else { |
1133 if (isValidTypeReference(token)) { | 1149 IdentifierContext context = IdentifierContext.typeReference; |
1134 token = parseIdentifier(token, IdentifierContext.typeReference); | 1150 if (token.isIdentifier && optional(".", token.next)) { |
1135 token = parseQualifiedRestOpt( | 1151 context = IdentifierContext.prefixedTypeReference; |
1136 token, IdentifierContext.typeReferenceContinuation); | |
1137 } else { | |
1138 token = | |
1139 reportUnrecoverableErrorCodeWithToken(token, codeExpectedType).next; | |
1140 listener.handleInvalidTypeReference(token); | |
1141 } | 1152 } |
1153 token = parseIdentifier(token, context); | |
1154 token = parseQualifiedRestOpt( | |
1155 token, IdentifierContext.typeReferenceContinuation); | |
1142 token = parseTypeArgumentsOpt(token); | 1156 token = parseTypeArgumentsOpt(token); |
1143 listener.handleType(begin, token); | 1157 listener.handleType(begin, token); |
1144 } | 1158 } |
1145 | 1159 |
1146 { | 1160 { |
1147 Token newBegin = | 1161 Token newBegin = |
1148 listener.replaceTokenWithGenericCommentTypeAssign(begin, token); | 1162 listener.replaceTokenWithGenericCommentTypeAssign(begin, token); |
1149 if (!identical(newBegin, begin)) { | 1163 if (!identical(newBegin, begin)) { |
1150 listener.discardTypeReplacedWithCommentTypeAssign(); | 1164 listener.discardTypeReplacedWithCommentTypeAssign(); |
1151 return parseType(newBegin); | 1165 return parseType(newBegin); |
1152 } | 1166 } |
1153 } | 1167 } |
1154 | 1168 |
1155 // While we see a `Function(` treat the pushed type as return type. | 1169 // While we see a `Function(` treat the pushed type as return type. |
1156 // For example: `int Function() Function(int) Function(String x)`. | 1170 // For example: `int Function() Function(int) Function(String x)`. |
1157 while (isGeneralizedFunctionType(token)) { | 1171 while (isGeneralizedFunctionType(token)) { |
1158 token = parseFunctionType(token); | 1172 token = parseFunctionType(token); |
1159 } | 1173 } |
1160 return token; | 1174 return token; |
1161 } | 1175 } |
1162 | 1176 |
1163 /// Parses a generalized function type. | 1177 /// Parses a generalized function type. |
1164 /// | 1178 /// |
1165 /// The return type must already be pushed. | 1179 /// The return type must already be pushed. |
1166 Token parseFunctionType(Token token) { | 1180 Token parseFunctionType(Token token) { |
1167 assert(optional('Function', token)); | 1181 assert(optional('Function', token)); |
1168 Token functionToken = token; | 1182 Token functionToken = token; |
1169 token = token.next; | 1183 token = token.next; |
1170 token = parseTypeVariablesOpt(token); | 1184 token = parseTypeVariablesOpt(token); |
1171 token = parseFormalParameters(token, inFunctionType: true); | 1185 token = parseFormalParameters(token, MemberKind.GeneralizedFunctionType); |
1172 listener.handleFunctionType(functionToken, token); | 1186 listener.handleFunctionType(functionToken, token); |
1173 return token; | 1187 return token; |
1174 } | 1188 } |
1175 | 1189 |
1176 Token parseTypeArgumentsOpt(Token token) { | 1190 Token parseTypeArgumentsOpt(Token token) { |
1177 return parseStuff( | 1191 return parseStuff( |
1178 token, | 1192 token, |
1179 (t) => listener.beginTypeArguments(t), | 1193 (t) => listener.beginTypeArguments(t), |
1180 (t) => parseType(t), | 1194 (t) => parseType(t), |
1181 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 1195 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1280 token = reportUnexpectedToken(token).next; | 1294 token = reportUnexpectedToken(token).next; |
1281 if (identical(token.kind, EOF_TOKEN)) return token; | 1295 if (identical(token.kind, EOF_TOKEN)) return token; |
1282 } | 1296 } |
1283 } | 1297 } |
1284 var modifiers = identifiers.reverse(); | 1298 var modifiers = identifiers.reverse(); |
1285 return isField | 1299 return isField |
1286 ? parseFields(start, modifiers, type, getOrSet, name, true) | 1300 ? parseFields(start, modifiers, type, getOrSet, name, true) |
1287 : parseTopLevelMethod(start, modifiers, type, getOrSet, name); | 1301 : parseTopLevelMethod(start, modifiers, type, getOrSet, name); |
1288 } | 1302 } |
1289 | 1303 |
1290 bool isVarFinalOrConst(Token token) { | |
1291 String value = token.stringValue; | |
1292 return identical('var', value) || | |
1293 identical('final', value) || | |
1294 identical('const', value); | |
1295 } | |
1296 | |
1297 Token expectVarFinalOrConst( | |
1298 Link<Token> modifiers, bool hasType, bool allowStatic) { | |
1299 int modifierCount = 0; | |
1300 Token staticModifier; | |
1301 if (allowStatic && | |
1302 !modifiers.isEmpty && | |
1303 optional('static', modifiers.head)) { | |
1304 staticModifier = modifiers.head; | |
1305 modifierCount++; | |
1306 parseModifier(staticModifier); | |
1307 modifiers = modifiers.tail; | |
1308 } | |
1309 if (modifiers.isEmpty) { | |
1310 listener.handleModifiers(modifierCount); | |
1311 return null; | |
1312 } | |
1313 if (modifiers.tail.isEmpty) { | |
1314 Token modifier = modifiers.head; | |
1315 if (isVarFinalOrConst(modifier)) { | |
1316 modifierCount++; | |
1317 parseModifier(modifier); | |
1318 listener.handleModifiers(modifierCount); | |
1319 // TODO(ahe): The caller checks for "var Type name", perhaps we should | |
1320 // check here instead. | |
1321 return modifier; | |
1322 } | |
1323 } | |
1324 | |
1325 // Slow case to report errors. | |
1326 List<Token> modifierList = modifiers.toList(); | |
1327 Token varFinalOrConst = | |
1328 modifierList.firstWhere(isVarFinalOrConst, orElse: () => null); | |
1329 if (allowStatic && staticModifier == null) { | |
1330 staticModifier = modifierList.firstWhere( | |
1331 (modifier) => optional('static', modifier), | |
1332 orElse: () => null); | |
1333 if (staticModifier != null) { | |
1334 modifierCount++; | |
1335 parseModifier(staticModifier); | |
1336 modifierList.remove(staticModifier); | |
1337 } | |
1338 } | |
1339 bool hasTypeOrModifier = hasType; | |
1340 if (varFinalOrConst != null) { | |
1341 parseModifier(varFinalOrConst); | |
1342 modifierCount++; | |
1343 hasTypeOrModifier = true; | |
1344 modifierList.remove(varFinalOrConst); | |
1345 } | |
1346 listener.handleModifiers(modifierCount); | |
1347 for (Token modifier in modifierList) { | |
1348 reportRecoverableErrorCodeWithToken( | |
1349 modifier, | |
1350 hasTypeOrModifier | |
1351 ? codeExtraneousModifier | |
1352 : codeExtraneousModifierReplace); | |
1353 } | |
1354 return null; | |
1355 } | |
1356 | |
1357 /// Removes the optional `covariant` token from the modifiers, if there | |
1358 /// is no `static` in the list, and `covariant` is the first modifier. | |
1359 Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) { | |
1360 if (modifiers.isEmpty || | |
1361 !identical(modifiers.first.stringValue, 'covariant')) { | |
1362 return modifiers; | |
1363 } | |
1364 for (Token modifier in modifiers.tail) { | |
1365 if (identical(modifier.stringValue, 'static')) { | |
1366 return modifiers; | |
1367 } | |
1368 } | |
1369 return modifiers.tail; | |
1370 } | |
1371 | |
1372 Token parseFields(Token start, Link<Token> modifiers, Token type, | 1304 Token parseFields(Token start, Link<Token> modifiers, Token type, |
1373 Token getOrSet, Token name, bool isTopLevel) { | 1305 Token getOrSet, Token name, bool isTopLevel) { |
1374 bool hasType = type != null; | 1306 Token token = parseModifiers(start, |
1307 isTopLevel ? MemberKind.TopLevelField : MemberKind.NonStaticField, | |
1308 isVariable: true); | |
1375 | 1309 |
1376 Token covariantKeyword; | 1310 if (token != name) { |
1377 if (getOrSet == null && !isTopLevel) { | 1311 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); |
1378 // TODO(ahe): replace the method removeOptCovariantTokenIfNotStatic with | 1312 token = name; |
1379 // a better mechanism. | |
1380 Link<Token> newModifiers = removeOptCovariantTokenIfNotStatic(modifiers); | |
1381 if (!identical(newModifiers, modifiers)) { | |
1382 covariantKeyword = modifiers.first; | |
1383 modifiers = newModifiers; | |
1384 } | |
1385 } | |
1386 | |
1387 Token varFinalOrConst = | |
1388 expectVarFinalOrConst(modifiers, hasType, !isTopLevel); | |
1389 bool isVar = false; | |
1390 bool hasModifier = false; | |
1391 if (varFinalOrConst != null) { | |
1392 hasModifier = true; | |
1393 isVar = optional('var', varFinalOrConst); | |
1394 } | |
1395 | |
1396 if (getOrSet != null) { | |
1397 reportRecoverableErrorCodeWithToken( | |
1398 getOrSet, | |
1399 hasModifier || hasType | |
1400 ? codeExtraneousModifier | |
1401 : codeExtraneousModifierReplace); | |
1402 } | |
1403 | |
1404 if (!hasType) { | |
1405 listener.handleNoType(name); | |
1406 } else if (optional('void', type) && | |
1407 !isGeneralizedFunctionType(type.next)) { | |
1408 listener.handleNoType(name); | |
1409 // TODO(ahe): This error is reported twice, second time is from | |
1410 // [parseVariablesDeclarationMaybeSemicolon] via | |
1411 // [PartialFieldListElement.parseNode]. | |
1412 reportRecoverableErrorCode(type, codeInvalidVoid); | |
1413 } else { | |
1414 parseType(type); | |
1415 if (isVar) { | |
1416 reportRecoverableErrorCodeWithToken( | |
1417 modifiers.head, codeExtraneousModifier); | |
1418 } | |
1419 } | 1313 } |
1420 | 1314 |
1421 IdentifierContext context = isTopLevel | 1315 IdentifierContext context = isTopLevel |
1422 ? IdentifierContext.topLevelVariableDeclaration | 1316 ? IdentifierContext.topLevelVariableDeclaration |
1423 : IdentifierContext.fieldDeclaration; | 1317 : IdentifierContext.fieldDeclaration; |
1424 Token token = parseIdentifier(name, context); | 1318 token = parseIdentifier(token, context); |
1425 | 1319 |
1426 int fieldCount = 1; | 1320 int fieldCount = 1; |
1427 token = parseFieldInitializerOpt(token); | 1321 token = parseFieldInitializerOpt(token); |
1428 while (optional(',', token)) { | 1322 while (optional(',', token)) { |
1429 token = parseIdentifier(token.next, context); | 1323 token = parseIdentifier(token.next, context); |
1430 token = parseFieldInitializerOpt(token); | 1324 token = parseFieldInitializerOpt(token); |
1431 ++fieldCount; | 1325 ++fieldCount; |
1432 } | 1326 } |
1433 Token semicolon = token; | 1327 Token semicolon = token; |
1434 token = expectSemicolon(token); | 1328 token = expectSemicolon(token); |
1435 if (isTopLevel) { | 1329 if (isTopLevel) { |
1436 listener.endTopLevelFields(fieldCount, start, semicolon); | 1330 listener.endTopLevelFields(fieldCount, start, semicolon); |
1437 } else { | 1331 } else { |
1438 listener.endFields(fieldCount, covariantKeyword, start, semicolon); | 1332 listener.endFields(fieldCount, start, semicolon); |
1439 } | 1333 } |
1440 return token; | 1334 return token; |
1441 } | 1335 } |
1442 | 1336 |
1443 Token parseTopLevelMethod(Token start, Link<Token> modifiers, Token type, | 1337 Token parseTopLevelMethod(Token start, Link<Token> modifiers, Token type, |
1444 Token getOrSet, Token name) { | 1338 Token getOrSet, Token name) { |
1445 listener.beginTopLevelMethod(start, name); | 1339 listener.beginTopLevelMethod(start, name); |
1446 Token externalModifier; | 1340 Token externalModifier; |
1447 // TODO(johnniwinther): Move error reporting to resolution to give more | 1341 // TODO(johnniwinther): Move error reporting to resolution to give more |
1448 // specific error messages. | 1342 // specific error messages. |
(...skipping 17 matching lines...) Expand all Loading... | |
1466 parseReturnTypeOpt(type); | 1360 parseReturnTypeOpt(type); |
1467 } | 1361 } |
1468 Token token = | 1362 Token token = |
1469 parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); | 1363 parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); |
1470 | 1364 |
1471 if (getOrSet == null) { | 1365 if (getOrSet == null) { |
1472 token = parseTypeVariablesOpt(token); | 1366 token = parseTypeVariablesOpt(token); |
1473 } else { | 1367 } else { |
1474 listener.handleNoTypeVariables(token); | 1368 listener.handleNoTypeVariables(token); |
1475 } | 1369 } |
1476 token = parseFormalParametersOpt(token); | 1370 token = parseFormalParametersOpt(token, MemberKind.TopLevelMethod); |
1477 AsyncModifier savedAsyncModifier = asyncState; | 1371 AsyncModifier savedAsyncModifier = asyncState; |
1478 Token asyncToken = token; | 1372 Token asyncToken = token; |
1479 token = parseAsyncModifier(token); | 1373 token = parseAsyncModifier(token); |
1480 if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) { | 1374 if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) { |
1481 reportRecoverableErrorCode(asyncToken, codeSetterNotSync); | 1375 reportRecoverableErrorCode(asyncToken, codeSetterNotSync); |
1482 } | 1376 } |
1483 token = parseFunctionBody(token, false, externalModifier != null); | 1377 token = parseFunctionBody(token, false, externalModifier != null); |
1484 asyncState = savedAsyncModifier; | 1378 asyncState = savedAsyncModifier; |
1485 Token endToken = token; | 1379 Token endToken = token; |
1486 token = token.next; | 1380 token = token.next; |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1684 } else { | 1578 } else { |
1685 reportRecoverableErrorCodeWithToken(token, codeExpectedString); | 1579 reportRecoverableErrorCodeWithToken(token, codeExpectedString); |
1686 return parseRecoverExpression(token); | 1580 return parseRecoverExpression(token); |
1687 } | 1581 } |
1688 } | 1582 } |
1689 | 1583 |
1690 Token expectSemicolon(Token token) { | 1584 Token expectSemicolon(Token token) { |
1691 return expect(';', token); | 1585 return expect(';', token); |
1692 } | 1586 } |
1693 | 1587 |
1694 bool isModifier(Token token) { | 1588 bool isModifier(Token token) => modifierOrder(token) < 127; |
1589 | |
1590 int modifierOrder(Token token) { | |
Johnni Winther
2017/05/19 08:23:39
Add doc about the semantics of the order.
ahe
2017/05/19 09:02:47
Done.
| |
1695 final String value = token.stringValue; | 1591 final String value = token.stringValue; |
1696 return (identical('final', value)) || | 1592 if (identical('external', value)) return 0; |
1697 (identical('var', value)) || | 1593 if (identical('static', value) || identical('covariant', value)) { |
1698 (identical('const', value)) || | 1594 return 1; |
1699 (identical('abstract', value)) || | 1595 } |
1700 (identical('static', value)) || | 1596 if (identical('final', value) || |
1701 (identical('external', value)); | 1597 identical('var', value) || |
1598 identical('const', value)) { | |
1599 return 2; | |
1600 } | |
1601 if (identical('abstract', value)) return 3; | |
1602 return 127; | |
1702 } | 1603 } |
1703 | 1604 |
1704 Token parseModifier(Token token) { | 1605 Token parseModifier(Token token) { |
1705 assert(isModifier(token)); | 1606 assert(isModifier(token)); |
1706 listener.handleModifier(token); | 1607 listener.handleModifier(token); |
1707 return token.next; | 1608 return token.next; |
1708 } | 1609 } |
1709 | 1610 |
1710 void parseModifierList(Link<Token> tokens) { | 1611 Token parseModifiers(Token token, MemberKind kind, |
Johnni Winther
2017/05/19 08:23:38
Add doc on when this is used (and not used)
Johnni Winther
2017/05/19 08:23:39
Rename [kind] to [memberKind].
ahe
2017/05/19 09:02:47
Done.
ahe
2017/05/19 09:02:47
Done.
| |
1612 {FormalParameterType parameterKind, bool isVariable: false}) { | |
1613 bool returnTypeAllowed = | |
1614 !isVariable && kind != MemberKind.GeneralizedFunctionType; | |
1615 bool typeRequired = | |
1616 isVariable || kind == MemberKind.GeneralizedFunctionType; | |
1711 int count = 0; | 1617 int count = 0; |
1712 for (; !tokens.isEmpty; tokens = tokens.tail) { | 1618 |
1713 Token token = tokens.head; | 1619 int currentOrder = -1; |
1714 if (isModifier(token)) { | 1620 bool hasVar = false; |
1715 parseModifier(token); | 1621 while (token.kind == KEYWORD_TOKEN) { |
1716 } else { | 1622 if (token.type.isPseudo) { |
1717 reportUnexpectedToken(token); | 1623 // A pseudo keyword is never a modifier. |
1718 // Skip the remaining modifiers. | |
1719 break; | 1624 break; |
1720 } | 1625 } |
1721 count++; | 1626 if (token.isBuiltInIdentifier) { |
1627 // A built-in identifier can only be a modifier as long as it is | |
1628 // followed by another modifier or an identifier. Otherwise, it is the | |
1629 // identifier. | |
1630 if (token.next.kind != KEYWORD_TOKEN && !token.next.isIdentifier) { | |
1631 break; | |
1632 } | |
1633 } | |
1634 int order = modifierOrder(token); | |
1635 if (order < 3) { | |
1636 // `abstract` isn't parsed with this method. | |
1637 if (order > currentOrder) { | |
1638 currentOrder = order; | |
1639 if (optional("var", token)) { | |
1640 if (!isVariable && parameterKind == null) { | |
1641 reportRecoverableErrorCodeWithToken( | |
1642 token, codeExtraneousModifier); | |
1643 } | |
1644 hasVar = true; | |
1645 typeRequired = false; | |
1646 } else if (optional("final", token)) { | |
1647 if (!isVariable && parameterKind == null) { | |
1648 reportRecoverableErrorCodeWithToken( | |
1649 token, codeExtraneousModifier); | |
1650 } | |
1651 typeRequired = false; | |
1652 } else if (optional("const", token)) { | |
1653 if (!isVariable) { | |
1654 reportRecoverableErrorCodeWithToken( | |
1655 token, codeExtraneousModifier); | |
1656 } | |
1657 typeRequired = false; | |
1658 } else if (optional("static", token)) { | |
1659 if (kind == MemberKind.NonStaticMethod) { | |
1660 kind = MemberKind.StaticMethod; | |
1661 } else if (kind == MemberKind.NonStaticField) { | |
1662 kind = MemberKind.StaticField; | |
1663 } else { | |
1664 reportRecoverableErrorCodeWithToken( | |
1665 token, codeExtraneousModifier); | |
1666 token = token.next; | |
1667 continue; | |
1668 } | |
1669 } else if (optional("covariant", token)) { | |
1670 switch (kind) { | |
1671 case MemberKind.StaticField: | |
1672 case MemberKind.StaticMethod: | |
1673 case MemberKind.TopLevelField: | |
1674 case MemberKind.TopLevelMethod: | |
1675 reportRecoverableErrorCodeWithToken( | |
1676 token, codeExtraneousModifier); | |
1677 token = token.next; | |
1678 continue; | |
1679 | |
1680 default: | |
1681 break; | |
1682 } | |
1683 } else if (optional("external", token)) { | |
1684 switch (kind) { | |
1685 case MemberKind.Factory: | |
1686 case MemberKind.NonStaticMethod: | |
1687 case MemberKind.StaticMethod: | |
1688 case MemberKind.TopLevelMethod: | |
1689 break; | |
1690 | |
1691 default: | |
1692 reportRecoverableErrorCodeWithToken( | |
1693 token, codeExtraneousModifier); | |
1694 token = token.next; | |
1695 continue; | |
1696 } | |
1697 } | |
1698 token = parseModifier(token); | |
1699 count++; | |
1700 } else { | |
1701 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); | |
1702 token = token.next; | |
1703 } | |
1704 } else { | |
1705 break; | |
1706 } | |
1722 } | 1707 } |
1723 listener.handleModifiers(count); | 1708 listener.handleModifiers(count); |
1724 } | |
1725 | 1709 |
1726 Token parseModifiers(Token token) { | 1710 Token beforeType = token; |
1727 // TODO(ahe): The calling convention of this method probably needs to | 1711 if (returnTypeAllowed) { |
1728 // change. For example, this is parsed as a local variable declaration: | 1712 token = parseReturnTypeOpt(token); |
1729 // `abstract foo;`. Ideally, this example should be handled as a local | 1713 } else { |
1730 // variable having the type `abstract` (which should be reported as | 1714 token = typeRequired ? parseType(token) : parseTypeOpt(token); |
1731 // `codeBuiltInIdentifierAsType` by [parseIdentifier]). | |
1732 int count = 0; | |
1733 while (identical(token.kind, KEYWORD_TOKEN)) { | |
1734 if (!isModifier(token)) break; | |
1735 token = parseModifier(token); | |
1736 count++; | |
1737 } | 1715 } |
1738 listener.handleModifiers(count); | 1716 if (typeRequired && beforeType == token) { |
1717 reportRecoverableErrorCode(token, codeTypeRequired); | |
1718 } | |
1719 if (hasVar && beforeType != token) { | |
1720 reportRecoverableErrorCode(beforeType, codeTypeAfterVar); | |
1721 } | |
1739 return token; | 1722 return token; |
1740 } | 1723 } |
1741 | 1724 |
1742 /// Returns the first token after the type starting at [token]. | 1725 /// Returns the first token after the type starting at [token]. |
1743 /// | 1726 /// |
1744 /// This method assumes that [token] is an identifier (or void). Use | 1727 /// This method assumes that [token] is an identifier (or void). Use |
1745 /// [peekAfterIfType] if [token] isn't known to be an identifier. | 1728 /// [peekAfterIfType] if [token] isn't known to be an identifier. |
1746 Token peekAfterType(Token token) { | 1729 Token peekAfterType(Token token) { |
1747 // We are looking at "identifier ...". | 1730 // We are looking at "identifier ...". |
1748 Token peek = token; | 1731 Token peek = token; |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1951 isField = true; | 1934 isField = true; |
1952 } | 1935 } |
1953 break; | 1936 break; |
1954 } else if ((identical(value, '=')) || (identical(value, ','))) { | 1937 } else if ((identical(value, '=')) || (identical(value, ','))) { |
1955 isField = true; | 1938 isField = true; |
1956 break; | 1939 break; |
1957 } else { | 1940 } else { |
1958 token = reportUnexpectedToken(token).next; | 1941 token = reportUnexpectedToken(token).next; |
1959 if (identical(token.kind, EOF_TOKEN)) { | 1942 if (identical(token.kind, EOF_TOKEN)) { |
1960 // TODO(ahe): This is a hack, see parseTopLevelMember. | 1943 // TODO(ahe): This is a hack, see parseTopLevelMember. |
1961 listener.endFields(1, null, start, token); | 1944 listener.endFields(1, start, token); |
1962 listener.endMember(); | 1945 listener.endMember(); |
1963 return token; | 1946 return token; |
1964 } | 1947 } |
1965 } | 1948 } |
1966 } | 1949 } |
1967 | 1950 |
1968 var modifiers = identifiers.reverse(); | 1951 var modifiers = identifiers.reverse(); |
1969 token = isField | 1952 token = isField |
1970 ? parseFields(start, modifiers, type, getOrSet, name, false) | 1953 ? parseFields(start, modifiers, type, getOrSet, name, false) |
1971 : parseMethod(start, modifiers, type, getOrSet, name); | 1954 : parseMethod(start, modifiers, type, getOrSet, name); |
1972 listener.endMember(); | 1955 listener.endMember(); |
1973 return token; | 1956 return token; |
1974 } | 1957 } |
1975 | 1958 |
1976 Token parseMethod(Token start, Link<Token> modifiers, Token type, | 1959 Token parseMethod(Token start, Link<Token> modifiers, Token type, |
1977 Token getOrSet, Token name) { | 1960 Token getOrSet, Token name) { |
1978 listener.beginMethod(start, name); | 1961 listener.beginMethod(start, name); |
1962 | |
1979 Token externalModifier; | 1963 Token externalModifier; |
1980 Token staticModifier; | 1964 Token staticModifier; |
1981 Token constModifier; | 1965 void parseModifierList(Link<Token> tokens) { |
1982 int modifierCount = 0; | 1966 int count = 0; |
1983 int allowedModifierCount = 1; | 1967 int currentOrder = -1; |
1984 // TODO(johnniwinther): Move error reporting to resolution to give more | 1968 for (; !tokens.isEmpty; tokens = tokens.tail) { |
1985 // specific error messages. | 1969 Token token = tokens.head; |
1986 for (Token modifier in modifiers) { | 1970 if (optional("abstract", token)) { |
1987 if (externalModifier == null && optional('external', modifier)) { | 1971 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); |
1988 modifierCount++; | 1972 continue; |
1989 externalModifier = modifier; | |
1990 if (modifierCount != allowedModifierCount) { | |
1991 reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier); | |
1992 } | 1973 } |
1993 allowedModifierCount++; | 1974 int order = modifierOrder(token); |
1994 } else if (staticModifier == null && optional('static', modifier)) { | 1975 if (order < 127) { |
1995 modifierCount++; | 1976 if (order > currentOrder) { |
1996 staticModifier = modifier; | 1977 currentOrder = order; |
1997 if (modifierCount != allowedModifierCount) { | 1978 if (optional("var", token)) { |
1998 reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier); | 1979 reportRecoverableErrorCodeWithToken( |
1980 token, codeExtraneousModifier); | |
1981 } else if (optional("const", token)) { | |
1982 if (getOrSet != null) { | |
1983 reportRecoverableErrorCodeWithToken( | |
1984 token, codeExtraneousModifier); | |
1985 continue; | |
1986 } | |
1987 } else if (optional("external", token)) { | |
1988 externalModifier = token; | |
1989 } else if (optional("static", token)) { | |
1990 staticModifier = token; | |
1991 } else if (optional("covariant", token)) { | |
1992 if (staticModifier != null || | |
1993 getOrSet == null || | |
1994 optional("get", getOrSet)) { | |
1995 reportRecoverableErrorCodeWithToken( | |
1996 token, codeExtraneousModifier); | |
1997 continue; | |
1998 } | |
1999 } | |
2000 } else { | |
2001 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); | |
2002 continue; | |
2003 } | |
2004 } else { | |
2005 reportUnexpectedToken(token); | |
2006 break; // Skip the remaining modifiers. | |
1999 } | 2007 } |
2000 } else if (constModifier == null && optional('const', modifier)) { | 2008 parseModifier(token); |
2001 modifierCount++; | 2009 count++; |
2002 constModifier = modifier; | |
2003 if (modifierCount != allowedModifierCount) { | |
2004 reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier); | |
2005 } | |
2006 } else { | |
2007 reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier); | |
2008 } | 2010 } |
2011 listener.handleModifiers(count); | |
2009 } | 2012 } |
2010 if (getOrSet != null && constModifier != null) { | 2013 |
2011 reportRecoverableErrorCodeWithToken( | |
2012 constModifier, codeExtraneousModifier); | |
2013 } | |
2014 parseModifierList(modifiers); | 2014 parseModifierList(modifiers); |
2015 | 2015 |
2016 if (type == null) { | 2016 if (type == null) { |
2017 listener.handleNoType(name); | 2017 listener.handleNoType(name); |
2018 } else { | 2018 } else { |
2019 parseReturnTypeOpt(type); | 2019 parseReturnTypeOpt(type); |
2020 } | 2020 } |
2021 Token token; | 2021 Token token; |
2022 if (optional('operator', name)) { | 2022 if (optional('operator', name)) { |
2023 token = parseOperatorName(name); | 2023 token = parseOperatorName(name); |
2024 if (staticModifier != null) { | 2024 if (staticModifier != null) { |
2025 reportRecoverableErrorCodeWithToken( | 2025 reportRecoverableErrorCodeWithToken( |
2026 staticModifier, codeExtraneousModifier); | 2026 staticModifier, codeExtraneousModifier); |
2027 } | 2027 } |
2028 } else { | 2028 } else { |
2029 token = parseIdentifier(name, IdentifierContext.methodDeclaration); | 2029 token = parseIdentifier(name, IdentifierContext.methodDeclaration); |
2030 } | 2030 } |
2031 | 2031 |
2032 token = parseQualifiedRestOpt( | 2032 token = parseQualifiedRestOpt( |
2033 token, IdentifierContext.methodDeclarationContinuation); | 2033 token, IdentifierContext.methodDeclarationContinuation); |
2034 if (getOrSet == null) { | 2034 if (getOrSet == null) { |
2035 token = parseTypeVariablesOpt(token); | 2035 token = parseTypeVariablesOpt(token); |
2036 } else { | 2036 } else { |
2037 listener.handleNoTypeVariables(token); | 2037 listener.handleNoTypeVariables(token); |
2038 } | 2038 } |
2039 token = parseFormalParametersOpt(token); | 2039 token = parseFormalParametersOpt( |
2040 token, | |
2041 staticModifier != null | |
2042 ? MemberKind.StaticMethod | |
2043 : MemberKind.NonStaticMethod); | |
2040 token = parseInitializersOpt(token); | 2044 token = parseInitializersOpt(token); |
2041 AsyncModifier savedAsyncModifier = asyncState; | 2045 AsyncModifier savedAsyncModifier = asyncState; |
2042 Token asyncToken = token; | 2046 Token asyncToken = token; |
2043 token = parseAsyncModifier(token); | 2047 token = parseAsyncModifier(token); |
2044 if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) { | 2048 if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) { |
2045 reportRecoverableErrorCode(asyncToken, codeSetterNotSync); | 2049 reportRecoverableErrorCode(asyncToken, codeSetterNotSync); |
2046 } | 2050 } |
2047 if (optional('=', token)) { | 2051 if (optional('=', token)) { |
2048 token = parseRedirectingFactoryBody(token); | 2052 token = parseRedirectingFactoryBody(token); |
2049 } else { | 2053 } else { |
(...skipping 15 matching lines...) Expand all Loading... | |
2065 isExternal = true; | 2069 isExternal = true; |
2066 } | 2070 } |
2067 token = parseModifier(token); | 2071 token = parseModifier(token); |
2068 modifierCount++; | 2072 modifierCount++; |
2069 } | 2073 } |
2070 listener.handleModifiers(modifierCount); | 2074 listener.handleModifiers(modifierCount); |
2071 Token factoryKeyword = token; | 2075 Token factoryKeyword = token; |
2072 listener.beginFactoryMethod(factoryKeyword); | 2076 listener.beginFactoryMethod(factoryKeyword); |
2073 token = expect('factory', token); | 2077 token = expect('factory', token); |
2074 token = parseConstructorReference(token); | 2078 token = parseConstructorReference(token); |
2075 token = parseFormalParameters(token); | 2079 token = parseFormalParameters(token, MemberKind.Factory); |
2076 Token asyncToken = token; | 2080 Token asyncToken = token; |
2077 token = parseAsyncModifier(token); | 2081 token = parseAsyncModifier(token); |
2078 if (!inPlainSync) { | 2082 if (!inPlainSync) { |
2079 reportRecoverableErrorCode(asyncToken, codeFactoryNotSync); | 2083 reportRecoverableErrorCode(asyncToken, codeFactoryNotSync); |
2080 } | 2084 } |
2081 if (optional('=', token)) { | 2085 if (optional('=', token)) { |
2082 token = parseRedirectingFactoryBody(token); | 2086 token = parseRedirectingFactoryBody(token); |
2083 } else { | 2087 } else { |
2084 token = parseFunctionBody(token, false, isExternal); | 2088 token = parseFunctionBody(token, false, isExternal); |
2085 } | 2089 } |
2086 listener.endFactoryMethod(start, factoryKeyword, token); | 2090 listener.endFactoryMethod(start, factoryKeyword, token); |
2087 return token.next; | 2091 return token.next; |
2088 } | 2092 } |
2089 | 2093 |
2090 Token parseOperatorName(Token token) { | 2094 Token parseOperatorName(Token token) { |
2091 assert(optional('operator', token)); | 2095 assert(optional('operator', token)); |
2092 if (isUserDefinableOperator(token.next.stringValue)) { | 2096 if (isUserDefinableOperator(token.next.stringValue)) { |
2093 Token operator = token; | 2097 Token operator = token; |
2094 token = token.next; | 2098 token = token.next; |
2095 listener.handleOperatorName(operator, token); | 2099 listener.handleOperatorName(operator, token); |
2096 return token.next; | 2100 return token.next; |
2097 } else { | 2101 } else { |
2098 return parseIdentifier(token, IdentifierContext.operatorName); | 2102 return parseIdentifier(token, IdentifierContext.operatorName); |
2099 } | 2103 } |
2100 } | 2104 } |
2101 | 2105 |
2102 Token parseFunction(Token token, Token getOrSet) { | 2106 Token parseFunction(Token token) { |
2103 Token beginToken = token; | 2107 Token beginToken = token; |
2104 listener.beginFunction(token); | 2108 listener.beginFunction(token); |
2105 token = parseModifiers(token); | 2109 token = parseModifiers(token, MemberKind.Local); |
2106 if (identical(getOrSet, token)) { | 2110 listener.beginFunctionName(token); |
2107 // get <name> => ... | 2111 token = parseIdentifier(token, IdentifierContext.localFunctionDeclaration); |
2108 token = token.next; | |
2109 listener.handleNoType(token); | |
2110 listener.beginFunctionName(token); | |
2111 if (optional('operator', token)) { | |
2112 token = parseOperatorName(token); | |
2113 } else { | |
2114 token = | |
2115 parseIdentifier(token, IdentifierContext.localAccessorDeclaration); | |
2116 } | |
2117 } else if (optional('operator', token)) { | |
2118 // operator <op> (... | |
2119 listener.handleNoType(token); | |
2120 listener.beginFunctionName(token); | |
2121 token = parseOperatorName(token); | |
2122 } else { | |
2123 // <type>? <get>? <name> | |
2124 token = parseReturnTypeOpt(token); | |
2125 if (identical(getOrSet, token)) { | |
2126 token = token.next; | |
2127 } | |
2128 listener.beginFunctionName(token); | |
2129 if (optional('operator', token)) { | |
2130 token = parseOperatorName(token); | |
2131 } else { | |
2132 token = | |
2133 parseIdentifier(token, IdentifierContext.localFunctionDeclaration); | |
2134 } | |
2135 } | |
2136 token = parseQualifiedRestOpt( | 2112 token = parseQualifiedRestOpt( |
2137 token, IdentifierContext.localFunctionDeclarationContinuation); | 2113 token, IdentifierContext.localFunctionDeclarationContinuation); |
2138 listener.endFunctionName(beginToken, token); | 2114 listener.endFunctionName(beginToken, token); |
2139 if (getOrSet == null) { | 2115 token = parseTypeVariablesOpt(token); |
2140 token = parseTypeVariablesOpt(token); | 2116 token = parseFormalParametersOpt(token, MemberKind.Local); |
2141 } else { | |
2142 listener.handleNoTypeVariables(token); | |
2143 } | |
2144 token = parseFormalParametersOpt(token); | |
2145 token = parseInitializersOpt(token); | 2117 token = parseInitializersOpt(token); |
2146 AsyncModifier savedAsyncModifier = asyncState; | 2118 AsyncModifier savedAsyncModifier = asyncState; |
2147 token = parseAsyncModifier(token); | 2119 token = parseAsyncModifier(token); |
2148 token = parseFunctionBody(token, false, true); | 2120 token = parseFunctionBody(token, false, true); |
2149 asyncState = savedAsyncModifier; | 2121 asyncState = savedAsyncModifier; |
2150 listener.endFunction(getOrSet, token); | 2122 listener.endFunction(null, token); |
2151 return token.next; | 2123 return token.next; |
2152 } | 2124 } |
2153 | 2125 |
2154 Token parseUnnamedFunction(Token token) { | 2126 Token parseUnnamedFunction(Token token) { |
2155 Token beginToken = token; | 2127 Token beginToken = token; |
2156 listener.beginUnnamedFunction(token); | 2128 listener.beginUnnamedFunction(token); |
2157 token = parseFormalParameters(token); | 2129 token = parseFormalParameters(token, MemberKind.Local); |
2158 AsyncModifier savedAsyncModifier = asyncState; | 2130 AsyncModifier savedAsyncModifier = asyncState; |
2159 token = parseAsyncModifier(token); | 2131 token = parseAsyncModifier(token); |
2160 bool isBlock = optional('{', token); | 2132 bool isBlock = optional('{', token); |
2161 token = parseFunctionBody(token, true, false); | 2133 token = parseFunctionBody(token, true, false); |
2162 asyncState = savedAsyncModifier; | 2134 asyncState = savedAsyncModifier; |
2163 listener.endUnnamedFunction(beginToken, token); | 2135 listener.endUnnamedFunction(beginToken, token); |
2164 return isBlock ? token.next : token; | 2136 return isBlock ? token.next : token; |
2165 } | 2137 } |
2166 | 2138 |
2167 Token parseFunctionDeclaration(Token token) { | 2139 Token parseFunctionDeclaration(Token token) { |
2168 listener.beginFunctionDeclaration(token); | 2140 listener.beginFunctionDeclaration(token); |
2169 token = parseFunction(token, null); | 2141 token = parseFunction(token); |
2170 listener.endFunctionDeclaration(token); | 2142 listener.endFunctionDeclaration(token); |
2171 return token; | 2143 return token; |
2172 } | 2144 } |
2173 | 2145 |
2174 Token parseFunctionExpression(Token token) { | 2146 Token parseFunctionExpression(Token token) { |
2175 Token beginToken = token; | 2147 Token beginToken = token; |
2176 listener.beginFunction(token); | 2148 listener.beginFunction(token); |
2177 listener.handleModifiers(0); | 2149 listener.handleModifiers(0); |
2178 token = parseReturnTypeOpt(token); | 2150 token = parseReturnTypeOpt(token); |
2179 listener.beginFunctionName(token); | 2151 listener.beginFunctionName(token); |
2180 token = parseIdentifier(token, IdentifierContext.functionExpressionName); | 2152 token = parseIdentifier(token, IdentifierContext.functionExpressionName); |
2181 listener.endFunctionName(beginToken, token); | 2153 listener.endFunctionName(beginToken, token); |
2182 token = parseTypeVariablesOpt(token); | 2154 token = parseTypeVariablesOpt(token); |
2183 token = parseFormalParameters(token); | 2155 token = parseFormalParameters(token, MemberKind.Local); |
2184 listener.handleNoInitializers(); | 2156 listener.handleNoInitializers(); |
2185 AsyncModifier savedAsyncModifier = asyncState; | 2157 AsyncModifier savedAsyncModifier = asyncState; |
2186 token = parseAsyncModifier(token); | 2158 token = parseAsyncModifier(token); |
2187 bool isBlock = optional('{', token); | 2159 bool isBlock = optional('{', token); |
2188 token = parseFunctionBody(token, true, false); | 2160 token = parseFunctionBody(token, true, false); |
2189 asyncState = savedAsyncModifier; | 2161 asyncState = savedAsyncModifier; |
2190 listener.endFunction(null, token); | 2162 listener.endFunction(null, token); |
2191 return isBlock ? token.next : token; | 2163 return isBlock ? token.next : token; |
2192 } | 2164 } |
2193 | 2165 |
(...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3413 return parseVariablesDeclarationMaybeSemicolon(token, false); | 3385 return parseVariablesDeclarationMaybeSemicolon(token, false); |
3414 } | 3386 } |
3415 | 3387 |
3416 Token parseVariablesDeclarationMaybeSemicolon( | 3388 Token parseVariablesDeclarationMaybeSemicolon( |
3417 Token token, bool endWithSemicolon) { | 3389 Token token, bool endWithSemicolon) { |
3418 int count = 1; | 3390 int count = 1; |
3419 token = parseMetadataStar(token); | 3391 token = parseMetadataStar(token); |
3420 | 3392 |
3421 // If the next token has a type substitution comment /*=T*/, then | 3393 // If the next token has a type substitution comment /*=T*/, then |
3422 // the current 'var' token should be repealed and replaced. | 3394 // the current 'var' token should be repealed and replaced. |
3423 if (identical('var', token.stringValue)) { | 3395 if (optional('var', token)) { |
3424 token = | 3396 token = |
3425 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next); | 3397 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next); |
3426 } | 3398 } |
3427 | 3399 |
3428 token = parseModifiers(token); | 3400 token = parseModifiers(token, MemberKind.Local, isVariable: true); |
3429 token = parseTypeOpt(token); | |
3430 listener.beginVariablesDeclaration(token); | 3401 listener.beginVariablesDeclaration(token); |
3431 token = parseOptionallyInitializedIdentifier(token); | 3402 token = parseOptionallyInitializedIdentifier(token); |
3432 while (optional(',', token)) { | 3403 while (optional(',', token)) { |
3433 token = parseOptionallyInitializedIdentifier(token.next); | 3404 token = parseOptionallyInitializedIdentifier(token.next); |
3434 ++count; | 3405 ++count; |
3435 } | 3406 } |
3436 if (endWithSemicolon) { | 3407 if (endWithSemicolon) { |
3437 Token semicolon = token; | 3408 Token semicolon = token; |
3438 token = expectSemicolon(semicolon); | 3409 token = expectSemicolon(semicolon); |
3439 listener.endVariablesDeclaration(count, semicolon); | 3410 listener.endVariablesDeclaration(count, semicolon); |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3641 if (identical(value, 'on')) { | 3612 if (identical(value, 'on')) { |
3642 // on qualified catchPart? | 3613 // on qualified catchPart? |
3643 onKeyword = token; | 3614 onKeyword = token; |
3644 token = parseType(token.next); | 3615 token = parseType(token.next); |
3645 value = token.stringValue; | 3616 value = token.stringValue; |
3646 } | 3617 } |
3647 Token catchKeyword = null; | 3618 Token catchKeyword = null; |
3648 if (identical(value, 'catch')) { | 3619 if (identical(value, 'catch')) { |
3649 catchKeyword = token; | 3620 catchKeyword = token; |
3650 // TODO(ahe): Validate the "parameters". | 3621 // TODO(ahe): Validate the "parameters". |
3651 token = parseFormalParameters(token.next); | 3622 token = parseFormalParameters(token.next, MemberKind.Catch); |
3652 } | 3623 } |
3653 listener.endCatchClause(token); | 3624 listener.endCatchClause(token); |
3654 token = parseBlock(token); | 3625 token = parseBlock(token); |
3655 ++catchCount; | 3626 ++catchCount; |
3656 listener.handleCatchBlock(onKeyword, catchKeyword); | 3627 listener.handleCatchBlock(onKeyword, catchKeyword); |
3657 value = token.stringValue; // while condition | 3628 value = token.stringValue; // while condition |
3658 } | 3629 } |
3659 | 3630 |
3660 Token finallyKeyword = null; | 3631 Token finallyKeyword = null; |
3661 if (optional('finally', token)) { | 3632 if (optional('finally', token)) { |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3917 return reportUnrecoverableError( | 3888 return reportUnrecoverableError( |
3918 token, () => code.format(uri, token.charOffset, string)); | 3889 token, () => code.format(uri, token.charOffset, string)); |
3919 } | 3890 } |
3920 } | 3891 } |
3921 | 3892 |
3922 typedef FastaMessage NoArgument(Uri uri, int charOffset); | 3893 typedef FastaMessage NoArgument(Uri uri, int charOffset); |
3923 | 3894 |
3924 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); | 3895 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); |
3925 | 3896 |
3926 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); | 3897 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); |
OLD | NEW |