@@ -6112,23 +6112,14 @@ class Parser {
6112
6112
return token;
6113
6113
}
6114
6114
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.
6121
6118
Token parseParenthesizedExpressionOrRecordLiteral (
6122
- Token token, Token ? constKeywordForRecord,
6123
- {bool forPattern = false }) {
6124
- if (forPattern) {
6125
- assert (constKeywordForRecord == null );
6126
- }
6119
+ Token token, Token ? constKeywordForRecord) {
6127
6120
Token begin = token.next! ;
6128
6121
assert (optional ('(' , begin));
6129
- if (! forPattern) {
6130
- listener.beginParenthesizedExpressionOrRecordLiteral (begin);
6131
- }
6122
+ listener.beginParenthesizedExpressionOrRecordLiteral (begin);
6132
6123
6133
6124
// For parsing of parenthesized expression we need parity with
6134
6125
// parseExpressionInParenthesisRest used in ensureParenthesizedCondition.
@@ -6143,13 +6134,7 @@ class Parser {
6143
6134
break ;
6144
6135
}
6145
6136
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)) {
6153
6138
// Record with named expression.
6154
6139
wasRecord = true ;
6155
6140
token = ensureIdentifier (
@@ -6159,30 +6144,15 @@ class Parser {
6159
6144
colon = token;
6160
6145
wasValidRecord = true ;
6161
6146
}
6162
- if (forPattern) {
6163
- token = parsePattern (token);
6164
- } else {
6165
- token = parseExpression (token);
6166
- }
6147
+ token = parseExpression (token);
6167
6148
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);
6175
6150
++ count;
6176
6151
if (! optional (',' , next)) {
6177
6152
// 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).
6180
6153
break ;
6181
6154
} else {
6182
6155
// It is a comma, i.e. it's a record.
6183
- if (forPattern && ! wasRecord && colon == null ) {
6184
- listener.handlePatternField (colon);
6185
- }
6186
6156
wasRecord = true ;
6187
6157
wasValidRecord = true ;
6188
6158
}
@@ -6200,17 +6170,9 @@ class Parser {
6200
6170
reportRecoverableError (
6201
6171
token, codes.messageRecordLiteralOnePositionalFieldNoTrailingComma);
6202
6172
}
6203
- if (forPattern) {
6204
- listener.handleRecordPattern (begin, count);
6205
- } else {
6206
- listener.endRecordLiteral (begin, count, constKeywordForRecord);
6207
- }
6173
+ listener.endRecordLiteral (begin, count, constKeywordForRecord);
6208
6174
} else {
6209
- if (forPattern) {
6210
- listener.handleParenthesizedPattern (begin);
6211
- } else {
6212
- listener.endParenthesizedExpression (begin);
6213
- }
6175
+ listener.endParenthesizedExpression (begin);
6214
6176
}
6215
6177
6216
6178
return token;
@@ -7063,21 +7025,15 @@ class Parser {
7063
7025
/// label expression
7064
7026
/// ;
7065
7027
/// ```
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! );
7071
7030
}
7072
7031
7073
7032
/// 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) {
7076
7034
Token begin = token;
7077
7035
assert (optional ('(' , begin));
7078
- if (! forPattern) {
7079
- listener.beginArguments (begin);
7080
- }
7036
+ listener.beginArguments (begin);
7081
7037
int argumentCount = 0 ;
7082
7038
bool old = mayParseFunctionExpressions;
7083
7039
mayParseFunctionExpressions = true ;
@@ -7088,27 +7044,15 @@ class Parser {
7088
7044
break ;
7089
7045
}
7090
7046
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)) {
7096
7048
token =
7097
7049
ensureIdentifier (token, IdentifierContext .namedArgumentReference)
7098
7050
.next! ;
7099
7051
colon = token;
7100
7052
}
7101
- if (forPattern) {
7102
- token = parsePattern (token);
7103
- } else {
7104
- token = parseExpression (token);
7105
- }
7053
+ token = parseExpression (token);
7106
7054
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);
7112
7056
++ argumentCount;
7113
7057
if (! optional (',' , next)) {
7114
7058
if (optional (')' , next)) {
@@ -7132,11 +7076,7 @@ class Parser {
7132
7076
}
7133
7077
assert (optional (')' , token));
7134
7078
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);
7140
7080
return token;
7141
7081
}
7142
7082
@@ -9234,8 +9174,7 @@ class Parser {
9234
9174
listener.handleRecordPattern (next, /* count = */ 0 );
9235
9175
return nextNext;
9236
9176
} else {
9237
- return parseParenthesizedExpressionOrRecordLiteral (token, null ,
9238
- forPattern: true );
9177
+ return parseParenthesizedPatternOrRecordPattern (token);
9239
9178
}
9240
9179
case 'const' :
9241
9180
// constantPattern ::= booleanLiteral
@@ -9297,7 +9236,7 @@ class Parser {
9297
9236
if (optional ('(' , afterToken) && ! potentialTypeArg.recovered) {
9298
9237
TypeParamOrArgInfo typeArg = potentialTypeArg;
9299
9238
token = typeArg.parseArguments (token, this );
9300
- token = parseArguments (token, forPattern : true );
9239
+ token = parseExtractorPatternRest (token);
9301
9240
listener.handleExtractorPattern (firstIdentifier, dot, secondIdentifier);
9302
9241
return token;
9303
9242
}
@@ -9465,6 +9404,141 @@ class Parser {
9465
9404
}
9466
9405
}
9467
9406
}
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
+ }
9468
9542
}
9469
9543
9470
9544
// TODO(ahe): Remove when analyzer supports generalized function syntax.
0 commit comments