Skip to content

Commit 6834894

Browse files
authored
libSyntax: parse declaration attribute list (@attributes). (#13212)
This commit starts to support syntax nodes for @ attributes list for declarations. These attributes don't include modifiers like "static" or access keywords. Along with the function change, the commit refactors some existing code to reduce duplication.
1 parent 5495392 commit 6834894

File tree

5 files changed

+91
-93
lines changed

5 files changed

+91
-93
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 52 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,11 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
512512
// Ok, it is a valid attribute, eat it, and then process it.
513513
StringRef AttrName = Tok.getText();
514514
SourceLoc Loc = consumeToken();
515+
516+
// We can only make this attribute a token list intead of an Attribute node
517+
// because the attribute node may include '@'
518+
SyntaxParsingContext TokListContext(SyntaxContext, SyntaxKind::TokenList);
519+
515520
bool DiscardAttribute = false;
516521

517522
// Diagnose duplicated attributes.
@@ -1853,17 +1858,21 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
18531858
bool Parser::parseDeclAttributeList(DeclAttributes &Attributes,
18541859
bool &FoundCCToken) {
18551860
FoundCCToken = false;
1856-
while (Tok.is(tok::at_sign)) {
1861+
if (Tok.isNot(tok::at_sign))
1862+
return false;
1863+
SyntaxParsingContext AttrListCtx(SyntaxContext, SyntaxKind::AttributeList);
1864+
do {
18571865
if (peekToken().is(tok::code_complete)) {
18581866
consumeToken(tok::at_sign);
18591867
consumeToken(tok::code_complete);
18601868
FoundCCToken = true;
18611869
continue;
18621870
}
1871+
SyntaxParsingContext AttrCtx(SyntaxContext, SyntaxKind::Attribute);
18631872
SourceLoc AtLoc = consumeToken();
18641873
if (parseDeclAttribute(Attributes, AtLoc))
18651874
return true;
1866-
}
1875+
} while (Tok.is(tok::at_sign));
18671876
return false;
18681877
}
18691878

@@ -2263,7 +2272,7 @@ Parser::parseDecl(ParseDeclOptions Flags,
22632272

22642273
switch (Tok.getKind()) {
22652274
// Modifiers
2266-
case tok::kw_static:
2275+
case tok::kw_static: {
22672276
if (StaticLoc.isValid()) {
22682277
diagnose(Tok, diag::decl_already_static,
22692278
StaticSpellingKind::KeywordStatic)
@@ -2275,7 +2284,7 @@ Parser::parseDecl(ParseDeclOptions Flags,
22752284
}
22762285
consumeToken(tok::kw_static);
22772286
continue;
2278-
2287+
}
22792288
// 'class' is a modifier on func, but is also a top-level decl.
22802289
case tok::kw_class: {
22812290
SourceLoc ClassLoc = consumeToken(tok::kw_class);
@@ -2302,84 +2311,58 @@ Parser::parseDecl(ParseDeclOptions Flags,
23022311
case tok::kw_private:
23032312
case tok::kw_fileprivate:
23042313
case tok::kw_internal:
2305-
case tok::kw_public:
2314+
case tok::kw_public: {
23062315
// We still model these specifiers as attributes.
23072316
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_AccessControl);
23082317
continue;
2309-
2318+
}
23102319
// Context sensitive keywords.
2311-
case tok::identifier:
2320+
case tok::identifier: {
2321+
Optional<DeclAttrKind> Kind;
23122322
// FIXME: This is ridiculous, this all needs to be sucked into the
23132323
// declparsing goop.
23142324
if (Tok.isContextualKeyword("open")) {
2315-
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_AccessControl);
2316-
continue;
2317-
}
2318-
if (Tok.isContextualKeyword("weak") ||
2319-
Tok.isContextualKeyword("unowned")) {
2320-
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Ownership);
2321-
continue;
2322-
}
2323-
if (Tok.isContextualKeyword("optional")) {
2324-
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Optional);
2325-
continue;
2326-
}
2327-
if (Tok.isContextualKeyword("required")) {
2328-
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Required);
2329-
continue;
2330-
}
2331-
if (Tok.isContextualKeyword("lazy")) {
2332-
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Lazy);
2333-
continue;
2334-
}
2335-
if (Tok.isContextualKeyword("final")) {
2336-
parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Final);
2337-
continue;
2338-
}
2339-
if (Tok.isContextualKeyword("dynamic")) {
2340-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Dynamic);
2341-
continue;
2342-
}
2343-
if (Tok.isContextualKeyword("prefix")) {
2344-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Prefix);
2345-
continue;
2346-
}
2347-
if (Tok.isContextualKeyword("postfix")) {
2348-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Postfix);
2349-
continue;
2350-
}
2351-
if (Tok.isContextualKeyword("indirect")) {
2352-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Indirect);
2353-
continue;
2354-
}
2355-
if (Tok.isContextualKeyword("infix")) {
2356-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Infix);
2357-
continue;
2358-
}
2359-
if (Tok.isContextualKeyword("override")) {
2360-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Override);
2361-
continue;
2362-
}
2363-
if (Tok.isContextualKeyword("mutating")) {
2364-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Mutating);
2365-
continue;
2366-
}
2367-
if (Tok.isContextualKeyword("nonmutating")) {
2368-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_NonMutating);
2369-
continue;
2370-
}
2371-
if (Tok.isContextualKeyword("__consuming")) {
2372-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Consuming);
2373-
continue;
2325+
Kind = DAK_AccessControl;
2326+
} else if (Tok.isContextualKeyword("weak") ||
2327+
Tok.isContextualKeyword("unowned")) {
2328+
Kind = DAK_Ownership;
2329+
} else if (Tok.isContextualKeyword("optional")) {
2330+
Kind = DAK_Optional;
2331+
} else if (Tok.isContextualKeyword("required")) {
2332+
Kind = DAK_Required;
2333+
} else if (Tok.isContextualKeyword("lazy")) {
2334+
Kind = DAK_Lazy;
2335+
} else if (Tok.isContextualKeyword("final")) {
2336+
Kind = DAK_Final;
2337+
} else if (Tok.isContextualKeyword("dynamic")) {
2338+
Kind = DAK_Dynamic;
2339+
} else if (Tok.isContextualKeyword("prefix")) {
2340+
Kind = DAK_Prefix;
2341+
} else if (Tok.isContextualKeyword("postfix")) {
2342+
Kind = DAK_Postfix;
2343+
} else if (Tok.isContextualKeyword("indirect")) {
2344+
Kind = DAK_Indirect;
2345+
} else if (Tok.isContextualKeyword("infix")) {
2346+
Kind = DAK_Infix;
2347+
} else if (Tok.isContextualKeyword("override")) {
2348+
Kind = DAK_Override;
2349+
} else if (Tok.isContextualKeyword("mutating")) {
2350+
Kind = DAK_Mutating;
2351+
} else if (Tok.isContextualKeyword("nonmutating")) {
2352+
Kind = DAK_NonMutating;
2353+
} else if (Tok.isContextualKeyword("__consuming")) {
2354+
Kind = DAK_Consuming;
2355+
} else if (Tok.isContextualKeyword("convenience")) {
2356+
Kind = DAK_Convenience;
23742357
}
2375-
if (Tok.isContextualKeyword("convenience")) {
2376-
parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Convenience);
2358+
if (Kind) {
2359+
parseNewDeclAttribute(Attributes, SourceLoc(), *Kind);
23772360
continue;
23782361
}
23792362

23802363
// Otherwise this is not a context-sensitive keyword.
23812364
LLVM_FALLTHROUGH;
2382-
2365+
}
23832366
case tok::pound_if:
23842367
case tok::pound_sourceLocation:
23852368
case tok::pound_line:

test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,13 @@ struct foo <MemberDeclBlock>{
7474
}</MemberDeclBlock>
7575
struct foo <MemberDeclBlock>{}</MemberDeclBlock>
7676
}</MemberDeclBlock>
77+
78+
struct foo <MemberDeclBlock>{<Attribute>
79+
@available(*, unavailable)</Attribute>
80+
struct foo <MemberDeclBlock>{}</MemberDeclBlock>
81+
public class foo {<Attribute>
82+
@available(*, unavailable)</Attribute><Attribute>
83+
@objc(fooObjc)</Attribute>
84+
private static func foo() <CodeBlock>{}</CodeBlock>
85+
}
86+
}</MemberDeclBlock>

test/Syntax/round_trip_parse_gen.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,13 @@ struct foo {
7474
}
7575
struct foo {}
7676
}
77+
78+
struct foo {
79+
@available(*, unavailable)
80+
struct foo {}
81+
public class foo {
82+
@available(*, unavailable)
83+
@objc(fooObjc)
84+
private static func foo() {}
85+
}
86+
}

unittests/Syntax/TypeSyntaxTests.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ TEST(TypeSyntaxTests, TypeAttributeWithAPIs) {
1919
llvm::raw_svector_ostream OS { Scratch };
2020
auto Autoclosure = SyntaxFactory::makeBlankAttribute()
2121
.withAtSignToken(At)
22-
.withIdentifier(AutoclosureID);
22+
.withAttributeName(AutoclosureID);
2323
Autoclosure.print(OS);
2424
ASSERT_EQ(OS.str().str(), "@autoclosure");
2525
}
@@ -31,15 +31,14 @@ TEST(TypeSyntaxTests, TypeAttributeWithAPIs) {
3131

3232
auto Convention = SyntaxFactory::makeBlankAttribute()
3333
.withAtSignToken(At)
34-
.withIdentifier(conventionID)
35-
.withLeftParen(LeftParen)
36-
.withRightParen(RightParen);
34+
.withAttributeName(conventionID)
35+
.withBalancedTokens(SyntaxFactory::makeTokenList({LeftParen, RightParen}));
3736

3837
{
3938
SmallString<48> Scratch;
4039
llvm::raw_svector_ostream OS { Scratch };
4140
auto cID = SyntaxFactory::makeIdentifier("c", {}, {});
42-
auto cArgs = SyntaxFactory::makeTokenList({cID});
41+
auto cArgs = SyntaxFactory::makeTokenList({LeftParen, cID, RightParen});
4342
Convention.withBalancedTokens(cArgs).print(OS);
4443
ASSERT_EQ(OS.str().str(), "@convention(c)");
4544
}
@@ -48,7 +47,7 @@ TEST(TypeSyntaxTests, TypeAttributeWithAPIs) {
4847
SmallString<48> Scratch;
4948
llvm::raw_svector_ostream OS { Scratch };
5049
auto swiftID = SyntaxFactory::makeIdentifier("swift", {}, {});
51-
auto swiftArgs = SyntaxFactory::makeTokenList({swiftID});
50+
auto swiftArgs = SyntaxFactory::makeTokenList({LeftParen, swiftID, RightParen});
5251
Convention.withBalancedTokens(swiftArgs).print(OS);
5352
ASSERT_EQ(OS.str().str(), "@convention(swift)");
5453
}
@@ -57,7 +56,7 @@ TEST(TypeSyntaxTests, TypeAttributeWithAPIs) {
5756
SmallString<48> Scratch;
5857
llvm::raw_svector_ostream OS { Scratch };
5958
auto blockID = SyntaxFactory::makeIdentifier("block", {}, {});
60-
auto blockArgs = SyntaxFactory::makeTokenList({blockID});
59+
auto blockArgs = SyntaxFactory::makeTokenList({LeftParen, blockID, RightParen});
6160
Convention.withBalancedTokens(blockArgs).print(OS);
6261
ASSERT_EQ(OS.str().str(), "@convention(block)");
6362
}
@@ -69,7 +68,7 @@ TEST(TypeSyntaxTests, TypeAttributeWithAPIs) {
6968
auto EscapingID = SyntaxFactory::makeIdentifier("escaping", {}, {});
7069
auto Escaping = SyntaxFactory::makeBlankAttribute()
7170
.withAtSignToken(At)
72-
.withIdentifier(EscapingID);
71+
.withAttributeName(EscapingID);
7372
Escaping.print(OS);
7473
ASSERT_EQ(OS.str().str(), "@escaping");
7574
}
@@ -83,7 +82,7 @@ TEST(TypeSyntaxTests, TypeAttributeMakeAPIs) {
8382
llvm::raw_svector_ostream OS { Scratch };
8483
auto Autoclosure = SyntaxFactory::makeBlankAttribute()
8584
.withAtSignToken(At)
86-
.withIdentifier(AutoclosureID);
85+
.withAttributeName(AutoclosureID);
8786
Autoclosure.print(OS);
8887
ASSERT_EQ(OS.str().str(), "@autoclosure");
8988
}
@@ -97,9 +96,8 @@ TEST(TypeSyntaxTests, TypeAttributeMakeAPIs) {
9796
SmallString<48> Scratch;
9897
llvm::raw_svector_ostream OS { Scratch };
9998
auto cID = SyntaxFactory::makeIdentifier("c", {}, {});
100-
auto cArgs = SyntaxFactory::makeTokenList({cID});
101-
SyntaxFactory::makeAttribute(At, conventionID, LeftParen, cArgs,
102-
RightParen)
99+
auto cArgs = SyntaxFactory::makeTokenList({LeftParen, cID, RightParen});
100+
SyntaxFactory::makeAttribute(At, conventionID, cArgs)
103101
.print(OS);
104102
ASSERT_EQ(OS.str().str(), "@convention(c)");
105103
}
@@ -108,9 +106,9 @@ TEST(TypeSyntaxTests, TypeAttributeMakeAPIs) {
108106
SmallString<48> Scratch;
109107
llvm::raw_svector_ostream OS { Scratch };
110108
auto swiftID = SyntaxFactory::makeIdentifier("swift", {}, {});
111-
auto swiftArgs = SyntaxFactory::makeTokenList({swiftID});
112-
SyntaxFactory::makeAttribute(At, conventionID, LeftParen,
113-
swiftArgs, RightParen)
109+
auto swiftArgs = SyntaxFactory::makeTokenList({LeftParen, swiftID,
110+
RightParen});
111+
SyntaxFactory::makeAttribute(At, conventionID, swiftArgs)
114112
.print(OS);
115113
ASSERT_EQ(OS.str().str(), "@convention(swift)");
116114
}
@@ -119,9 +117,9 @@ TEST(TypeSyntaxTests, TypeAttributeMakeAPIs) {
119117
SmallString<48> Scratch;
120118
llvm::raw_svector_ostream OS { Scratch };
121119
auto blockID = SyntaxFactory::makeIdentifier("block", {}, {});
122-
auto blockArgs = SyntaxFactory::makeTokenList({blockID});
123-
SyntaxFactory::makeAttribute(At, conventionID, LeftParen,
124-
blockArgs,RightParen)
120+
auto blockArgs = SyntaxFactory::makeTokenList({LeftParen, blockID,
121+
RightParen});
122+
SyntaxFactory::makeAttribute(At, conventionID, blockArgs)
125123
.print(OS);
126124
ASSERT_EQ(OS.str().str(), "@convention(block)");
127125
}
@@ -133,7 +131,7 @@ TEST(TypeSyntaxTests, TypeAttributeMakeAPIs) {
133131
auto EscapingID = SyntaxFactory::makeIdentifier("escaping", {}, {});
134132
auto Escaping = SyntaxFactory::makeBlankAttribute()
135133
.withAtSignToken(At)
136-
.withIdentifier(EscapingID);
134+
.withAttributeName(EscapingID);
137135
Escaping.print(OS);
138136
ASSERT_EQ(OS.str().str(), "@escaping");
139137
}

utils/gyb_syntax_support/AttributeNodes.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@
1010
Node('Attribute', kind='Syntax',
1111
children=[
1212
Child('AtSignToken', kind='AtSignToken'),
13-
Child('Identifier', kind='IdentifierToken'),
14-
Child('LeftParen', kind='LeftParenToken',
15-
is_optional=True),
13+
Child('AttributeName', kind='Token'),
14+
# FIXME: more structure
1615
Child('BalancedTokens', kind='TokenList'),
17-
Child('RightParen', kind='RightParenToken',
18-
is_optional=True),
1916
]),
2017

2118
# attribute-list -> attribute attribute-list?

0 commit comments

Comments
 (0)