Skip to content

Commit 9eb5544

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Parser: split some pattern/expression parsing logic.
This change restores `parseParenthesizedExpressionOrRecordLiteral`, `parseArguments`, and `parseArgumentsRest` to the way they looked prior to adding parser support, and instead adds new methods `parseParenthesizedPatternOrRecordPattern` and `parseExtractorPatternRest` that are specialized for patterns parsing. Bug: #50035 Change-Id: I104e031a796ef7f217cd427e1a9ae94a04dafa7b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/261620 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Jens Johansen <[email protected]>
1 parent 9158353 commit 9eb5544

File tree

163 files changed

+1488
-1399
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+1488
-1399
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart

Lines changed: 155 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -6112,23 +6112,14 @@ class Parser {
61126112
return token;
61136113
}
61146114

6115-
/// Parse either a parenthesized expression or a record literal, or a
6116-
/// parenthesized pattern or record pattern. If [constKeywordForRecord] is
6117-
/// non-null it is forced to be a record literal and an error will be issued
6118-
/// if there is no trailing comma.
6119-
///
6120-
/// [forPattern] indicates whether a pattern is being parsed.
6115+
/// Parse either a parenthesized expression or a record literal.
6116+
/// If [constKeywordForRecord] is non-null it is forced to be a record
6117+
/// literal and an error will be issued if there is no trailing comma.
61216118
Token parseParenthesizedExpressionOrRecordLiteral(
6122-
Token token, Token? constKeywordForRecord,
6123-
{bool forPattern = false}) {
6124-
if (forPattern) {
6125-
assert(constKeywordForRecord == null);
6126-
}
6119+
Token token, Token? constKeywordForRecord) {
61276120
Token begin = token.next!;
61286121
assert(optional('(', begin));
6129-
if (!forPattern) {
6130-
listener.beginParenthesizedExpressionOrRecordLiteral(begin);
6131-
}
6122+
listener.beginParenthesizedExpressionOrRecordLiteral(begin);
61326123

61336124
// For parsing of parenthesized expression we need parity with
61346125
// parseExpressionInParenthesisRest used in ensureParenthesizedCondition.
@@ -6143,13 +6134,7 @@ class Parser {
61436134
break;
61446135
}
61456136
Token? colon = null;
6146-
if (forPattern && optional(':', next)) {
6147-
wasRecord = true;
6148-
wasValidRecord = true;
6149-
listener.handleNoName(token);
6150-
colon = token = next;
6151-
} else if (optional(':', next.next!) || /* recovery */
6152-
optional(':', next)) {
6137+
if (optional(':', next.next!) || /* recovery */ optional(':', next)) {
61536138
// Record with named expression.
61546139
wasRecord = true;
61556140
token = ensureIdentifier(
@@ -6159,30 +6144,15 @@ class Parser {
61596144
colon = token;
61606145
wasValidRecord = true;
61616146
}
6162-
if (forPattern) {
6163-
token = parsePattern(token);
6164-
} else {
6165-
token = parseExpression(token);
6166-
}
6147+
token = parseExpression(token);
61676148
next = token.next!;
6168-
if (forPattern) {
6169-
if (wasRecord || colon != null) {
6170-
listener.handlePatternField(colon);
6171-
}
6172-
} else {
6173-
if (colon != null) listener.handleNamedRecordField(colon);
6174-
}
6149+
if (colon != null) listener.handleNamedRecordField(colon);
61756150
++count;
61766151
if (!optional(',', next)) {
61776152
// TODO(jensj): Possible more specific recovery.
6178-
// TODO(paulberry): make sure to test the error case where there's a
6179-
// colon but it's not a record (for patterns).
61806153
break;
61816154
} else {
61826155
// It is a comma, i.e. it's a record.
6183-
if (forPattern && !wasRecord && colon == null) {
6184-
listener.handlePatternField(colon);
6185-
}
61866156
wasRecord = true;
61876157
wasValidRecord = true;
61886158
}
@@ -6200,17 +6170,9 @@ class Parser {
62006170
reportRecoverableError(
62016171
token, codes.messageRecordLiteralOnePositionalFieldNoTrailingComma);
62026172
}
6203-
if (forPattern) {
6204-
listener.handleRecordPattern(begin, count);
6205-
} else {
6206-
listener.endRecordLiteral(begin, count, constKeywordForRecord);
6207-
}
6173+
listener.endRecordLiteral(begin, count, constKeywordForRecord);
62086174
} else {
6209-
if (forPattern) {
6210-
listener.handleParenthesizedPattern(begin);
6211-
} else {
6212-
listener.endParenthesizedExpression(begin);
6213-
}
6175+
listener.endParenthesizedExpression(begin);
62146176
}
62156177

62166178
return token;
@@ -7063,21 +7025,15 @@ class Parser {
70637025
/// label expression
70647026
/// ;
70657027
/// ```
7066-
///
7067-
/// [forPattern] indicates whether an expression or pattern is being
7068-
/// parsed.
7069-
Token parseArguments(Token token, {bool forPattern = false}) {
7070-
return parseArgumentsRest(token.next!, forPattern: forPattern);
7028+
Token parseArguments(Token token) {
7029+
return parseArgumentsRest(token.next!);
70717030
}
70727031

70737032
/// Parses the rest of an arguments list, where [token] is the `(`.
7074-
/// [forPattern] indicates whether an expression or pattern is being parsed.
7075-
Token parseArgumentsRest(Token token, {bool forPattern = false}) {
7033+
Token parseArgumentsRest(Token token) {
70767034
Token begin = token;
70777035
assert(optional('(', begin));
7078-
if (!forPattern) {
7079-
listener.beginArguments(begin);
7080-
}
7036+
listener.beginArguments(begin);
70817037
int argumentCount = 0;
70827038
bool old = mayParseFunctionExpressions;
70837039
mayParseFunctionExpressions = true;
@@ -7088,27 +7044,15 @@ class Parser {
70887044
break;
70897045
}
70907046
Token? colon = null;
7091-
if (forPattern && optional(':', next)) {
7092-
listener.handleNoName(token);
7093-
colon = token = next;
7094-
} else if (optional(':', next.next!) || /* recovery */
7095-
optional(':', next)) {
7047+
if (optional(':', next.next!) || /* recovery */ optional(':', next)) {
70967048
token =
70977049
ensureIdentifier(token, IdentifierContext.namedArgumentReference)
70987050
.next!;
70997051
colon = token;
71007052
}
7101-
if (forPattern) {
7102-
token = parsePattern(token);
7103-
} else {
7104-
token = parseExpression(token);
7105-
}
7053+
token = parseExpression(token);
71067054
next = token.next!;
7107-
if (forPattern) {
7108-
listener.handlePatternField(colon);
7109-
} else {
7110-
if (colon != null) listener.handleNamedArgument(colon);
7111-
}
7055+
if (colon != null) listener.handleNamedArgument(colon);
71127056
++argumentCount;
71137057
if (!optional(',', next)) {
71147058
if (optional(')', next)) {
@@ -7132,11 +7076,7 @@ class Parser {
71327076
}
71337077
assert(optional(')', token));
71347078
mayParseFunctionExpressions = old;
7135-
if (forPattern) {
7136-
listener.handleExtractorPatternFields(argumentCount, begin, token);
7137-
} else {
7138-
listener.endArguments(argumentCount, begin, token);
7139-
}
7079+
listener.endArguments(argumentCount, begin, token);
71407080
return token;
71417081
}
71427082

@@ -9234,8 +9174,7 @@ class Parser {
92349174
listener.handleRecordPattern(next, /* count = */ 0);
92359175
return nextNext;
92369176
} else {
9237-
return parseParenthesizedExpressionOrRecordLiteral(token, null,
9238-
forPattern: true);
9177+
return parseParenthesizedPatternOrRecordPattern(token);
92399178
}
92409179
case 'const':
92419180
// constantPattern ::= booleanLiteral
@@ -9297,7 +9236,7 @@ class Parser {
92979236
if (optional('(', afterToken) && !potentialTypeArg.recovered) {
92989237
TypeParamOrArgInfo typeArg = potentialTypeArg;
92999238
token = typeArg.parseArguments(token, this);
9300-
token = parseArguments(token, forPattern: true);
9239+
token = parseExtractorPatternRest(token);
93019240
listener.handleExtractorPattern(firstIdentifier, dot, secondIdentifier);
93029241
return token;
93039242
}
@@ -9465,6 +9404,141 @@ class Parser {
94659404
}
94669405
}
94679406
}
9407+
9408+
/// Parses either a parenthesizedPattern or a recordPattern.
9409+
///
9410+
/// parenthesizedPattern ::= '(' pattern ')'
9411+
/// recordPattern ::= '(' patternFields? ')'
9412+
/// patternFields ::= patternField ( ',' patternField )* ','?
9413+
/// patternField ::= ( identifier? ':' )? pattern
9414+
Token parseParenthesizedPatternOrRecordPattern(Token token) {
9415+
Token begin = token.next!;
9416+
assert(optional('(', begin));
9417+
9418+
token = begin;
9419+
int count = 0;
9420+
bool wasRecord = false;
9421+
bool wasValidRecord = false;
9422+
while (true) {
9423+
Token next = token.next!;
9424+
if ((count > 0 || wasRecord) && optional(')', next)) {
9425+
break;
9426+
}
9427+
Token? colon = null;
9428+
// TODO(paulberry): test error recovery
9429+
if (optional(':', next)) {
9430+
wasRecord = true;
9431+
wasValidRecord = true;
9432+
listener.handleNoName(token);
9433+
colon = token = next;
9434+
} else if (optional(':', next.next!) || /* recovery */
9435+
optional(':', next)) {
9436+
// Record with named expression.
9437+
wasRecord = true;
9438+
token = ensureIdentifier(
9439+
token,
9440+
IdentifierContext.namedRecordFieldReference,
9441+
).next!;
9442+
colon = token;
9443+
wasValidRecord = true;
9444+
}
9445+
token = parsePattern(token);
9446+
next = token.next!;
9447+
if (wasRecord || colon != null) {
9448+
listener.handlePatternField(colon);
9449+
}
9450+
++count;
9451+
if (!optional(',', next)) {
9452+
// TODO(paulberry): make sure to test the error case where there's a
9453+
// colon but it's not a record.
9454+
break;
9455+
} else {
9456+
// It is a comma, i.e. it's a record.
9457+
if (!wasRecord && colon == null) {
9458+
listener.handlePatternField(colon);
9459+
}
9460+
wasRecord = true;
9461+
wasValidRecord = true;
9462+
}
9463+
token = next;
9464+
}
9465+
token = ensureCloseParen(token, begin);
9466+
assert(optional(')', token));
9467+
9468+
assert(wasRecord || count <= 1);
9469+
9470+
if (wasRecord) {
9471+
if (count == 0) {
9472+
reportRecoverableError(token, codes.messageRecordLiteralEmpty);
9473+
} else if (count == 1 && !wasValidRecord) {
9474+
reportRecoverableError(
9475+
token, codes.messageRecordLiteralOnePositionalFieldNoTrailingComma);
9476+
}
9477+
listener.handleRecordPattern(begin, count);
9478+
} else {
9479+
listener.handleParenthesizedPattern(begin);
9480+
}
9481+
9482+
return token;
9483+
}
9484+
9485+
/// Parses the rest of an extractorPattern, where [token] is the token before
9486+
/// the `(`.
9487+
///
9488+
/// extractorPattern ::= extractorName typeArguments?
9489+
/// '(' patternFields? ')'
9490+
Token parseExtractorPatternRest(Token token) {
9491+
Token begin = token = token.next!;
9492+
assert(optional('(', begin));
9493+
int argumentCount = 0;
9494+
bool old = mayParseFunctionExpressions;
9495+
mayParseFunctionExpressions = true;
9496+
while (true) {
9497+
Token next = token.next!;
9498+
if (optional(')', next)) {
9499+
token = next;
9500+
break;
9501+
}
9502+
Token? colon = null;
9503+
if (optional(':', next)) {
9504+
listener.handleNoName(token);
9505+
colon = token = next;
9506+
} else if (optional(':', next.next!)) {
9507+
token =
9508+
ensureIdentifier(token, IdentifierContext.namedArgumentReference)
9509+
.next!;
9510+
colon = token;
9511+
}
9512+
token = parsePattern(token);
9513+
next = token.next!;
9514+
listener.handlePatternField(colon);
9515+
++argumentCount;
9516+
if (!optional(',', next)) {
9517+
if (optional(')', next)) {
9518+
token = next;
9519+
break;
9520+
}
9521+
// TODO(paulberry): test error recovery
9522+
// Recovery
9523+
if (looksLikeExpressionStart(next)) {
9524+
// If this looks like the start of an expression,
9525+
// then report an error, insert the comma, and continue parsing.
9526+
next = rewriteAndRecover(
9527+
token,
9528+
codes.templateExpectedButGot.withArguments(','),
9529+
new SyntheticToken(TokenType.COMMA, next.offset));
9530+
} else {
9531+
token = ensureCloseParen(token, begin);
9532+
break;
9533+
}
9534+
}
9535+
token = next;
9536+
}
9537+
assert(optional(')', token));
9538+
mayParseFunctionExpressions = old;
9539+
listener.handleExtractorPatternFields(argumentCount, begin, token);
9540+
return token;
9541+
}
94689542
}
94699543

94709544
// TODO(ahe): Remove when analyzer supports generalized function syntax.

pkg/front_end/parser_testcases/augmentation/augment_super.dart.intertwined.expect

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ parseUnit(augment)
3737
parseAugmentSuperExpression({, expression)
3838
listener: handleAugmentSuperExpression(augment, super, expression)
3939
listener: handleNoTypeArguments(()
40-
parseArguments(super, forPattern: false)
41-
parseArgumentsRest((, forPattern: false)
40+
parseArguments(super)
41+
parseArgumentsRest(()
4242
listener: beginArguments(()
4343
listener: endArguments(0, (, ))
4444
listener: handleSend(augment, ;)
@@ -335,8 +335,8 @@ parseUnit(augment)
335335
parseAugmentSuperExpression({, expression)
336336
listener: handleAugmentSuperExpression(augment, super, expression)
337337
listener: handleNoTypeArguments(()
338-
parseArguments(super, forPattern: false)
339-
parseArgumentsRest((, forPattern: false)
338+
parseArguments(super)
339+
parseArgumentsRest(()
340340
listener: beginArguments(()
341341
listener: endArguments(0, (, ))
342342
listener: handleSend(augment, ;)
@@ -469,8 +469,8 @@ parseUnit(augment)
469469
parseAugmentSuperExpression({, expression)
470470
listener: handleAugmentSuperExpression(augment, super, expression)
471471
listener: handleNoTypeArguments(()
472-
parseArguments(super, forPattern: false)
473-
parseArgumentsRest((, forPattern: false)
472+
parseArguments(super)
473+
parseArgumentsRest(()
474474
listener: beginArguments(()
475475
listener: endArguments(0, (, ))
476476
listener: handleSend(augment, ;)
@@ -746,8 +746,8 @@ parseUnit(augment)
746746
parseAugmentSuperExpression({, expression)
747747
listener: handleAugmentSuperExpression(augment, super, expression)
748748
listener: handleNoTypeArguments(()
749-
parseArguments(super, forPattern: false)
750-
parseArgumentsRest((, forPattern: false)
749+
parseArguments(super)
750+
parseArgumentsRest(()
751751
listener: beginArguments(()
752752
listener: endArguments(0, (, ))
753753
listener: handleSend(augment, ;)

pkg/front_end/parser_testcases/enhanced_enums/entries_with_type_arguments.dart.intertwined.expect

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ parseUnit(enum)
5656
listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
5757
listener: endConstructorReference(one, null, (, ConstructorReferenceContext.Const)
5858
parseConstructorInvocationArguments(>)
59-
parseArgumentsRest((, forPattern: false)
59+
parseArgumentsRest(()
6060
listener: beginArguments(()
6161
listener: endArguments(0, (, ))
6262
listener: handleEnumElement({)
@@ -79,7 +79,7 @@ parseUnit(enum)
7979
listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
8080
listener: endConstructorReference(two, null, (, ConstructorReferenceContext.Const)
8181
parseConstructorInvocationArguments(>)
82-
parseArgumentsRest((, forPattern: false)
82+
parseArgumentsRest(()
8383
listener: beginArguments(()
8484
listener: endArguments(0, (, ))
8585
listener: handleEnumElement(,)
@@ -103,7 +103,7 @@ parseUnit(enum)
103103
listener: handleIdentifier(named, constructorReferenceContinuationAfterTypeArguments)
104104
listener: endConstructorReference(three, ., (, ConstructorReferenceContext.Const)
105105
parseConstructorInvocationArguments(named)
106-
parseArgumentsRest((, forPattern: false)
106+
parseArgumentsRest(()
107107
listener: beginArguments(()
108108
parseExpression(()
109109
parsePrecedenceExpression((, 1, true)

0 commit comments

Comments
 (0)