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

Side by Side Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 2951463002: Refactor parseType in preparation for bigger changes. (Closed)
Patch Set: Created 3 years, 6 months 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
« no previous file with comments | « no previous file | pkg/kernel/lib/text/ast_to_text.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 /// the prefix `skip`. 194 /// the prefix `skip`.
195 /// 195 ///
196 /// Parse methods generate events (by calling methods on [listener]) and return 196 /// Parse methods generate events (by calling methods on [listener]) and return
197 /// the next token to parse. Peek methods do not generate events (except for 197 /// the next token to parse. Peek methods do not generate events (except for
198 /// errors) and may return null. Skip methods are like parse methods, but skip 198 /// errors) and may return null. Skip methods are like parse methods, but skip
199 /// over some parts of the file being parsed. 199 /// over some parts of the file being parsed.
200 /// 200 ///
201 /// Parse methods are generally named `parseGrammarProductionSuffix`. The 201 /// Parse methods are generally named `parseGrammarProductionSuffix`. The
202 /// suffix can be one of `opt`, or `star`. `opt` means zero or one matches, 202 /// suffix can be one of `opt`, or `star`. `opt` means zero or one matches,
203 /// `star` means zero or more matches. For example, [parseMetadataStar] 203 /// `star` means zero or more matches. For example, [parseMetadataStar]
204 /// corresponds to this grammar snippet: `metadata*`, and [parseTypeOpt] 204 /// corresponds to this grammar snippet: `metadata*`, and [parseArgumentsOpt]
205 /// corresponds to: `type?`. 205 /// corresponds to: `arguments?`.
206 /// 206 ///
207 /// ## Implementation Notes 207 /// ## Implementation Notes
208 /// 208 ///
209 /// The parser assumes that keywords, built-in identifiers, and other special 209 /// The parser assumes that keywords, built-in identifiers, and other special
210 /// words (pseudo-keywords) are all canonicalized. To extend the parser to 210 /// words (pseudo-keywords) are all canonicalized. To extend the parser to
211 /// recognize a new identifier, one should modify 211 /// recognize a new identifier, one should modify
212 /// [keyword.dart](../scanner/keyword.dart) and ensure the identifier is added 212 /// [keyword.dart](../scanner/keyword.dart) and ensure the identifier is added
213 /// to the keyword table. 213 /// to the keyword table.
214 /// 214 ///
215 /// As a consequence of this, one should not use `==` to compare strings in the 215 /// As a consequence of this, one should not use `==` to compare strings in the
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 Token typedefKeyword = token; 615 Token typedefKeyword = token;
616 listener.beginFunctionTypeAlias(token); 616 listener.beginFunctionTypeAlias(token);
617 Token equals; 617 Token equals;
618 if (optional('=', peekAfterNominalType(token.next))) { 618 if (optional('=', peekAfterNominalType(token.next))) {
619 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); 619 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration);
620 token = parseTypeVariablesOpt(token); 620 token = parseTypeVariablesOpt(token);
621 equals = token; 621 equals = token;
622 token = expect('=', token); 622 token = expect('=', token);
623 token = parseType(token); 623 token = parseType(token);
624 } else { 624 } else {
625 token = parseReturnTypeOpt(token.next); 625 token = parseType(token.next, isOptional: true);
626 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); 626 token = parseIdentifier(token, IdentifierContext.typedefDeclaration);
627 token = parseTypeVariablesOpt(token); 627 token = parseTypeVariablesOpt(token);
628 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); 628 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias);
629 } 629 }
630 listener.endFunctionTypeAlias(typedefKeyword, equals, token); 630 listener.endFunctionTypeAlias(typedefKeyword, equals, token);
631 return expect(';', token); 631 return expect(';', token);
632 } 632 }
633 633
634 Token parseMixinApplication(Token token) { 634 Token parseMixinApplication(Token token) {
635 listener.beginMixinApplication(token); 635 listener.beginMixinApplication(token);
636 token = parseType(token); 636 token = parseType(token);
637 Token withKeyword = token; 637 Token withKeyword = token;
638 token = expect('with', token); 638 token = expect('with', token);
639 token = parseTypeList(token); 639 token = parseTypeList(token);
640 listener.endMixinApplication(withKeyword); 640 listener.endMixinApplication(withKeyword);
641 return token; 641 return token;
642 } 642 }
643 643
644 Token parseReturnTypeOpt(Token token) {
645 if (identical(token.stringValue, 'void')) {
646 if (isGeneralizedFunctionType(token.next)) {
647 return parseType(token);
648 } else {
649 listener.handleVoidKeyword(token);
650 return token.next;
651 }
652 } else {
653 return parseTypeOpt(token);
654 }
655 }
656
657 Token parseFormalParametersOpt(Token token, MemberKind kind) { 644 Token parseFormalParametersOpt(Token token, MemberKind kind) {
658 if (optional('(', token)) { 645 if (optional('(', token)) {
659 return parseFormalParameters(token, kind); 646 return parseFormalParameters(token, kind);
660 } else { 647 } else {
661 listener.handleNoFormalParameters(token, kind); 648 listener.handleNoFormalParameters(token, kind);
662 return token; 649 return token;
663 } 650 }
664 } 651 }
665 652
666 Token skipFormalParameters(Token token, MemberKind kind) { 653 Token skipFormalParameters(Token token, MemberKind kind) {
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
826 : codeEmptyOptionalParameterList); 813 : codeEmptyOptionalParameterList);
827 } 814 }
828 listener.endOptionalFormalParameters(parameterCount, begin, token); 815 listener.endOptionalFormalParameters(parameterCount, begin, token);
829 if (isNamed) { 816 if (isNamed) {
830 return expect('}', token); 817 return expect('}', token);
831 } else { 818 } else {
832 return expect(']', token); 819 return expect(']', token);
833 } 820 }
834 } 821 }
835 822
836 Token parseTypeOpt(Token token) {
837 if (isGeneralizedFunctionType(token)) {
838 // Function type without return type.
839 return parseType(token);
840 }
841 token = listener.injectGenericCommentTypeAssign(token);
842 Token peek = peekAfterIfType(token);
843 if (peek != null && (peek.isIdentifier || optional('this', peek))) {
844 return parseType(token);
845 }
846 listener.handleNoType(token);
847 return token;
848 }
849
850 bool isValidTypeReference(Token token) { 823 bool isValidTypeReference(Token token) {
851 int kind = token.kind; 824 int kind = token.kind;
852 if (IDENTIFIER_TOKEN == kind) return true; 825 if (IDENTIFIER_TOKEN == kind) return true;
853 if (KEYWORD_TOKEN == kind) { 826 if (KEYWORD_TOKEN == kind) {
854 String value = token.type.lexeme; 827 String value = token.type.lexeme;
855 return token.type.isPseudo || 828 return token.type.isPseudo ||
856 (identical(value, 'dynamic')) || 829 (identical(value, 'dynamic')) ||
857 (identical(value, 'void')); 830 (identical(value, 'void'));
858 } 831 }
859 return false; 832 return false;
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
1159 bool notEofOrValue(String value, Token token) { 1132 bool notEofOrValue(String value, Token token) {
1160 return !identical(token.kind, EOF_TOKEN) && 1133 return !identical(token.kind, EOF_TOKEN) &&
1161 !identical(value, token.stringValue); 1134 !identical(value, token.stringValue);
1162 } 1135 }
1163 1136
1164 bool isGeneralizedFunctionType(Token token) { 1137 bool isGeneralizedFunctionType(Token token) {
1165 return optional('Function', token) && 1138 return optional('Function', token) &&
1166 (optional('<', token.next) || optional('(', token.next)); 1139 (optional('<', token.next) || optional('(', token.next));
1167 } 1140 }
1168 1141
1169 Token parseType(Token token) { 1142 Token parseType(Token token, {bool isOptional: false}) {
1143 if (isOptional) {
danrubel 2017/06/19 15:31:06 for better performance, should this block be place
ahe 2017/06/19 16:46:49 Great idea, but I have much bigger plans for this
1144 do {
1145 if (optional("void", token)) {
1146 if (isGeneralizedFunctionType(token.next)) {
1147 // This is a type, parse it.
1148 break;
1149 } else {
1150 listener.handleVoidKeyword(token);
1151 return token.next;
1152 }
1153 } else {
1154 if (isGeneralizedFunctionType(token)) {
1155 // Function type without return type, parse it.
1156 break;
1157 }
1158 token = listener.injectGenericCommentTypeAssign(token);
1159 Token peek = peekAfterIfType(token);
1160 if (peek != null && (peek.isIdentifier || optional('this', peek))) {
1161 // This is a type followed by an identifier, parse it.
1162 break;
1163 }
1164 listener.handleNoType(token);
1165 return token;
1166 }
1167 } while (false);
danrubel 2017/06/19 15:31:06 Why is all this in a do while(false)? It does not
ahe 2017/06/19 16:46:49 It was for the breaks. I agree it isn't nice, but
1168 }
1170 Token begin = token; 1169 Token begin = token;
1171 if (isGeneralizedFunctionType(token)) { 1170 if (isGeneralizedFunctionType(token)) {
1172 // A function type without return type. 1171 // A function type without return type.
1173 // Push the non-existing return type first. The loop below will 1172 // Push the non-existing return type first. The loop below will
1174 // generate the full type. 1173 // generate the full type.
1175 listener.handleNoType(token); 1174 listener.handleNoType(token);
1176 } else if (optional("void", token) && 1175 } else if (optional("void", token) &&
1177 isGeneralizedFunctionType(token.next)) { 1176 isGeneralizedFunctionType(token.next)) {
1178 listener.handleVoidKeyword(token); 1177 listener.handleVoidKeyword(token);
1179 token = token.next; 1178 token = token.next;
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
1393 if (externalModifier != null) { 1392 if (externalModifier != null) {
1394 parseModifier(externalModifier); 1393 parseModifier(externalModifier);
1395 listener.handleModifiers(1); 1394 listener.handleModifiers(1);
1396 } else { 1395 } else {
1397 listener.handleModifiers(0); 1396 listener.handleModifiers(0);
1398 } 1397 }
1399 1398
1400 if (type == null) { 1399 if (type == null) {
1401 listener.handleNoType(name); 1400 listener.handleNoType(name);
1402 } else { 1401 } else {
1403 parseReturnTypeOpt(type); 1402 parseType(type, isOptional: true);
1404 } 1403 }
1405 Token token = 1404 Token token =
1406 parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); 1405 parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration);
1407 1406
1408 bool isGetter = false; 1407 bool isGetter = false;
1409 if (getOrSet == null) { 1408 if (getOrSet == null) {
1410 token = parseTypeVariablesOpt(token); 1409 token = parseTypeVariablesOpt(token);
1411 } else { 1410 } else {
1412 isGetter = optional("get", getOrSet); 1411 isGetter = optional("get", getOrSet);
1413 listener.handleNoTypeVariables(token); 1412 listener.handleNoTypeVariables(token);
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
1793 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); 1792 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier);
1794 token = token.next; 1793 token = token.next;
1795 } 1794 }
1796 } else { 1795 } else {
1797 break; 1796 break;
1798 } 1797 }
1799 } 1798 }
1800 listener.handleModifiers(count); 1799 listener.handleModifiers(count);
1801 1800
1802 Token beforeType = token; 1801 Token beforeType = token;
1803 if (returnTypeAllowed) { 1802 token = parseType(token, isOptional: returnTypeAllowed || !typeRequired);
1804 token = parseReturnTypeOpt(token);
1805 } else {
1806 token = typeRequired ? parseType(token) : parseTypeOpt(token);
1807 }
1808 if (typeRequired && beforeType == token) { 1803 if (typeRequired && beforeType == token) {
1809 reportRecoverableErrorCode(token, codeTypeRequired); 1804 reportRecoverableErrorCode(token, codeTypeRequired);
1810 } 1805 }
1811 if (hasVar && beforeType != token) { 1806 if (hasVar && beforeType != token) {
1812 reportRecoverableErrorCode(beforeType, codeTypeAfterVar); 1807 reportRecoverableErrorCode(beforeType, codeTypeAfterVar);
1813 } 1808 }
1814 return token; 1809 return token;
1815 } 1810 }
1816 1811
1817 /// Returns the first token after the type starting at [token]. 1812 /// Returns the first token after the type starting at [token].
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
2102 count++; 2097 count++;
2103 } 2098 }
2104 listener.handleModifiers(count); 2099 listener.handleModifiers(count);
2105 } 2100 }
2106 2101
2107 parseModifierList(modifiers); 2102 parseModifierList(modifiers);
2108 2103
2109 if (type == null) { 2104 if (type == null) {
2110 listener.handleNoType(name); 2105 listener.handleNoType(name);
2111 } else { 2106 } else {
2112 parseReturnTypeOpt(type); 2107 parseType(type, isOptional: true);
2113 } 2108 }
2114 Token token; 2109 Token token;
2115 if (optional('operator', name)) { 2110 if (optional('operator', name)) {
2116 token = parseOperatorName(name); 2111 token = parseOperatorName(name);
2117 if (staticModifier != null) { 2112 if (staticModifier != null) {
2118 reportRecoverableErrorCodeWithToken( 2113 reportRecoverableErrorCodeWithToken(
2119 staticModifier, codeExtraneousModifier); 2114 staticModifier, codeExtraneousModifier);
2120 } 2115 }
2121 } else { 2116 } else {
2122 token = parseIdentifier(name, IdentifierContext.methodDeclaration); 2117 token = parseIdentifier(name, IdentifierContext.methodDeclaration);
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
2236 listener.beginFunctionDeclaration(token); 2231 listener.beginFunctionDeclaration(token);
2237 token = parseFunction(token); 2232 token = parseFunction(token);
2238 listener.endFunctionDeclaration(token); 2233 listener.endFunctionDeclaration(token);
2239 return token; 2234 return token;
2240 } 2235 }
2241 2236
2242 Token parseFunctionExpression(Token token) { 2237 Token parseFunctionExpression(Token token) {
2243 Token beginToken = token; 2238 Token beginToken = token;
2244 listener.beginFunction(token); 2239 listener.beginFunction(token);
2245 listener.handleModifiers(0); 2240 listener.handleModifiers(0);
2246 token = parseReturnTypeOpt(token); 2241 token = parseType(token, isOptional: true);
2247 listener.beginFunctionName(token); 2242 listener.beginFunctionName(token);
2248 token = parseIdentifier(token, IdentifierContext.functionExpressionName); 2243 token = parseIdentifier(token, IdentifierContext.functionExpressionName);
2249 listener.endFunctionName(beginToken, token); 2244 listener.endFunctionName(beginToken, token);
2250 token = parseTypeVariablesOpt(token); 2245 token = parseTypeVariablesOpt(token);
2251 token = parseFormalParameters(token, MemberKind.Local); 2246 token = parseFormalParameters(token, MemberKind.Local);
2252 listener.handleNoInitializers(); 2247 listener.handleNoInitializers();
2253 AsyncModifier savedAsyncModifier = asyncState; 2248 AsyncModifier savedAsyncModifier = asyncState;
2254 token = parseAsyncModifier(token); 2249 token = parseAsyncModifier(token);
2255 bool isBlock = optional('{', token); 2250 bool isBlock = optional('{', token);
2256 token = parseFunctionBody(token, true, false); 2251 token = parseFunctionBody(token, true, false);
(...skipping 1773 matching lines...) Expand 10 before | Expand all | Expand 10 after
4030 return reportUnrecoverableError( 4025 return reportUnrecoverableError(
4031 token, () => code.format(uri, token.charOffset, string)); 4026 token, () => code.format(uri, token.charOffset, string));
4032 } 4027 }
4033 } 4028 }
4034 4029
4035 typedef FastaMessage NoArgument(Uri uri, int charOffset); 4030 typedef FastaMessage NoArgument(Uri uri, int charOffset);
4036 4031
4037 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); 4032 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token);
4038 4033
4039 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); 4034 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string);
OLDNEW
« no previous file with comments | « no previous file | pkg/kernel/lib/text/ast_to_text.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698