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 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 /// | 173 /// |
174 /// An assertion can legally occur as a statement. However, assertions are also | 174 /// An assertion can legally occur as a statement. However, assertions are also |
175 /// experimentally allowed in initializers. For improved error recovery, we | 175 /// experimentally allowed in initializers. For improved error recovery, we |
176 /// also attempt to parse asserts as expressions. | 176 /// also attempt to parse asserts as expressions. |
177 enum Assert { | 177 enum Assert { |
178 Expression, | 178 Expression, |
179 Initializer, | 179 Initializer, |
180 Statement, | 180 Statement, |
181 } | 181 } |
182 | 182 |
| 183 /// Indication of how the parser should continue after (attempting) to parse a |
| 184 /// type. |
| 185 /// |
| 186 /// Depending on the continuation, the parser may not parse a type at all. |
| 187 enum TypeContinuation { |
| 188 /// Indicates that a type is unconditionally expected. |
| 189 Required, |
| 190 |
| 191 /// Indicates that a type may follow. If the following matches one of these |
| 192 /// productions, it is parsed as a type: |
| 193 /// |
| 194 /// - `'void'` |
| 195 /// - `'Function' ( '(' | '<' )` |
| 196 /// - `identifier ('.' identifier)? ('<' ... '>')? identifer` |
| 197 /// |
| 198 /// Otherwise, do nothing. |
| 199 Optional, |
| 200 |
| 201 /// Indicates that the keyword `typedef` has just been seen, and the parser |
| 202 /// should parse the following as a type unless it is followed by `=`. |
| 203 Typedef, |
| 204 } |
| 205 |
183 /// An event generating parser of Dart programs. This parser expects all tokens | 206 /// An event generating parser of Dart programs. This parser expects all tokens |
184 /// in a linked list (aka a token stream). | 207 /// in a linked list (aka a token stream). |
185 /// | 208 /// |
186 /// The class [Scanner] is used to generate a token stream. See the file | 209 /// The class [Scanner] is used to generate a token stream. See the file |
187 /// [scanner.dart](../scanner.dart). | 210 /// [scanner.dart](../scanner.dart). |
188 /// | 211 /// |
189 /// Subclasses of the class [Listener] are used to listen to events. | 212 /// Subclasses of the class [Listener] are used to listen to events. |
190 /// | 213 /// |
191 /// Most methods of this class belong in one of three major categories: parse | 214 /// Most methods of this class belong in one of three major categories: parse |
192 /// methods, peek methods, and skip methods. Parse methods all have the prefix | 215 /// methods, peek methods, and skip methods. Parse methods all have the prefix |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 | 631 |
609 Token parseScript(Token token) { | 632 Token parseScript(Token token) { |
610 listener.handleScript(token); | 633 listener.handleScript(token); |
611 return token.next; | 634 return token.next; |
612 } | 635 } |
613 | 636 |
614 Token parseTypedef(Token token) { | 637 Token parseTypedef(Token token) { |
615 Token typedefKeyword = token; | 638 Token typedefKeyword = token; |
616 listener.beginFunctionTypeAlias(token); | 639 listener.beginFunctionTypeAlias(token); |
617 Token equals; | 640 Token equals; |
618 if (optional('=', peekAfterNominalType(token.next))) { | 641 Token afterType = parseType(token.next, TypeContinuation.Typedef); |
| 642 if (afterType == null) { |
619 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); | 643 token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); |
620 token = parseTypeVariablesOpt(token); | 644 token = parseTypeVariablesOpt(token); |
621 equals = token; | 645 equals = token; |
622 token = expect('=', token); | 646 token = expect('=', token); |
623 token = parseType(token); | 647 token = parseType(token); |
624 } else { | 648 } else { |
625 token = parseType(token.next, isOptional: true); | 649 token = afterType; |
626 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); | 650 token = parseIdentifier(token, IdentifierContext.typedefDeclaration); |
627 token = parseTypeVariablesOpt(token); | 651 token = parseTypeVariablesOpt(token); |
628 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); | 652 token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); |
629 } | 653 } |
630 listener.endFunctionTypeAlias(typedefKeyword, equals, token); | 654 listener.endFunctionTypeAlias(typedefKeyword, equals, token); |
631 return expect(';', token); | 655 return expect(';', token); |
632 } | 656 } |
633 | 657 |
634 Token parseMixinApplication(Token token) { | 658 Token parseMixinApplication(Token token) { |
635 listener.beginMixinApplication(token); | 659 listener.beginMixinApplication(token); |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 count++; | 985 count++; |
962 } | 986 } |
963 } | 987 } |
964 Token endBrace = token; | 988 Token endBrace = token; |
965 token = expect('}', token); | 989 token = expect('}', token); |
966 listener.endEnum(enumKeyword, endBrace, count); | 990 listener.endEnum(enumKeyword, endBrace, count); |
967 return token; | 991 return token; |
968 } | 992 } |
969 | 993 |
970 Token parseClassOrNamedMixinApplication(Token token) { | 994 Token parseClassOrNamedMixinApplication(Token token) { |
| 995 listener.beginClassOrNamedMixinApplication(token); |
971 Token begin = token; | 996 Token begin = token; |
972 Token abstractKeyword; | 997 if (optional('abstract', token)) { |
| 998 token = parseModifier(token); |
| 999 listener.handleModifiers(1); |
| 1000 } else { |
| 1001 listener.handleModifiers(0); |
| 1002 } |
973 Token classKeyword = token; | 1003 Token classKeyword = token; |
974 if (optional('abstract', token)) { | 1004 token = expect("class", token); |
975 abstractKeyword = token; | 1005 Token name = token; |
976 token = token.next; | 1006 token = |
977 classKeyword = token; | 1007 parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); |
978 } | 1008 token = parseTypeVariablesOpt(token); |
979 assert(optional('class', classKeyword)); | 1009 if (optional('=', token)) { |
980 int modifierCount = 0; | |
981 if (abstractKeyword != null) { | |
982 parseModifier(abstractKeyword); | |
983 modifierCount++; | |
984 } | |
985 listener.handleModifiers(modifierCount); | |
986 bool isMixinApplication = optional('=', peekAfterNominalType(token)); | |
987 Token name = token.next; | |
988 | |
989 if (isMixinApplication) { | |
990 token = parseIdentifier(name, IdentifierContext.namedMixinDeclaration); | |
991 listener.beginNamedMixinApplication(begin, name); | 1010 listener.beginNamedMixinApplication(begin, name); |
992 } else { | |
993 token = parseIdentifier(name, IdentifierContext.classDeclaration); | |
994 listener.beginClassDeclaration(begin, name); | |
995 } | |
996 | |
997 token = parseTypeVariablesOpt(token); | |
998 | |
999 if (optional('=', token)) { | |
1000 Token equals = token; | 1011 Token equals = token; |
1001 token = token.next; | 1012 token = token.next; |
1002 return parseNamedMixinApplication( | 1013 return parseNamedMixinApplication( |
1003 token, begin, classKeyword, name, equals); | 1014 token, begin, classKeyword, name, equals); |
1004 } else { | 1015 } else { |
| 1016 listener.beginClassDeclaration(begin, name); |
1005 return parseClass(token, begin, classKeyword, name); | 1017 return parseClass(token, begin, classKeyword, name); |
1006 } | 1018 } |
1007 } | 1019 } |
1008 | 1020 |
1009 Token parseNamedMixinApplication( | 1021 Token parseNamedMixinApplication( |
1010 Token token, Token begin, Token classKeyword, Token name, Token equals) { | 1022 Token token, Token begin, Token classKeyword, Token name, Token equals) { |
1011 token = parseMixinApplication(token); | 1023 token = parseMixinApplication(token); |
1012 Token implementsKeyword = null; | 1024 Token implementsKeyword = null; |
1013 if (optional('implements', token)) { | 1025 if (optional('implements', token)) { |
1014 implementsKeyword = token; | 1026 implementsKeyword = token; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1132 bool notEofOrValue(String value, Token token) { | 1144 bool notEofOrValue(String value, Token token) { |
1133 return !identical(token.kind, EOF_TOKEN) && | 1145 return !identical(token.kind, EOF_TOKEN) && |
1134 !identical(value, token.stringValue); | 1146 !identical(value, token.stringValue); |
1135 } | 1147 } |
1136 | 1148 |
1137 bool isGeneralizedFunctionType(Token token) { | 1149 bool isGeneralizedFunctionType(Token token) { |
1138 return optional('Function', token) && | 1150 return optional('Function', token) && |
1139 (optional('<', token.next) || optional('(', token.next)); | 1151 (optional('<', token.next) || optional('(', token.next)); |
1140 } | 1152 } |
1141 | 1153 |
1142 Token parseType(Token token, {bool isOptional: false}) { | 1154 /// Parse a type, if it is appropriate to do so. |
1143 if (isOptional) { | 1155 /// |
1144 do { | 1156 /// If this method can parse a type, it will return the next (non-null) token |
| 1157 /// after the type. Otherwise, it returns null. |
| 1158 Token parseType(Token token, |
| 1159 [TypeContinuation continuation = TypeContinuation.Required]) { |
| 1160 switch (continuation) { |
| 1161 case TypeContinuation.Typedef: |
| 1162 if (optional('=', peekAfterNominalType(token))) { |
| 1163 return null; // This isn't a type, it's a new-style typedef. |
| 1164 } |
| 1165 continue optional; |
| 1166 |
| 1167 optional: |
| 1168 case TypeContinuation.Optional: |
1145 if (optional("void", token)) { | 1169 if (optional("void", token)) { |
1146 if (isGeneralizedFunctionType(token.next)) { | 1170 if (isGeneralizedFunctionType(token.next)) { |
1147 // This is a type, parse it. | 1171 // This is a type, parse it. |
1148 break; | 1172 break; |
1149 } else { | 1173 } else { |
1150 listener.handleVoidKeyword(token); | 1174 listener.handleVoidKeyword(token); |
1151 return token.next; | 1175 return token.next; |
1152 } | 1176 } |
1153 } else { | 1177 } else { |
1154 if (isGeneralizedFunctionType(token)) { | 1178 if (isGeneralizedFunctionType(token)) { |
1155 // Function type without return type, parse it. | 1179 // Function type without return type, parse it. |
1156 break; | 1180 break; |
1157 } | 1181 } |
1158 token = listener.injectGenericCommentTypeAssign(token); | 1182 token = listener.injectGenericCommentTypeAssign(token); |
1159 Token peek = peekAfterIfType(token); | 1183 Token peek = peekAfterIfType(token); |
1160 if (peek != null && (peek.isIdentifier || optional('this', peek))) { | 1184 if (peek != null && (peek.isIdentifier || optional('this', peek))) { |
1161 // This is a type followed by an identifier, parse it. | 1185 // This is a type followed by an identifier, parse it. |
1162 break; | 1186 break; |
1163 } | 1187 } |
1164 listener.handleNoType(token); | 1188 listener.handleNoType(token); |
1165 return token; | 1189 return token; |
1166 } | 1190 } |
1167 } while (false); | 1191 break; |
| 1192 |
| 1193 case TypeContinuation.Required: |
| 1194 break; |
| 1195 |
| 1196 default: |
| 1197 throw "Internal error: Unhandled continuation '$continuation'."; |
1168 } | 1198 } |
1169 Token begin = token; | 1199 Token begin = token; |
1170 if (isGeneralizedFunctionType(token)) { | 1200 if (isGeneralizedFunctionType(token)) { |
1171 // A function type without return type. | 1201 // A function type without return type. |
1172 // Push the non-existing return type first. The loop below will | 1202 // Push the non-existing return type first. The loop below will |
1173 // generate the full type. | 1203 // generate the full type. |
1174 listener.handleNoType(token); | 1204 listener.handleNoType(token); |
1175 } else if (optional("void", token) && | 1205 } else if (optional("void", token) && |
1176 isGeneralizedFunctionType(token.next)) { | 1206 isGeneralizedFunctionType(token.next)) { |
1177 listener.handleVoidKeyword(token); | 1207 listener.handleVoidKeyword(token); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1392 if (externalModifier != null) { | 1422 if (externalModifier != null) { |
1393 parseModifier(externalModifier); | 1423 parseModifier(externalModifier); |
1394 listener.handleModifiers(1); | 1424 listener.handleModifiers(1); |
1395 } else { | 1425 } else { |
1396 listener.handleModifiers(0); | 1426 listener.handleModifiers(0); |
1397 } | 1427 } |
1398 | 1428 |
1399 if (type == null) { | 1429 if (type == null) { |
1400 listener.handleNoType(name); | 1430 listener.handleNoType(name); |
1401 } else { | 1431 } else { |
1402 parseType(type, isOptional: true); | 1432 parseType(type, TypeContinuation.Optional); |
1403 } | 1433 } |
1404 Token token = | 1434 Token token = |
1405 parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); | 1435 parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); |
1406 | 1436 |
1407 bool isGetter = false; | 1437 bool isGetter = false; |
1408 if (getOrSet == null) { | 1438 if (getOrSet == null) { |
1409 token = parseTypeVariablesOpt(token); | 1439 token = parseTypeVariablesOpt(token); |
1410 } else { | 1440 } else { |
1411 isGetter = optional("get", getOrSet); | 1441 isGetter = optional("get", getOrSet); |
1412 listener.handleNoTypeVariables(token); | 1442 listener.handleNoTypeVariables(token); |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1792 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); | 1822 reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier); |
1793 token = token.next; | 1823 token = token.next; |
1794 } | 1824 } |
1795 } else { | 1825 } else { |
1796 break; | 1826 break; |
1797 } | 1827 } |
1798 } | 1828 } |
1799 listener.handleModifiers(count); | 1829 listener.handleModifiers(count); |
1800 | 1830 |
1801 Token beforeType = token; | 1831 Token beforeType = token; |
1802 token = parseType(token, isOptional: returnTypeAllowed || !typeRequired); | 1832 token = parseType( |
| 1833 token, |
| 1834 returnTypeAllowed || !typeRequired |
| 1835 ? TypeContinuation.Optional |
| 1836 : TypeContinuation.Required); |
1803 if (typeRequired && beforeType == token) { | 1837 if (typeRequired && beforeType == token) { |
1804 reportRecoverableErrorCode(token, codeTypeRequired); | 1838 reportRecoverableErrorCode(token, codeTypeRequired); |
1805 } | 1839 } |
1806 if (hasVar && beforeType != token) { | 1840 if (hasVar && beforeType != token) { |
1807 reportRecoverableErrorCode(beforeType, codeTypeAfterVar); | 1841 reportRecoverableErrorCode(beforeType, codeTypeAfterVar); |
1808 } | 1842 } |
1809 return token; | 1843 return token; |
1810 } | 1844 } |
1811 | 1845 |
1812 /// Returns the first token after the type starting at [token]. | 1846 /// Returns the first token after the type starting at [token]. |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2097 count++; | 2131 count++; |
2098 } | 2132 } |
2099 listener.handleModifiers(count); | 2133 listener.handleModifiers(count); |
2100 } | 2134 } |
2101 | 2135 |
2102 parseModifierList(modifiers); | 2136 parseModifierList(modifiers); |
2103 | 2137 |
2104 if (type == null) { | 2138 if (type == null) { |
2105 listener.handleNoType(name); | 2139 listener.handleNoType(name); |
2106 } else { | 2140 } else { |
2107 parseType(type, isOptional: true); | 2141 parseType(type, TypeContinuation.Optional); |
2108 } | 2142 } |
2109 Token token; | 2143 Token token; |
2110 if (optional('operator', name)) { | 2144 if (optional('operator', name)) { |
2111 token = parseOperatorName(name); | 2145 token = parseOperatorName(name); |
2112 if (staticModifier != null) { | 2146 if (staticModifier != null) { |
2113 reportRecoverableErrorCodeWithToken( | 2147 reportRecoverableErrorCodeWithToken( |
2114 staticModifier, codeExtraneousModifier); | 2148 staticModifier, codeExtraneousModifier); |
2115 } | 2149 } |
2116 } else { | 2150 } else { |
2117 token = parseIdentifier(name, IdentifierContext.methodDeclaration); | 2151 token = parseIdentifier(name, IdentifierContext.methodDeclaration); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2231 listener.beginFunctionDeclaration(token); | 2265 listener.beginFunctionDeclaration(token); |
2232 token = parseFunction(token); | 2266 token = parseFunction(token); |
2233 listener.endFunctionDeclaration(token); | 2267 listener.endFunctionDeclaration(token); |
2234 return token; | 2268 return token; |
2235 } | 2269 } |
2236 | 2270 |
2237 Token parseFunctionExpression(Token token) { | 2271 Token parseFunctionExpression(Token token) { |
2238 Token beginToken = token; | 2272 Token beginToken = token; |
2239 listener.beginFunction(token); | 2273 listener.beginFunction(token); |
2240 listener.handleModifiers(0); | 2274 listener.handleModifiers(0); |
2241 token = parseType(token, isOptional: true); | 2275 token = parseType(token, TypeContinuation.Optional); |
2242 listener.beginFunctionName(token); | 2276 listener.beginFunctionName(token); |
2243 token = parseIdentifier(token, IdentifierContext.functionExpressionName); | 2277 token = parseIdentifier(token, IdentifierContext.functionExpressionName); |
2244 listener.endFunctionName(beginToken, token); | 2278 listener.endFunctionName(beginToken, token); |
2245 token = parseTypeVariablesOpt(token); | 2279 token = parseTypeVariablesOpt(token); |
2246 token = parseFormalParameters(token, MemberKind.Local); | 2280 token = parseFormalParameters(token, MemberKind.Local); |
2247 listener.handleNoInitializers(); | 2281 listener.handleNoInitializers(); |
2248 AsyncModifier savedAsyncModifier = asyncState; | 2282 AsyncModifier savedAsyncModifier = asyncState; |
2249 token = parseAsyncModifier(token); | 2283 token = parseAsyncModifier(token); |
2250 bool isBlock = optional('{', token); | 2284 bool isBlock = optional('{', token); |
2251 token = parseFunctionBody(token, true, false); | 2285 token = parseFunctionBody(token, true, false); |
(...skipping 1773 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4025 return reportUnrecoverableError( | 4059 return reportUnrecoverableError( |
4026 token, () => code.format(uri, token.charOffset, string)); | 4060 token, () => code.format(uri, token.charOffset, string)); |
4027 } | 4061 } |
4028 } | 4062 } |
4029 | 4063 |
4030 typedef FastaMessage NoArgument(Uri uri, int charOffset); | 4064 typedef FastaMessage NoArgument(Uri uri, int charOffset); |
4031 | 4065 |
4032 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); | 4066 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); |
4033 | 4067 |
4034 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); | 4068 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); |
OLD | NEW |