| 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 |