Skip to content

Commit ef2dcd5

Browse files
kallentuCommit Queue
authored andcommitted
[parser] Initial parsing of dot shorthands.
Doing some initial work for parsing dot shorthands. The listeners in the CFE and analyzer will report an extra error if the experiment is not turned on. The compilation should still fail and produce errors, but it won't crash. If you turn on the experiment, the parsing will crash, but I'd like to get this in so I can modularly work on the CFE and analyzer separately. Bug: #59758, #59835 Change-Id: I262b0bd5cffc8e5e04ac79c76454b6e355779ade Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/409540 Reviewed-by: Jens Johansen <[email protected]> Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Kallen Tu <[email protected]> Reviewed-by: Chloe Stefantsova <[email protected]>
1 parent a0b3818 commit ef2dcd5

File tree

16 files changed

+454
-5
lines changed

16 files changed

+454
-5
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,16 @@ class ForwardingListener implements Listener {
21932193
void handleNoPrimaryConstructor(Token token, Token? constKeyword) {
21942194
listener?.handleNoPrimaryConstructor(token, constKeyword);
21952195
}
2196+
2197+
@override
2198+
void handleDotShorthandHead(Token token) {
2199+
listener?.handleDotShorthandHead(token);
2200+
}
2201+
2202+
@override
2203+
void handleDotShorthandContext(Token token) {
2204+
listener?.handleDotShorthandContext(token);
2205+
}
21962206
}
21972207

21982208
class NullListener extends ForwardingListener {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2392,4 +2392,12 @@ class Listener implements UnescapeErrorListener {
23922392
void handlePatternAssignment(Token equals) {
23932393
logEvent("PatternAssignment");
23942394
}
2395+
2396+
void handleDotShorthandContext(Token token) {
2397+
logEvent("DotShorthandContext");
2398+
}
2399+
2400+
void handleDotShorthandHead(Token token) {
2401+
logEvent('DotShorthandHead');
2402+
}
23952403
}

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5830,7 +5830,13 @@ class Parser {
58305830
bool allowCascades, ConstantPatternContext constantPatternContext) {
58315831
assert(precedence >= 1);
58325832
assert(precedence <= SELECTOR_PRECEDENCE);
5833+
5834+
bool isDotShorthand = token.next!.isA(TokenType.PERIOD) &&
5835+
(token.next!.next!.isIdentifier || token.next!.next!.isA(Keyword.NEW));
5836+
// TODO(kallentu): Once the parser handles dot shorthands by default,
5837+
// we don't need to parse for an error here.
58335838
token = parseUnaryExpression(token, allowCascades, constantPatternContext);
5839+
58345840
Token bangToken = token;
58355841
if (token.next!.isA(TokenType.BANG)) {
58365842
bangToken = token.next!;
@@ -5854,6 +5860,17 @@ class Parser {
58545860
}
58555861
}
58565862

5863+
if (isDotShorthand) {
5864+
Token dot = token.next!;
5865+
token = _parsePrecedenceExpressionLoop(SELECTOR_PRECEDENCE, allowCascades,
5866+
typeArg, token, constantPatternContext,
5867+
isDotShorthand: true);
5868+
5869+
// The entire shorthand is parsed at this point.
5870+
listener.handleDotShorthandContext(dot);
5871+
return token;
5872+
}
5873+
58575874
return _parsePrecedenceExpressionLoop(
58585875
precedence, allowCascades, typeArg, token, constantPatternContext);
58595876
}
@@ -5863,7 +5880,8 @@ class Parser {
58635880
bool allowCascades,
58645881
TypeParamOrArgInfo typeArg,
58655882
Token token,
5866-
ConstantPatternContext constantPatternContext) {
5883+
ConstantPatternContext constantPatternContext,
5884+
{bool isDotShorthand = false}) {
58675885
Token next = token.next!;
58685886
TokenType type = next.type;
58695887
int tokenLevel = _computePrecedence(next, forPattern: false);
@@ -5962,11 +5980,16 @@ class Parser {
59625980
// should just call [parseUnaryExpression] directly. However, a
59635981
// unary expression isn't legal after a period, so we call
59645982
// [parsePrimary] instead.
5965-
token = parsePrimary(
5966-
token.next!,
5967-
IdentifierContext.expressionContinuation,
5983+
Token dot = token.next!;
5984+
token = parsePrimary(dot, IdentifierContext.expressionContinuation,
59685985
constantPatternContext);
5969-
listener.handleEndingBinaryExpression(operator, token);
5986+
5987+
if (isDotShorthand) {
5988+
listener.handleDotShorthandHead(dot);
5989+
isDotShorthand = false;
5990+
} else {
5991+
listener.handleEndingBinaryExpression(operator, token);
5992+
}
59705993

59715994
Token bangToken = token;
59725995
if (token.next!.isA(TokenType.BANG)) {

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ class AstBuilder extends StackListener {
160160
/// `true` if null-aware elements is enabled
161161
final bool enableNullAwareElements;
162162

163+
/// `true` if dot-shorthands is enabled
164+
final bool enabledDotShorthands;
165+
163166
/// `true` if digit-separators is enabled.
164167
final bool _enableDigitSeparators;
165168

@@ -196,6 +199,7 @@ class AstBuilder extends StackListener {
196199
enableClassModifiers = _featureSet.isEnabled(Feature.class_modifiers),
197200
enableNullAwareElements =
198201
_featureSet.isEnabled(Feature.null_aware_elements),
202+
enabledDotShorthands = _featureSet.isEnabled(Feature.dot_shorthands),
199203
_enableDigitSeparators =
200204
_featureSet.isEnabled(Feature.digit_separators),
201205
uri = uri ?? fileUri;
@@ -4038,6 +4042,35 @@ class AstBuilder extends StackListener {
40384042
);
40394043
}
40404044

4045+
@override
4046+
void handleDotShorthandContext(Token token) {
4047+
debugEvent("DotShorthandContext");
4048+
if (!enabledDotShorthands) {
4049+
_reportFeatureNotEnabled(
4050+
feature: ExperimentalFeatures.dot_shorthands,
4051+
startToken: token,
4052+
);
4053+
}
4054+
4055+
// TODO(kallentu): Handle dot shorthands.
4056+
}
4057+
4058+
@override
4059+
void handleDotShorthandHead(Token token) {
4060+
debugEvent("DotShorthandHead");
4061+
if (!enabledDotShorthands) {
4062+
_reportFeatureNotEnabled(
4063+
feature: ExperimentalFeatures.dot_shorthands,
4064+
startToken: token,
4065+
);
4066+
4067+
// Recovery.
4068+
pop();
4069+
}
4070+
4071+
// TODO(kallentu): Handle dot shorthands.
4072+
}
4073+
40414074
@override
40424075
void handleDottedName(int count, Token firstIdentifier) {
40434076
assert(firstIdentifier.isIdentifier);

pkg/front_end/lib/src/kernel/body_builder.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9974,6 +9974,37 @@ class BodyBuilder extends StackListenerImpl
99749974
push(
99759975
forest.createPatternAssignment(equals.charOffset, pattern, expression));
99769976
}
9977+
9978+
@override
9979+
// Coverage-ignore(suite): Not run.
9980+
void handleDotShorthandContext(Token token) {
9981+
debugEvent("DotShorthandContext");
9982+
if (!libraryFeatures.dotShorthands.isEnabled) {
9983+
addProblem(
9984+
templateExperimentNotEnabledOffByDefault
9985+
.withArguments(ExperimentalFlag.dotShorthands.name),
9986+
token.offset,
9987+
token.length);
9988+
}
9989+
}
9990+
9991+
@override
9992+
// Coverage-ignore(suite): Not run.
9993+
void handleDotShorthandHead(Token token) {
9994+
debugEvent("DotShorthandHead");
9995+
if (!libraryFeatures.dotShorthands.isEnabled) {
9996+
addProblem(
9997+
templateExperimentNotEnabledOffByDefault
9998+
.withArguments(ExperimentalFlag.dotShorthands.name),
9999+
token.offset,
10000+
token.length);
10001+
10002+
// Recovery, avoid crashing with an extra selector.
10003+
pop();
10004+
}
10005+
10006+
// TODO(kallentu): Handle dot shorthands.
10007+
}
997710008
}
997810009

997910010
class Operator {

pkg/front_end/lib/src/util/parser_ast_helper.dart

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,20 @@ abstract class AbstractParserAstListener implements Listener {
32023202
new PatternAssignmentHandle(ParserAstType.HANDLE, equals: equals);
32033203
seen(data);
32043204
}
3205+
3206+
@override
3207+
void handleDotShorthandContext(Token token) {
3208+
DotShorthandContextHandle data =
3209+
new DotShorthandContextHandle(ParserAstType.HANDLE, token: token);
3210+
seen(data);
3211+
}
3212+
3213+
@override
3214+
void handleDotShorthandHead(Token token) {
3215+
DotShorthandHeadHandle data =
3216+
new DotShorthandHeadHandle(ParserAstType.HANDLE, token: token);
3217+
seen(data);
3218+
}
32053219
}
32063220

32073221
class ArgumentsBegin extends ParserAstNode {
@@ -10112,6 +10126,36 @@ class PatternAssignmentHandle extends ParserAstNode {
1011210126
R accept<R>(ParserAstVisitor<R> v) => v.visitPatternAssignmentHandle(this);
1011310127
}
1011410128

10129+
class DotShorthandContextHandle extends ParserAstNode {
10130+
final Token token;
10131+
10132+
DotShorthandContextHandle(ParserAstType type, {required this.token})
10133+
: super("DotShorthandContext", type);
10134+
10135+
@override
10136+
Map<String, Object?> get deprecatedArguments => {
10137+
"token": token,
10138+
};
10139+
10140+
@override
10141+
R accept<R>(ParserAstVisitor<R> v) => v.visitDotShorthandContextHandle(this);
10142+
}
10143+
10144+
class DotShorthandHeadHandle extends ParserAstNode {
10145+
final Token token;
10146+
10147+
DotShorthandHeadHandle(ParserAstType type, {required this.token})
10148+
: super("DotShorthandHead", type);
10149+
10150+
@override
10151+
Map<String, Object?> get deprecatedArguments => {
10152+
"token": token,
10153+
};
10154+
10155+
@override
10156+
R accept<R>(ParserAstVisitor<R> v) => v.visitDotShorthandHeadHandle(this);
10157+
}
10158+
1011510159
abstract class ParserAstVisitor<R> {
1011610160
R visitArgumentsBegin(ArgumentsBegin node);
1011710161
R visitArgumentsEnd(ArgumentsEnd node);
@@ -10506,6 +10550,8 @@ abstract class ParserAstVisitor<R> {
1050610550
R visitPatternVariableDeclarationStatementHandle(
1050710551
PatternVariableDeclarationStatementHandle node);
1050810552
R visitPatternAssignmentHandle(PatternAssignmentHandle node);
10553+
R visitDotShorthandContextHandle(DotShorthandContextHandle node);
10554+
R visitDotShorthandHeadHandle(DotShorthandHeadHandle node);
1050910555
}
1051010556

1051110557
class RecursiveParserAstVisitor implements ParserAstVisitor<void> {
@@ -11916,6 +11962,14 @@ class RecursiveParserAstVisitor implements ParserAstVisitor<void> {
1191611962
@override
1191711963
void visitPatternAssignmentHandle(PatternAssignmentHandle node) =>
1191811964
node.visitChildren(this);
11965+
11966+
@override
11967+
void visitDotShorthandContextHandle(DotShorthandContextHandle node) =>
11968+
node.visitChildren(this);
11969+
11970+
@override
11971+
void visitDotShorthandHeadHandle(DotShorthandHeadHandle node) =>
11972+
node.visitChildren(this);
1191911973
}
1192011974

1192111975
class RecursiveParserAstVisitorWithDefaultNodeAsync
@@ -13404,4 +13458,12 @@ class RecursiveParserAstVisitorWithDefaultNodeAsync
1340413458
@override
1340513459
Future<void> visitPatternAssignmentHandle(PatternAssignmentHandle node) =>
1340613460
defaultNode(node);
13461+
13462+
@override
13463+
Future<void> visitDotShorthandContextHandle(DotShorthandContextHandle node) =>
13464+
defaultNode(node);
13465+
13466+
@override
13467+
Future<void> visitDotShorthandHeadHandle(DotShorthandHeadHandle node) =>
13468+
defaultNode(node);
1340713469
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
enum Color { red, blue, green }
2+
3+
void main() {
4+
Color c = .red;
5+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
Problems reported:
2+
3+
parser/dot_shorthands/syntax:4:13: Expected an identifier, but got '.'.
4+
Color c = .red;
5+
^
6+
7+
beginCompilationUnit(enum)
8+
beginMetadataStar(enum)
9+
endMetadataStar(0)
10+
beginUncategorizedTopLevelDeclaration(enum)
11+
handleIdentifier(Color, enumDeclaration)
12+
beginEnum(enum)
13+
handleNoTypeVariables({)
14+
handleEnumNoWithClause()
15+
handleImplements(null, 0)
16+
handleEnumHeader(null, enum, {)
17+
beginMetadataStar(red)
18+
endMetadataStar(0)
19+
handleIdentifier(red, enumValueDeclaration)
20+
handleNoTypeNameInConstructorReference(,)
21+
beginConstructorReference(red)
22+
handleNoTypeArguments(,)
23+
handleNoConstructorReferenceContinuationAfterTypeArguments(red)
24+
endConstructorReference(red, null, red, ConstructorReferenceContext.Const)
25+
handleNoArguments(red)
26+
handleEnumElement({, null)
27+
beginMetadataStar(blue)
28+
endMetadataStar(0)
29+
handleIdentifier(blue, enumValueDeclaration)
30+
handleNoTypeNameInConstructorReference(,)
31+
beginConstructorReference(blue)
32+
handleNoTypeArguments(,)
33+
handleNoConstructorReferenceContinuationAfterTypeArguments(blue)
34+
endConstructorReference(blue, null, blue, ConstructorReferenceContext.Const)
35+
handleNoArguments(blue)
36+
handleEnumElement(,, null)
37+
beginMetadataStar(green)
38+
endMetadataStar(0)
39+
handleIdentifier(green, enumValueDeclaration)
40+
handleNoTypeNameInConstructorReference(})
41+
beginConstructorReference(green)
42+
handleNoTypeArguments(})
43+
handleNoConstructorReferenceContinuationAfterTypeArguments(green)
44+
endConstructorReference(green, null, green, ConstructorReferenceContext.Const)
45+
handleNoArguments(green)
46+
handleEnumElement(,, null)
47+
handleEnumElements(}, 3)
48+
endEnum(enum, enum, {, 0, })
49+
endTopLevelDeclaration(})
50+
beginMetadataStar(void)
51+
endMetadataStar(0)
52+
beginTopLevelMember(void)
53+
beginTopLevelMethod(}, null, null)
54+
handleVoidKeyword(void)
55+
handleIdentifier(main, topLevelFunctionDeclaration)
56+
handleNoTypeVariables(()
57+
beginFormalParameters((, MemberKind.TopLevelMethod)
58+
endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
59+
handleAsyncModifier(null, null)
60+
beginBlockFunctionBody({)
61+
beginMetadataStar(Color)
62+
endMetadataStar(0)
63+
handleIdentifier(Color, typeReference)
64+
handleNoTypeArguments(c)
65+
handleType(Color, null)
66+
beginVariablesDeclaration(c, null, null)
67+
handleIdentifier(c, localVariableDeclaration)
68+
beginInitializedIdentifier(c)
69+
beginVariableInitializer(=)
70+
handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got '.'., Try inserting an identifier before '.'., {lexeme: .}], ., .)
71+
handleIdentifier(, expression)
72+
handleNoTypeArguments(.)
73+
handleNoArguments(.)
74+
handleSend(, )
75+
handleIdentifier(red, expressionContinuation)
76+
handleNoTypeArguments(;)
77+
handleNoArguments(;)
78+
handleSend(red, red)
79+
handleDotShorthandHead(.)
80+
handleDotShorthandContext(.)
81+
endVariableInitializer(=)
82+
endInitializedIdentifier(c)
83+
endVariablesDeclaration(1, ;)
84+
endBlockFunctionBody(1, {, })
85+
endTopLevelMethod(void, null, })
86+
endTopLevelDeclaration(})
87+
endCompilationUnit(2, )

0 commit comments

Comments
 (0)