Skip to content

Commit 0083afa

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[parser] Make NullAwareEntry to be treated as a direct entry
Previously NullAwareEntry set the hasEntry property to false, which meant that it relied on a nested entry element to handle the rest of its contents. However, according to the grammar for null-aware elements (see https://github.com/dart-lang/language/blob/main/accepted/future-releases/0323-null-aware-elements/feature-specification.md#syntax), null-aware elements and entries are leaf nodes and can only contain expressions. This CL also fixes some crashes in the CFE that expects the map entries appearing in lists to be handled by the parser. Change-Id: I3d7a3f3e8507a2ef8a290e51b49e4749260dfcda Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/389900 Commit-Queue: Chloe Stefantsova <[email protected]> Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 307e5a6 commit 0083afa

File tree

8 files changed

+121
-85
lines changed

8 files changed

+121
-85
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'parser_impl.dart';
1010
/// [simpleEntry] is the first step for parsing a literal entry
1111
/// without any control flow or spread collection operator.
1212
const LiteralEntryInfo simpleEntry =
13-
const LiteralEntryInfo(/* hasEntry = */ true, /* ifConditionDelta = */ 0);
13+
const LiteralEntryInfo(hasEntry: true, ifConditionDelta: 0);
1414

1515
/// [LiteralEntryInfo] represents steps for processing an entry
1616
/// in a literal list, map, or set. These steps will handle parsing
@@ -39,7 +39,8 @@ class LiteralEntryInfo {
3939
/// +1 for an `if` condition and -1 for `else`.
4040
final int ifConditionDelta;
4141

42-
const LiteralEntryInfo(this.hasEntry, this.ifConditionDelta);
42+
const LiteralEntryInfo(
43+
{required this.hasEntry, required this.ifConditionDelta});
4344

4445
/// Parse the control flow and spread collection aspects of this entry.
4546
Token parse(Token token, Parser parser) {

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

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const NullAwareEntry nullAwareEntry = const NullAwareEntry();
2424
class ForCondition extends LiteralEntryInfo {
2525
bool _inStyle = false;
2626

27-
ForCondition() : super(false, 0);
27+
ForCondition() : super(hasEntry: false, ifConditionDelta: 0);
2828

2929
@override
3030
Token parse(Token token, Parser parser) {
@@ -125,7 +125,7 @@ class ForInSpread extends SpreadOperator {
125125
/// A step for parsing a literal list, set, or map entry
126126
/// as the "for" control flow's expression.
127127
class ForEntry extends LiteralEntryInfo {
128-
const ForEntry() : super(true, 0);
128+
const ForEntry() : super(hasEntry: true, ifConditionDelta: 0);
129129

130130
@override
131131
LiteralEntryInfo computeNext(Token token) {
@@ -136,7 +136,7 @@ class ForEntry extends LiteralEntryInfo {
136136
/// A step for parsing a literal list, set, or map entry
137137
/// as the "for-in" control flow's expression.
138138
class ForInEntry extends LiteralEntryInfo {
139-
const ForInEntry() : super(true, 0);
139+
const ForInEntry() : super(hasEntry: true, ifConditionDelta: 0);
140140

141141
@override
142142
LiteralEntryInfo computeNext(Token token) {
@@ -145,7 +145,7 @@ class ForInEntry extends LiteralEntryInfo {
145145
}
146146

147147
class ForComplete extends LiteralEntryInfo {
148-
const ForComplete() : super(false, 0);
148+
const ForComplete() : super(hasEntry: false, ifConditionDelta: 0);
149149

150150
@override
151151
Token parse(Token token, Parser parser) {
@@ -155,7 +155,7 @@ class ForComplete extends LiteralEntryInfo {
155155
}
156156

157157
class ForInComplete extends LiteralEntryInfo {
158-
const ForInComplete() : super(false, 0);
158+
const ForInComplete() : super(hasEntry: false, ifConditionDelta: 0);
159159

160160
@override
161161
Token parse(Token token, Parser parser) {
@@ -166,7 +166,7 @@ class ForInComplete extends LiteralEntryInfo {
166166

167167
/// The first step when processing an `if` control flow collection entry.
168168
class IfCondition extends LiteralEntryInfo {
169-
const IfCondition() : super(false, 1);
169+
const IfCondition() : super(hasEntry: false, ifConditionDelta: 1);
170170

171171
@override
172172
Token parse(Token token, Parser parser) {
@@ -209,14 +209,14 @@ class IfSpread extends SpreadOperator {
209209
/// A step for parsing a literal list, set, or map entry
210210
/// as the `if` control flow's then-expression.
211211
class IfEntry extends LiteralEntryInfo {
212-
const IfEntry() : super(true, 0);
212+
const IfEntry() : super(hasEntry: true, ifConditionDelta: 0);
213213

214214
@override
215215
LiteralEntryInfo computeNext(Token token) => const IfComplete();
216216
}
217217

218218
class IfComplete extends LiteralEntryInfo {
219-
const IfComplete() : super(false, 0);
219+
const IfComplete() : super(hasEntry: false, ifConditionDelta: 0);
220220

221221
@override
222222
Token parse(Token token, Parser parser) {
@@ -234,7 +234,7 @@ class IfComplete extends LiteralEntryInfo {
234234

235235
/// A step for parsing the `else` portion of an `if` control flow.
236236
class IfElse extends LiteralEntryInfo {
237-
const IfElse() : super(false, -1);
237+
const IfElse() : super(hasEntry: false, ifConditionDelta: -1);
238238

239239
@override
240240
Token parse(Token token, Parser parser) {
@@ -273,7 +273,7 @@ class ElseSpread extends SpreadOperator {
273273
}
274274

275275
class ElseEntry extends LiteralEntryInfo {
276-
const ElseEntry() : super(true, 0);
276+
const ElseEntry() : super(hasEntry: true, ifConditionDelta: 0);
277277

278278
@override
279279
LiteralEntryInfo computeNext(Token token) {
@@ -282,7 +282,7 @@ class ElseEntry extends LiteralEntryInfo {
282282
}
283283

284284
class IfElseComplete extends LiteralEntryInfo {
285-
const IfElseComplete() : super(false, 0);
285+
const IfElseComplete() : super(hasEntry: false, ifConditionDelta: 0);
286286

287287
@override
288288
Token parse(Token token, Parser parser) {
@@ -293,7 +293,7 @@ class IfElseComplete extends LiteralEntryInfo {
293293

294294
/// The first step when processing a spread entry.
295295
class SpreadOperator extends LiteralEntryInfo {
296-
const SpreadOperator() : super(false, 0);
296+
const SpreadOperator() : super(hasEntry: false, ifConditionDelta: 0);
297297

298298
@override
299299
Token parse(Token token, Parser parser) {
@@ -310,7 +310,8 @@ class Nested extends LiteralEntryInfo {
310310
LiteralEntryInfo? nestedStep;
311311
final LiteralEntryInfo lastStep;
312312

313-
Nested(this.nestedStep, this.lastStep) : super(false, 0);
313+
Nested(this.nestedStep, this.lastStep)
314+
: super(hasEntry: false, ifConditionDelta: 0);
314315

315316
@override
316317
bool get hasEntry => nestedStep!.hasEntry;
@@ -326,28 +327,5 @@ class Nested extends LiteralEntryInfo {
326327
}
327328

328329
class NullAwareEntry extends LiteralEntryInfo {
329-
const NullAwareEntry() : super(false, 0);
330-
331-
@override
332-
Token parse(Token token, Parser parser) {
333-
final Token entryNullAwareToken = token.next!;
334-
assert(entryNullAwareToken.isA(TokenType.QUESTION));
335-
token = parser.parseExpression(entryNullAwareToken);
336-
if (token.next!.isA(TokenType.COLON)) {
337-
Token colon = token.next!;
338-
Token next = colon.next!;
339-
if (next.isA(TokenType.QUESTION)) {
340-
token = parser.parseExpression(next);
341-
parser.listener.handleLiteralMapEntry(colon, token,
342-
nullAwareKeyToken: entryNullAwareToken, nullAwareValueToken: next);
343-
} else {
344-
token = parser.parseExpression(colon);
345-
parser.listener.handleLiteralMapEntry(colon, token,
346-
nullAwareKeyToken: entryNullAwareToken, nullAwareValueToken: null);
347-
}
348-
} else {
349-
parser.listener.handleNullAwareElement(entryNullAwareToken);
350-
}
351-
return token;
352-
}
330+
const NullAwareEntry() : super(hasEntry: true, ifConditionDelta: 0);
353331
}

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

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6963,7 +6963,14 @@ class Parser {
69636963
LiteralEntryInfo? info = computeLiteralEntry(token);
69646964
while (info != null) {
69656965
if (info.hasEntry) {
6966-
token = parseExpression(token);
6966+
if (token.next!.isA(TokenType.QUESTION)) {
6967+
Token nullAwareToken = token.next!;
6968+
token = token.next!;
6969+
token = parseExpression(token);
6970+
listener.handleNullAwareElement(nullAwareToken);
6971+
} else {
6972+
token = parseExpression(token);
6973+
}
69676974
} else {
69686975
token = info.parse(token, this);
69696976
}
@@ -7054,21 +7061,43 @@ class Parser {
70547061
} else {
70557062
while (info != null) {
70567063
if (info.hasEntry) {
7057-
token = parseExpression(token);
7064+
Token? nullAwareKeyToken;
7065+
if (token.next!.isA(TokenType.QUESTION)) {
7066+
// Null-aware key, for example:
7067+
// <double, Symbol>{ if (b) ?x: y }
7068+
// <double, Symbol>{ if (b) ?x: ?y }
7069+
nullAwareKeyToken = token.next!;
7070+
7071+
// Parse the expression after '?'.
7072+
token = nullAwareKeyToken;
7073+
token = parseExpression(token);
7074+
} else {
7075+
token = parseExpression(token);
7076+
}
70587077
if (token.next!.isA(TokenType.COLON)) {
70597078
Token colon = token.next!;
70607079
Token next = colon.next!;
70617080
if (next.isA(TokenType.QUESTION)) {
70627081
token = parseExpression(next);
70637082
// Null-aware value. For example:
70647083
// <double, Symbol>{ if (b) x: ?y }
7065-
listener.handleLiteralMapEntry(colon, token,
7066-
nullAwareKeyToken: null, nullAwareValueToken: next);
7084+
// <double, Symbol>{ if (b) ?x: ?y }
7085+
listener.handleLiteralMapEntry(colon, token.next!,
7086+
nullAwareKeyToken: nullAwareKeyToken,
7087+
nullAwareValueToken: next);
70677088
} else {
7068-
// Non null-aware entry. For example:
7089+
// Non null-aware value. For example:
70697090
// <String, int>{ if (b) x : y }
7091+
// <String, int>{ if (b) ?x : y }
70707092
token = parseExpression(colon);
7071-
listener.handleLiteralMapEntry(colon, token.next!);
7093+
listener.handleLiteralMapEntry(colon, token.next!,
7094+
nullAwareKeyToken: nullAwareKeyToken);
7095+
}
7096+
} else {
7097+
if (nullAwareKeyToken != null) {
7098+
// Null-aware element. For example:
7099+
// <String>{ if (b) ?x }
7100+
listener.handleNullAwareElement(nullAwareKeyToken);
70727101
}
70737102
}
70747103
} else {

pkg/front_end/parser_testcases/null_aware_elements/nested.dart.expect

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ beginCompilationUnit(test1)
484484
handleSend(a, :)
485485
beginLiteralString("value")
486486
endLiteralString(0, })
487-
handleLiteralMapEntry(:, "value", ?, null)
487+
handleLiteralMapEntry(:, }, ?, null)
488488
endIfControlFlow("value")
489489
endForInControlFlow("value")
490490
handleLiteralSetOrMap(1, {, null, }, false)
@@ -591,15 +591,15 @@ beginCompilationUnit(test1)
591591
handleSend(a, :)
592592
beginLiteralString("value")
593593
endLiteralString(0, else)
594-
handleLiteralMapEntry(:, "value", ?, null)
594+
handleLiteralMapEntry(:, else, ?, null)
595595
handleElseControlFlow(else)
596596
handleIdentifier(b, expression)
597597
handleNoTypeArguments(:)
598598
handleNoArguments(:)
599599
handleSend(b, :)
600600
beginLiteralString("value")
601601
endLiteralString(0, })
602-
handleLiteralMapEntry(:, "value", ?, null)
602+
handleLiteralMapEntry(:, }, ?, null)
603603
endIfElseControlFlow("value")
604604
endForInControlFlow("value")
605605
handleLiteralSetOrMap(1, {, null, }, false)
@@ -678,7 +678,7 @@ beginCompilationUnit(test1)
678678
handleSend(a, :)
679679
beginLiteralString("value")
680680
endLiteralString(0, })
681-
handleLiteralMapEntry(:, "value", ?, null)
681+
handleLiteralMapEntry(:, }, ?, null)
682682
endForInControlFlow("value")
683683
endIfControlFlow("value")
684684
handleLiteralSetOrMap(1, {, null, }, false)
@@ -766,7 +766,7 @@ beginCompilationUnit(test1)
766766
handleSend(a, :)
767767
beginLiteralString("value")
768768
endLiteralString(0, else)
769-
handleLiteralMapEntry(:, "value", ?, null)
769+
handleLiteralMapEntry(:, else, ?, null)
770770
endForInControlFlow("value")
771771
handleElseControlFlow(else)
772772
beginForControlFlow(null, for)
@@ -793,7 +793,7 @@ beginCompilationUnit(test1)
793793
handleSend(b, :)
794794
beginLiteralString("value")
795795
endLiteralString(0, })
796-
handleLiteralMapEntry(:, "value", ?, null)
796+
handleLiteralMapEntry(:, }, ?, null)
797797
endForInControlFlow("value")
798798
endIfElseControlFlow("value")
799799
handleLiteralSetOrMap(1, {, null, }, false)
@@ -891,7 +891,7 @@ beginCompilationUnit(test1)
891891
handleNoTypeArguments(})
892892
handleNoArguments(})
893893
handleSend(a, })
894-
handleLiteralMapEntry(:, a, null, ?)
894+
handleLiteralMapEntry(:, }, null, ?)
895895
endIfControlFlow(a)
896896
endForInControlFlow(a)
897897
handleLiteralSetOrMap(1, {, null, }, false)
@@ -998,15 +998,15 @@ beginCompilationUnit(test1)
998998
handleNoTypeArguments(else)
999999
handleNoArguments(else)
10001000
handleSend(a, else)
1001-
handleLiteralMapEntry(:, a, null, ?)
1001+
handleLiteralMapEntry(:, else, null, ?)
10021002
handleElseControlFlow(else)
10031003
beginLiteralString("key")
10041004
endLiteralString(0, :)
10051005
handleIdentifier(b, expression)
10061006
handleNoTypeArguments(})
10071007
handleNoArguments(})
10081008
handleSend(b, })
1009-
handleLiteralMapEntry(:, b, null, ?)
1009+
handleLiteralMapEntry(:, }, null, ?)
10101010
endIfElseControlFlow(b)
10111011
endForInControlFlow(b)
10121012
handleLiteralSetOrMap(1, {, null, }, false)
@@ -1085,7 +1085,7 @@ beginCompilationUnit(test1)
10851085
handleNoTypeArguments(})
10861086
handleNoArguments(})
10871087
handleSend(a, })
1088-
handleLiteralMapEntry(:, a, null, ?)
1088+
handleLiteralMapEntry(:, }, null, ?)
10891089
endForInControlFlow(a)
10901090
endIfControlFlow(a)
10911091
handleLiteralSetOrMap(1, {, null, }, false)
@@ -1173,7 +1173,7 @@ beginCompilationUnit(test1)
11731173
handleNoTypeArguments(else)
11741174
handleNoArguments(else)
11751175
handleSend(a, else)
1176-
handleLiteralMapEntry(:, a, null, ?)
1176+
handleLiteralMapEntry(:, else, null, ?)
11771177
endForInControlFlow(a)
11781178
handleElseControlFlow(else)
11791179
beginForControlFlow(null, for)
@@ -1200,7 +1200,7 @@ beginCompilationUnit(test1)
12001200
handleNoTypeArguments(})
12011201
handleNoArguments(})
12021202
handleSend(b, })
1203-
handleLiteralMapEntry(:, b, null, ?)
1203+
handleLiteralMapEntry(:, }, null, ?)
12041204
endForInControlFlow(b)
12051205
endIfElseControlFlow(b)
12061206
handleLiteralSetOrMap(1, {, null, }, false)

0 commit comments

Comments
 (0)