| 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 '../scanner.dart' show ErrorToken; | 7 import '../scanner.dart' show ErrorToken; |
| 8 | 8 |
| 9 import '../scanner/recover.dart' show closeBraceFor, skipToEof; | 9 import '../scanner/recover.dart' show closeBraceFor, skipToEof; |
| 10 | 10 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 final String type; | 83 final String type; |
| 84 const FormalParameterType(this.type); | 84 const FormalParameterType(this.type); |
| 85 bool get isRequired => this == REQUIRED; | 85 bool get isRequired => this == REQUIRED; |
| 86 bool get isPositional => this == POSITIONAL; | 86 bool get isPositional => this == POSITIONAL; |
| 87 bool get isNamed => this == NAMED; | 87 bool get isNamed => this == NAMED; |
| 88 static final REQUIRED = const FormalParameterType('required'); | 88 static final REQUIRED = const FormalParameterType('required'); |
| 89 static final POSITIONAL = const FormalParameterType('positional'); | 89 static final POSITIONAL = const FormalParameterType('positional'); |
| 90 static final NAMED = const FormalParameterType('named'); | 90 static final NAMED = const FormalParameterType('named'); |
| 91 } | 91 } |
| 92 | 92 |
| 93 /** | 93 /// An event generating parser of Dart programs. This parser expects all tokens |
| 94 * An event generating parser of Dart programs. This parser expects | 94 /// in a linked list (aka a token stream). |
| 95 * all tokens in a linked list (aka a token stream). | 95 /// |
| 96 * | 96 /// The class [Scanner] is used to generate a token stream. See the file |
| 97 * The class [Scanner] is used to generate a token stream. See the | 97 /// [scanner.dart](../scanner.dart). |
| 98 * file scanner.dart. | 98 /// |
| 99 * | 99 /// Subclasses of the class [Listener] are used to listen to events. |
| 100 * Subclasses of the class [Listener] are used to listen to events. | 100 /// |
| 101 * | 101 /// Most methods of this class belong in one of three major categories: parse |
| 102 * Most methods of this class belong in one of two major categories: | 102 /// methods, peek methods, and skip methods. Parse methods all have the prefix |
| 103 * parse methods and peek methods. Parse methods all have the prefix | 103 /// `parse`, peek methods all have the prefix `peek`, and skip methods all have |
| 104 * parse, and peek methods all have the prefix peek. | 104 /// the prefix `skip`. |
| 105 * | 105 /// |
| 106 * Parse methods generate events (by calling methods on [listener]) | 106 /// Parse methods generate events (by calling methods on [listener]) and return |
| 107 * and return the next token to parse. Peek methods do not generate | 107 /// the next token to parse. Peek methods do not generate events (except for |
| 108 * events (except for errors) and may return null. | 108 /// errors) and may return null. Skip methods are like parse methods, but skip |
| 109 * | 109 /// over some parts of the file being parsed. |
| 110 * Parse methods are generally named parseGrammarProductionSuffix. The | 110 /// |
| 111 * suffix can be one of "opt", or "star". "opt" means zero or one | 111 /// Parse methods are generally named `parseGrammarProductionSuffix`. The |
| 112 * matches, "star" means zero or more matches. For example, | 112 /// suffix can be one of `opt`, or `star`. `opt` means zero or one matches, |
| 113 * [parseMetadataStar] corresponds to this grammar snippet: [: | 113 /// `star` means zero or more matches. For example, [parseMetadataStar] |
| 114 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. | 114 /// corresponds to this grammar snippet: `metadata*`, and [parseTypeOpt] |
| 115 */ | 115 /// corresponds to: `type?`. |
| 116 /// |
| 117 /// ## Implementation Notes |
| 118 /// |
| 119 /// The parser assumes that keywords, built-in identifiers, and other special |
| 120 /// words (pseudo-keywords) are all canonicalized. To extend the parser to |
| 121 /// recognize a new identifier, one should modify |
| 122 /// [keyword.dart](../scanner/keyword.dart) and ensure the identifier is added |
| 123 /// to the keyword table. |
| 124 /// |
| 125 /// As a consequence of this, one should not use `==` to compare strings in the |
| 126 /// parser. One should favor the methods [optional] and [expected] to recognize |
| 127 /// keywords or identifiers. In some cases, it's possible to compare a token's |
| 128 /// `stringValue` using [identical], but normally [optional] will suffice. |
| 129 /// |
| 130 /// Historically, we over-used identical, and when identical is used on other |
| 131 /// objects than strings, it can often be replaced by `==`. |
| 116 class Parser { | 132 class Parser { |
| 117 final Listener listener; | 133 final Listener listener; |
| 118 | 134 |
| 119 bool mayParseFunctionExpressions = true; | 135 bool mayParseFunctionExpressions = true; |
| 120 | 136 |
| 121 /// Represents parser state: what asynchronous syntax is allowed in the | 137 /// Represents parser state: what asynchronous syntax is allowed in the |
| 122 /// function being currently parsed. In rare situations, this can be set by | 138 /// function being currently parsed. In rare situations, this can be set by |
| 123 /// external clients, for example, to parse an expression outside a function. | 139 /// external clients, for example, to parse an expression outside a function. |
| 124 AsyncModifier asyncState = AsyncModifier.Sync; | 140 AsyncModifier asyncState = AsyncModifier.Sync; |
| 125 | 141 |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 listener.beginMetadataStar(token); | 398 listener.beginMetadataStar(token); |
| 383 int count = 0; | 399 int count = 0; |
| 384 while (optional('@', token)) { | 400 while (optional('@', token)) { |
| 385 token = parseMetadata(token); | 401 token = parseMetadata(token); |
| 386 count++; | 402 count++; |
| 387 } | 403 } |
| 388 listener.endMetadataStar(count, forParameter); | 404 listener.endMetadataStar(count, forParameter); |
| 389 return token; | 405 return token; |
| 390 } | 406 } |
| 391 | 407 |
| 392 /** | 408 /// Parse `'@' qualified (‘.’ identifier)? (arguments)?` |
| 393 * Parse | |
| 394 * [: '@' qualified (‘.’ identifier)? (arguments)? :] | |
| 395 */ | |
| 396 Token parseMetadata(Token token) { | 409 Token parseMetadata(Token token) { |
| 397 listener.beginMetadata(token); | 410 listener.beginMetadata(token); |
| 398 Token atToken = token; | 411 Token atToken = token; |
| 399 assert(optional('@', token)); | 412 assert(optional('@', token)); |
| 400 token = parseIdentifier(token.next, IdentifierContext.metadataReference); | 413 token = parseIdentifier(token.next, IdentifierContext.metadataReference); |
| 401 token = | 414 token = |
| 402 parseQualifiedRestOpt(token, IdentifierContext.metadataContinuation); | 415 parseQualifiedRestOpt(token, IdentifierContext.metadataContinuation); |
| 403 token = parseTypeArgumentsOpt(token); | 416 token = parseTypeArgumentsOpt(token); |
| 404 Token period = null; | 417 Token period = null; |
| 405 if (optional('.', token)) { | 418 if (optional('.', token)) { |
| (...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 if (optional('extends', token) || optional('super', token)) { | 953 if (optional('extends', token) || optional('super', token)) { |
| 941 extendsOrSuper = token; | 954 extendsOrSuper = token; |
| 942 token = parseType(token.next); | 955 token = parseType(token.next); |
| 943 } else { | 956 } else { |
| 944 listener.handleNoType(token); | 957 listener.handleNoType(token); |
| 945 } | 958 } |
| 946 listener.endTypeVariable(token, extendsOrSuper); | 959 listener.endTypeVariable(token, extendsOrSuper); |
| 947 return token; | 960 return token; |
| 948 } | 961 } |
| 949 | 962 |
| 950 /** | 963 /// Returns true if the stringValue of the [token] is either [value1], |
| 951 * Returns true if the stringValue of the [token] is either [value1], | 964 /// [value2], or [value3]. |
| 952 * [value2], or [value3]. | |
| 953 */ | |
| 954 bool isOneOf3(Token token, String value1, String value2, String value3) { | 965 bool isOneOf3(Token token, String value1, String value2, String value3) { |
| 955 String stringValue = token.stringValue; | 966 String stringValue = token.stringValue; |
| 956 return value1 == stringValue || | 967 return value1 == stringValue || |
| 957 value2 == stringValue || | 968 value2 == stringValue || |
| 958 value3 == stringValue; | 969 value3 == stringValue; |
| 959 } | 970 } |
| 960 | 971 |
| 961 /** | 972 /// Returns true if the stringValue of the [token] is either [value1], |
| 962 * Returns true if the stringValue of the [token] is either [value1], | 973 /// [value2], [value3], or [value4]. |
| 963 * [value2], [value3], or [value4]. | |
| 964 */ | |
| 965 bool isOneOf4( | 974 bool isOneOf4( |
| 966 Token token, String value1, String value2, String value3, String value4) { | 975 Token token, String value1, String value2, String value3, String value4) { |
| 967 String stringValue = token.stringValue; | 976 String stringValue = token.stringValue; |
| 968 return value1 == stringValue || | 977 return value1 == stringValue || |
| 969 value2 == stringValue || | 978 value2 == stringValue || |
| 970 value3 == stringValue || | 979 value3 == stringValue || |
| 971 value4 == stringValue; | 980 value4 == stringValue; |
| 972 } | 981 } |
| 973 | 982 |
| 974 bool notEofOrValue(String value, Token token) { | 983 bool notEofOrValue(String value, Token token) { |
| (...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 int count = 0; | 1577 int count = 0; |
| 1569 while (identical(token.kind, KEYWORD_TOKEN)) { | 1578 while (identical(token.kind, KEYWORD_TOKEN)) { |
| 1570 if (!isModifier(token)) break; | 1579 if (!isModifier(token)) break; |
| 1571 token = parseModifier(token); | 1580 token = parseModifier(token); |
| 1572 count++; | 1581 count++; |
| 1573 } | 1582 } |
| 1574 listener.handleModifiers(count); | 1583 listener.handleModifiers(count); |
| 1575 return token; | 1584 return token; |
| 1576 } | 1585 } |
| 1577 | 1586 |
| 1578 /** | 1587 /// Returns the first token after the type starting at [token]. |
| 1579 * Returns the first token after the type starting at [token]. | 1588 /// |
| 1580 * | 1589 /// This method assumes that [token] is an identifier (or void). Use |
| 1581 * This method assumes that [token] is an identifier (or void). | 1590 /// [peekAfterIfType] if [token] isn't known to be an identifier. |
| 1582 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | |
| 1583 */ | |
| 1584 Token peekAfterType(Token token) { | 1591 Token peekAfterType(Token token) { |
| 1585 // We are looking at "identifier ...". | 1592 // We are looking at "identifier ...". |
| 1586 Token peek = token; | 1593 Token peek = token; |
| 1587 if (!isGeneralizedFunctionType(token)) { | 1594 if (!isGeneralizedFunctionType(token)) { |
| 1588 peek = peekAfterNominalType(token); | 1595 peek = peekAfterNominalType(token); |
| 1589 } | 1596 } |
| 1590 | 1597 |
| 1591 // We might have just skipped over the return value of the function type. | 1598 // We might have just skipped over the return value of the function type. |
| 1592 // Check again, if we are now at a function type position. | 1599 // Check again, if we are now at a function type position. |
| 1593 while (isGeneralizedFunctionType(peek)) { | 1600 while (isGeneralizedFunctionType(peek)) { |
| 1594 peek = peekAfterFunctionType(peek.next); | 1601 peek = peekAfterFunctionType(peek.next); |
| 1595 } | 1602 } |
| 1596 return peek; | 1603 return peek; |
| 1597 } | 1604 } |
| 1598 | 1605 |
| 1599 /** | 1606 /// Returns the first token after the nominal type starting at [token]. |
| 1600 * Returns the first token after the nominal type starting at [token]. | 1607 /// |
| 1601 * | 1608 /// This method assumes that [token] is an identifier (or void). |
| 1602 * This method assumes that [token] is an identifier (or void). | |
| 1603 */ | |
| 1604 Token peekAfterNominalType(Token token) { | 1609 Token peekAfterNominalType(Token token) { |
| 1605 Token peek = token.next; | 1610 Token peek = token.next; |
| 1606 if (identical(peek.kind, PERIOD_TOKEN)) { | 1611 if (identical(peek.kind, PERIOD_TOKEN)) { |
| 1607 if (peek.next.isIdentifier()) { | 1612 if (peek.next.isIdentifier()) { |
| 1608 // Look past a library prefix. | 1613 // Look past a library prefix. |
| 1609 peek = peek.next.next; | 1614 peek = peek.next.next; |
| 1610 } | 1615 } |
| 1611 } | 1616 } |
| 1612 // We are looking at "qualified ...". | 1617 // We are looking at "qualified ...". |
| 1613 if (identical(peek.kind, LT_TOKEN)) { | 1618 if (identical(peek.kind, LT_TOKEN)) { |
| 1614 // Possibly generic type. | 1619 // Possibly generic type. |
| 1615 // We are looking at "qualified '<'". | 1620 // We are looking at "qualified '<'". |
| 1616 BeginGroupToken beginGroupToken = peek; | 1621 BeginGroupToken beginGroupToken = peek; |
| 1617 Token gtToken = beginGroupToken.endGroup; | 1622 Token gtToken = beginGroupToken.endGroup; |
| 1618 if (gtToken != null) { | 1623 if (gtToken != null) { |
| 1619 // We are looking at "qualified '<' ... '>' ...". | 1624 // We are looking at "qualified '<' ... '>' ...". |
| 1620 peek = gtToken.next; | 1625 peek = gtToken.next; |
| 1621 } | 1626 } |
| 1622 } | 1627 } |
| 1623 return peek; | 1628 return peek; |
| 1624 } | 1629 } |
| 1625 | 1630 |
| 1626 /** | 1631 /// Returns the first token after the function type starting at [token]. |
| 1627 * Returns the first token after the function type starting at [token]. | 1632 /// |
| 1628 * | 1633 /// The token must be at the token *after* the `Function` token |
| 1629 * The token must be at the token *after* the `Function` token position. That | 1634 /// position. That is, the return type and the `Function` token must have |
| 1630 * is, the return type and the `Function` token must have already been | 1635 /// already been skipped. |
| 1631 * skipped. | 1636 /// |
| 1632 * | 1637 /// This function only skips over one function type syntax. If necessary, |
| 1633 * This function only skips over one function type syntax. | 1638 /// this function must be called multiple times. |
| 1634 * If necessary, this function must be called multiple times. | 1639 /// |
| 1635 * | 1640 /// Example: |
| 1636 * Example: | 1641 /// |
| 1637 * ``` | 1642 /// int Function() Function<T>(int) |
| 1638 * int Function() Function<T>(int) | 1643 /// ^ ^ |
| 1639 * ^ ^ | 1644 /// |
| 1640 * A call to this function must be either at `(` or at `<`. | 1645 /// A call to this function must be either at `(` or at `<`. If `token` |
| 1641 * If `token` pointed to the first `(`, then the returned | 1646 /// pointed to the first `(`, then the returned token points to the second |
| 1642 * token points to the second `Function` token. | 1647 /// `Function` token. |
| 1643 */ | |
| 1644 Token peekAfterFunctionType(Token token) { | 1648 Token peekAfterFunctionType(Token token) { |
| 1645 // Possible inputs are: | 1649 // Possible inputs are: |
| 1646 // ( ... ) | 1650 // ( ... ) |
| 1647 // < ... >( ... ) | 1651 // < ... >( ... ) |
| 1648 | 1652 |
| 1649 Token peek = token; | 1653 Token peek = token; |
| 1650 // If there is a generic argument to the function, skip over that one first. | 1654 // If there is a generic argument to the function, skip over that one first. |
| 1651 if (identical(peek.kind, LT_TOKEN)) { | 1655 if (identical(peek.kind, LT_TOKEN)) { |
| 1652 BeginGroupToken beginGroupToken = peek; | 1656 BeginGroupToken beginGroupToken = peek; |
| 1653 Token closeToken = beginGroupToken.endGroup; | 1657 Token closeToken = beginGroupToken.endGroup; |
| 1654 if (closeToken != null) { | 1658 if (closeToken != null) { |
| 1655 peek = closeToken.next; | 1659 peek = closeToken.next; |
| 1656 } | 1660 } |
| 1657 } | 1661 } |
| 1658 | 1662 |
| 1659 // Now we just need to skip over the formals. | 1663 // Now we just need to skip over the formals. |
| 1660 expect('(', peek); | 1664 expect('(', peek); |
| 1661 | 1665 |
| 1662 BeginGroupToken beginGroupToken = peek; | 1666 BeginGroupToken beginGroupToken = peek; |
| 1663 Token closeToken = beginGroupToken.endGroup; | 1667 Token closeToken = beginGroupToken.endGroup; |
| 1664 if (closeToken != null) { | 1668 if (closeToken != null) { |
| 1665 peek = closeToken.next; | 1669 peek = closeToken.next; |
| 1666 } | 1670 } |
| 1667 | 1671 |
| 1668 return peek; | 1672 return peek; |
| 1669 } | 1673 } |
| 1670 | 1674 |
| 1671 /** | 1675 /// If [token] is the start of a type, returns the token after that type. |
| 1672 * If [token] is the start of a type, returns the token after that type. | 1676 /// If [token] is not the start of a type, null is returned. |
| 1673 * If [token] is not the start of a type, null is returned. | |
| 1674 */ | |
| 1675 Token peekAfterIfType(Token token) { | 1677 Token peekAfterIfType(Token token) { |
| 1676 if (!optional('void', token) && !token.isIdentifier()) { | 1678 if (!optional('void', token) && !token.isIdentifier()) { |
| 1677 return null; | 1679 return null; |
| 1678 } | 1680 } |
| 1679 return peekAfterType(token); | 1681 return peekAfterType(token); |
| 1680 } | 1682 } |
| 1681 | 1683 |
| 1682 Token skipClassBody(Token token) { | 1684 Token skipClassBody(Token token) { |
| 1683 if (!optional('{', token)) { | 1685 if (!optional('{', token)) { |
| 1684 return reportUnrecoverableError(token, ErrorKind.ExpectedClassBodyToSkip) | 1686 return reportUnrecoverableError(token, ErrorKind.ExpectedClassBodyToSkip) |
| (...skipping 1400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3085 while (identical(token.stringValue, '.')) { | 3087 while (identical(token.stringValue, '.')) { |
| 3086 count++; | 3088 count++; |
| 3087 token = parseIdentifier( | 3089 token = parseIdentifier( |
| 3088 token.next, IdentifierContext.literalSymbolContinuation); | 3090 token.next, IdentifierContext.literalSymbolContinuation); |
| 3089 } | 3091 } |
| 3090 listener.endLiteralSymbol(hashToken, count); | 3092 listener.endLiteralSymbol(hashToken, count); |
| 3091 return token; | 3093 return token; |
| 3092 } | 3094 } |
| 3093 } | 3095 } |
| 3094 | 3096 |
| 3095 /** | 3097 /// Only called when `identical(token.kind, STRING_TOKEN)`. |
| 3096 * Only called when [:token.kind === STRING_TOKEN:]. | |
| 3097 */ | |
| 3098 Token parseSingleLiteralString(Token token) { | 3098 Token parseSingleLiteralString(Token token) { |
| 3099 listener.beginLiteralString(token); | 3099 listener.beginLiteralString(token); |
| 3100 // Parsing the prefix, for instance 'x of 'x${id}y${id}z' | 3100 // Parsing the prefix, for instance 'x of 'x${id}y${id}z' |
| 3101 token = token.next; | 3101 token = token.next; |
| 3102 int interpolationCount = 0; | 3102 int interpolationCount = 0; |
| 3103 var kind = token.kind; | 3103 var kind = token.kind; |
| 3104 while (kind != EOF_TOKEN) { | 3104 while (kind != EOF_TOKEN) { |
| 3105 if (identical(kind, STRING_INTERPOLATION_TOKEN)) { | 3105 if (identical(kind, STRING_INTERPOLATION_TOKEN)) { |
| 3106 // Parsing ${expression}. | 3106 // Parsing ${expression}. |
| 3107 token = token.next; | 3107 token = token.next; |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3503 break; | 3503 break; |
| 3504 } | 3504 } |
| 3505 token = parseSwitchCase(token); | 3505 token = parseSwitchCase(token); |
| 3506 ++caseCount; | 3506 ++caseCount; |
| 3507 } | 3507 } |
| 3508 listener.endSwitchBlock(caseCount, begin, token); | 3508 listener.endSwitchBlock(caseCount, begin, token); |
| 3509 expect('}', token); | 3509 expect('}', token); |
| 3510 return token; | 3510 return token; |
| 3511 } | 3511 } |
| 3512 | 3512 |
| 3513 /** | 3513 /// Peek after the following labels (if any). The following token |
| 3514 * Peek after the following labels (if any). The following token | 3514 /// is used to determine if the labels belong to a statement or a |
| 3515 * is used to determine if the labels belong to a statement or a | 3515 /// switch case. |
| 3516 * switch case. | |
| 3517 */ | |
| 3518 Token peekPastLabels(Token token) { | 3516 Token peekPastLabels(Token token) { |
| 3519 while (token.isIdentifier() && optional(':', token.next)) { | 3517 while (token.isIdentifier() && optional(':', token.next)) { |
| 3520 token = token.next.next; | 3518 token = token.next.next; |
| 3521 } | 3519 } |
| 3522 return token; | 3520 return token; |
| 3523 } | 3521 } |
| 3524 | 3522 |
| 3525 /** | 3523 /// Parse a group of labels, cases and possibly a default keyword and the |
| 3526 * Parse a group of labels, cases and possibly a default keyword and | 3524 /// statements that they select. |
| 3527 * the statements that they select. | |
| 3528 */ | |
| 3529 Token parseSwitchCase(Token token) { | 3525 Token parseSwitchCase(Token token) { |
| 3530 Token begin = token; | 3526 Token begin = token; |
| 3531 Token defaultKeyword = null; | 3527 Token defaultKeyword = null; |
| 3532 int expressionCount = 0; | 3528 int expressionCount = 0; |
| 3533 int labelCount = 0; | 3529 int labelCount = 0; |
| 3534 Token peek = peekPastLabels(token); | 3530 Token peek = peekPastLabels(token); |
| 3535 while (true) { | 3531 while (true) { |
| 3536 // Loop until we find something that can't be part of a switch case. | 3532 // Loop until we find something that can't be part of a switch case. |
| 3537 String value = peek.stringValue; | 3533 String value = peek.stringValue; |
| 3538 if (identical(value, 'default')) { | 3534 if (identical(value, 'default')) { |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3696 break; | 3692 break; |
| 3697 } | 3693 } |
| 3698 if (isRecoverable) { | 3694 if (isRecoverable) { |
| 3699 listener.handleRecoverableError(token, kind, arguments); | 3695 listener.handleRecoverableError(token, kind, arguments); |
| 3700 return null; | 3696 return null; |
| 3701 } else { | 3697 } else { |
| 3702 return listener.handleUnrecoverableError(token, kind, arguments); | 3698 return listener.handleUnrecoverableError(token, kind, arguments); |
| 3703 } | 3699 } |
| 3704 } | 3700 } |
| 3705 } | 3701 } |
| OLD | NEW |