| 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' show Code, Message, Template; | 7 import '../fasta_codes.dart' show Code, Message, Template; |
| 8 | 8 |
| 9 import '../fasta_codes.dart' as fasta; | 9 import '../fasta_codes.dart' as fasta; |
| 10 | 10 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 token = _parseTopLevelDeclaration(token); | 263 token = _parseTopLevelDeclaration(token); |
| 264 listener.endTopLevelDeclaration(token); | 264 listener.endTopLevelDeclaration(token); |
| 265 return token; | 265 return token; |
| 266 } | 266 } |
| 267 | 267 |
| 268 Token _parseTopLevelDeclaration(Token token) { | 268 Token _parseTopLevelDeclaration(Token token) { |
| 269 if (identical(token.type, TokenType.SCRIPT_TAG)) { | 269 if (identical(token.type, TokenType.SCRIPT_TAG)) { |
| 270 return parseScript(token); | 270 return parseScript(token); |
| 271 } | 271 } |
| 272 token = parseMetadataStar(token); | 272 token = parseMetadataStar(token); |
| 273 String value = token.stringValue; | 273 if (token.isTopLevelKeyword) { |
| 274 if (identical(value, 'abstract')) { | 274 return parseTopLevelKeywordDeclaration(null, token); |
| 275 if (optional('class', token.next)) { | 275 } |
| 276 return parseClassOrNamedMixinApplication(token); | 276 Token start = token; |
| 277 Link<Token> modifiers = const Link<Token>(); |
| 278 while (token.isModifier) { |
| 279 modifiers = modifiers.prepend(token); |
| 280 token = token.next; |
| 281 } |
| 282 if (token.isTopLevelKeyword) { |
| 283 Token abstractToken; |
| 284 while (modifiers.isNotEmpty) { |
| 285 Token modifierToken = modifiers.head; |
| 286 if (optional('abstract', modifierToken) && |
| 287 optional('class', token) && |
| 288 abstractToken == null) { |
| 289 abstractToken = modifierToken; |
| 290 } else { |
| 291 // TODO(danrubel): Report more specific recoverable error message |
| 292 // for `const class` to better help the user. |
| 293 // See ParserErrorCode CONST_CLASS |
| 294 |
| 295 // Report an error for each extraneous modifier |
| 296 reportRecoverableErrorWithToken( |
| 297 modifierToken, fasta.templateExtraneousModifier); |
| 298 } |
| 299 modifiers = modifiers.tail; |
| 277 } | 300 } |
| 278 reportRecoverableErrorWithToken(token, fasta.templateExtraneousModifier); | 301 return parseTopLevelKeywordDeclaration(abstractToken, token); |
| 279 token = token.next; | 302 } else if (token.isIdentifier || token.keyword != null) { |
| 280 value = token.stringValue; | 303 return parseTopLevelMember(token, start, modifiers); |
| 304 } else if (modifiers.isNotEmpty && modifiers.head.type.isBuiltIn) { |
| 305 // Handle the edge case where a modifier is being used as an identifier |
| 306 return parseTopLevelMember(start); |
| 281 } | 307 } |
| 308 // Ignore any preceding modifiers and just report the unexpected token |
| 309 reportRecoverableErrorWithToken(token, fasta.templateExpectedDeclaration); |
| 310 listener.handleInvalidTopLevelDeclaration(token); |
| 311 return token.next; |
| 312 } |
| 313 |
| 314 Token parseTopLevelKeywordDeclaration(Token abstractToken, Token token) { |
| 315 final String value = token.stringValue; |
| 282 if (identical(value, 'class')) { | 316 if (identical(value, 'class')) { |
| 283 return parseClassOrNamedMixinApplication(token); | 317 return parseClassOrNamedMixinApplication(abstractToken, token); |
| 284 } else if (identical(value, 'enum')) { | 318 } else if (identical(value, 'enum')) { |
| 285 return parseEnum(token); | 319 return parseEnum(token); |
| 286 } else if (identical(value, 'typedef') && | 320 } else if (identical(value, 'typedef')) { |
| 287 (token.next.isIdentifier || optional("void", token.next))) { | 321 Token next = token.next; |
| 288 return parseTypedef(token); | 322 if (next.isIdentifier || optional("void", next)) { |
| 323 return parseTypedef(token); |
| 324 } else { |
| 325 return parseTopLevelMember(token); |
| 326 } |
| 289 } else if (identical(value, 'library')) { | 327 } else if (identical(value, 'library')) { |
| 290 return parseLibraryName(token); | 328 return parseLibraryName(token); |
| 291 } else if (identical(value, 'import')) { | 329 } else if (identical(value, 'import')) { |
| 292 return parseImport(token); | 330 return parseImport(token); |
| 293 } else if (identical(value, 'export')) { | 331 } else if (identical(value, 'export')) { |
| 294 return parseExport(token); | 332 return parseExport(token); |
| 295 } else if (identical(value, 'part')) { | 333 } else if (identical(value, 'part')) { |
| 296 return parsePartOrPartOf(token); | 334 return parsePartOrPartOf(token); |
| 297 } else if (token.type == TokenType.IDENTIFIER || token.keyword != null) { | |
| 298 return parseTopLevelMember(token); | |
| 299 } else { | |
| 300 reportRecoverableErrorWithToken(token, fasta.templateExpectedDeclaration); | |
| 301 listener.handleInvalidTopLevelDeclaration(token); | |
| 302 return token.next; | |
| 303 } | 335 } |
| 336 |
| 337 throw "Internal error: Unhandled top level keyword '$value'."; |
| 304 } | 338 } |
| 305 | 339 |
| 306 /// library qualified ';' | 340 /// library qualified ';' |
| 307 Token parseLibraryName(Token token) { | 341 Token parseLibraryName(Token token) { |
| 308 Token libraryKeyword = token; | 342 Token libraryKeyword = token; |
| 309 listener.beginLibraryName(libraryKeyword); | 343 listener.beginLibraryName(libraryKeyword); |
| 310 assert(optional('library', token)); | 344 assert(optional('library', token)); |
| 311 token = parseQualified(token.next, IdentifierContext.libraryName, | 345 token = parseQualified(token.next, IdentifierContext.libraryName, |
| 312 IdentifierContext.libraryNameContinuation); | 346 IdentifierContext.libraryNameContinuation); |
| 313 Token semicolon = token; | 347 Token semicolon = token; |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 token = parseIdentifier(token, IdentifierContext.enumValueDeclaration); | 854 token = parseIdentifier(token, IdentifierContext.enumValueDeclaration); |
| 821 count++; | 855 count++; |
| 822 } | 856 } |
| 823 } | 857 } |
| 824 Token endBrace = token; | 858 Token endBrace = token; |
| 825 token = expect('}', token); | 859 token = expect('}', token); |
| 826 listener.endEnum(enumKeyword, endBrace, count); | 860 listener.endEnum(enumKeyword, endBrace, count); |
| 827 return token; | 861 return token; |
| 828 } | 862 } |
| 829 | 863 |
| 830 Token parseClassOrNamedMixinApplication(Token token) { | 864 Token parseClassOrNamedMixinApplication(Token abstractToken, Token token) { |
| 831 listener.beginClassOrNamedMixinApplication(token); | 865 listener.beginClassOrNamedMixinApplication(token); |
| 832 Token begin = token; | 866 Token begin = abstractToken ?? token; |
| 833 if (optional('abstract', token)) { | 867 if (abstractToken != null) { |
| 834 token = parseModifier(token); | 868 token = parseModifier(abstractToken); |
| 835 listener.handleModifiers(1); | 869 listener.handleModifiers(1); |
| 836 } else { | 870 } else { |
| 837 listener.handleModifiers(0); | 871 listener.handleModifiers(0); |
| 838 } | 872 } |
| 839 Token classKeyword = token; | 873 Token classKeyword = token; |
| 840 token = expect("class", token); | 874 token = expect("class", token); |
| 841 Token name = token; | 875 Token name = token; |
| 842 token = | 876 token = |
| 843 parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); | 877 parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); |
| 844 token = parseTypeVariablesOpt(token); | 878 token = parseTypeVariablesOpt(token); |
| (...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 token.next = new Token(TokenType.GT, token.charOffset + 1); | 1602 token.next = new Token(TokenType.GT, token.charOffset + 1); |
| 1569 token.next.next = next; | 1603 token.next.next = next; |
| 1570 } | 1604 } |
| 1571 endStuff(count, begin, token); | 1605 endStuff(count, begin, token); |
| 1572 return expect('>', token); | 1606 return expect('>', token); |
| 1573 } | 1607 } |
| 1574 handleNoStuff(token); | 1608 handleNoStuff(token); |
| 1575 return token; | 1609 return token; |
| 1576 } | 1610 } |
| 1577 | 1611 |
| 1578 Token parseTopLevelMember(Token token) { | 1612 Token parseTopLevelMember(Token token, |
| 1579 Token start = token; | 1613 [Token start, Link<Token> identifiers = const Link<Token>()]) { |
| 1614 start ??= token; |
| 1580 listener.beginTopLevelMember(token); | 1615 listener.beginTopLevelMember(token); |
| 1581 | 1616 |
| 1582 Link<Token> identifiers = findMemberName(token); | 1617 identifiers = findMemberName(token, identifiers); |
| 1583 if (identifiers.isEmpty) { | 1618 if (identifiers.isEmpty) { |
| 1584 return reportUnrecoverableErrorWithToken( | 1619 return reportUnrecoverableErrorWithToken( |
| 1585 start, fasta.templateExpectedDeclaration) | 1620 start, fasta.templateExpectedDeclaration) |
| 1586 .next; | 1621 .next; |
| 1587 } | 1622 } |
| 1588 Token afterName = identifiers.head; | 1623 Token afterName = identifiers.head; |
| 1589 identifiers = identifiers.tail; | 1624 identifiers = identifiers.tail; |
| 1590 | 1625 |
| 1591 if (identifiers.isEmpty) { | 1626 if (identifiers.isEmpty) { |
| 1592 return reportUnrecoverableErrorWithToken( | 1627 return reportUnrecoverableErrorWithToken( |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1770 /// | 1805 /// |
| 1771 /// get foo async* { return null } | 1806 /// get foo async* { return null } |
| 1772 /// results in | 1807 /// results in |
| 1773 /// ['{', 'foo', 'get'] | 1808 /// ['{', 'foo', 'get'] |
| 1774 /// | 1809 /// |
| 1775 /// | 1810 /// |
| 1776 /// operator *(arg) => null; | 1811 /// operator *(arg) => null; |
| 1777 /// results in | 1812 /// results in |
| 1778 /// ['(', '*', 'operator'] | 1813 /// ['(', '*', 'operator'] |
| 1779 /// | 1814 /// |
| 1780 Link<Token> findMemberName(Token token) { | 1815 Link<Token> findMemberName(Token token, |
| 1816 [Link<Token> identifiers = const Link<Token>()]) { |
| 1781 // TODO(ahe): This method is rather broken for examples like this: | 1817 // TODO(ahe): This method is rather broken for examples like this: |
| 1782 // | 1818 // |
| 1783 // get<T>(){} | 1819 // get<T>(){} |
| 1784 // | 1820 // |
| 1785 // In addition, the loop below will include things that can't be | 1821 // In addition, the loop below will include things that can't be |
| 1786 // identifiers. This may be desirable (for error recovery), or | 1822 // identifiers. This may be desirable (for error recovery), or |
| 1787 // not. Regardless, this method probably needs an overhaul. | 1823 // not. Regardless, this method probably needs an overhaul. |
| 1788 Link<Token> identifiers = const Link<Token>(); | |
| 1789 | 1824 |
| 1790 // `true` if 'get' has been seen. | 1825 // `true` if 'get' has been seen. |
| 1791 bool isGetter = false; | 1826 bool isGetter = false; |
| 1792 // `true` if an identifier has been seen after 'get'. | 1827 // `true` if an identifier has been seen after 'get'. |
| 1793 bool hasName = false; | 1828 bool hasName = false; |
| 1794 | 1829 |
| 1795 while (token.kind != EOF_TOKEN) { | 1830 while (token.kind != EOF_TOKEN) { |
| 1796 if (optional('get', token)) { | 1831 if (optional('get', token)) { |
| 1797 isGetter = true; | 1832 isGetter = true; |
| 1798 } else if (hasName && | 1833 } else if (hasName && |
| (...skipping 2349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4148 } | 4183 } |
| 4149 | 4184 |
| 4150 Token reportUnexpectedToken(Token token) { | 4185 Token reportUnexpectedToken(Token token) { |
| 4151 return reportUnrecoverableErrorWithToken( | 4186 return reportUnrecoverableErrorWithToken( |
| 4152 token, fasta.templateUnexpectedToken); | 4187 token, fasta.templateUnexpectedToken); |
| 4153 } | 4188 } |
| 4154 } | 4189 } |
| 4155 | 4190 |
| 4156 // TODO(ahe): Remove when analyzer supports generalized function syntax. | 4191 // TODO(ahe): Remove when analyzer supports generalized function syntax. |
| 4157 typedef _MessageWithArgument<T> = Message Function(T); | 4192 typedef _MessageWithArgument<T> = Message Function(T); |
| OLD | NEW |