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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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); |
OLD | NEW |