Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 2756953002: Update parser documentation. (Closed)
Patch Set: Remove redundant 'all'. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698