Skip to content

Commit 72bc06a

Browse files
committed
[Parser] Attributes on MacroExpansionDeclSyntax
* Add `attributes` and `modifiers` to `MacroExpansionDeclSyntax` * Diagnose whitespaces between # and the macro name * Attach attributes to MacroExpansionDeclSyntax rdar://107386648
1 parent 8cd23e5 commit 72bc06a

File tree

12 files changed

+459
-113
lines changed

12 files changed

+459
-113
lines changed

CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,18 @@ public let DECL_NODES: [Node] = [
12781278
"FreestandingMacroExpansion"
12791279
],
12801280
children: [
1281+
Child(
1282+
name: "Attributes",
1283+
kind: .collection(kind: "AttributeList", collectionElementName: "Attribute"),
1284+
nameForDiagnostics: "attributes",
1285+
isOptional: true
1286+
),
1287+
Child(
1288+
name: "Modifiers",
1289+
kind: .collection(kind: "ModifierList", collectionElementName: "Modifier"),
1290+
nameForDiagnostics: "modifiers",
1291+
isOptional: true
1292+
),
12811293
Child(
12821294
name: "PoundToken",
12831295
kind: .token(choices: [.token(tokenKind: "PoundToken")]),

Sources/SwiftParser/Declarations.swift

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,25 @@ extension DeclarationModifier {
2929
}
3030

3131
extension TokenConsumer {
32+
mutating func atStartOfFreestandingMacroExpansion() -> Bool {
33+
if !self.at(.pound) {
34+
return false
35+
}
36+
if self.peek().rawTokenKind != .identifier && !self.peek().isLexerClassifiedKeyword {
37+
return false
38+
}
39+
if self.currentToken.trailingTriviaByteLength != 0 || self.peek().leadingTriviaByteLength != 0 {
40+
return false
41+
}
42+
return true
43+
}
44+
3245
mutating func atStartOfDeclaration(
3346
isAtTopLevel: Bool = false,
3447
allowInitDecl: Bool = true,
3548
allowRecovery: Bool = false
3649
) -> Bool {
3750
if self.at(anyIn: PoundDeclarationStart.self) != nil {
38-
// Don't treat freestanding macro expansions as declarations. They'll be
39-
// parsed as expressions.
40-
if self.at(.pound) {
41-
return false
42-
}
43-
4451
return true
4552
}
4653

@@ -53,12 +60,14 @@ extension TokenConsumer {
5360
_ = subparser.consumeAttributeList()
5461
}
5562

63+
var hasModifier = false
5664
if subparser.currentToken.isLexerClassifiedKeyword || subparser.currentToken.rawTokenKind == .identifier {
5765
var modifierProgress = LoopProgressCondition()
5866
while let (modifierKind, handle) = subparser.at(anyIn: DeclarationModifier.self),
5967
modifierKind != .class,
6068
modifierProgress.evaluate(subparser.currentToken)
6169
{
70+
hasModifier = true
6271
subparser.eat(handle)
6372
if modifierKind != .open && subparser.at(.leftParen) && modifierKind.canHaveParenthesizedArgument {
6473
// When determining whether we are at a declaration, don't consume anything in parentheses after 'open'
@@ -113,6 +122,16 @@ extension TokenConsumer {
113122
case .macroKeyword:
114123
// macro Foo ...
115124
return subparser.peek().rawTokenKind == .identifier
125+
case .pound:
126+
// Force parsing '#<identifier>' after attributes as a macro expansion decl.
127+
if hasAttribute || hasModifier {
128+
return true
129+
}
130+
131+
// Otherwise, parse it as a expression.
132+
// FIXME: C++ parser returns true if this is a top-level non-"script" files.
133+
// But we don't have "is library" flag.
134+
return false
116135
case .some(_):
117136
// All other decl start keywords unconditonally start a decl.
118137
return true
@@ -203,10 +222,6 @@ extension Parser {
203222
return .decls(RawMemberDeclListSyntax(elements: elements, arena: parser.arena))
204223
}
205224
return RawDeclSyntax(directive)
206-
case (.pound, _)?:
207-
// FIXME: If we can have attributes for macro expansions, handle this
208-
// via DeclarationStart.
209-
return RawDeclSyntax(self.parseMacroExpansionDeclaration())
210225
case nil:
211226
break
212227
}
@@ -258,6 +273,8 @@ extension Parser {
258273
return RawDeclSyntax(self.parseNominalTypeDeclaration(for: RawActorDeclSyntax.self, attrs: attrs, introucerHandle: handle))
259274
case (.macroKeyword, let handle)?:
260275
return RawDeclSyntax(self.parseMacroDeclaration(attrs: attrs, introducerHandle: handle))
276+
case (.pound, let handle)?:
277+
return RawDeclSyntax(self.parseMacroExpansionDeclaration(attrs, handle))
261278
case nil:
262279
if inMemberDeclList {
263280
let isProbablyVarDecl = self.at(.identifier, .wildcard) && self.peek().rawTokenKind.is(.colon, .equal, .comma)
@@ -2023,9 +2040,30 @@ extension Parser {
20232040
/// =======
20242041
///
20252042
/// macro-expansion-declaration → '#' identifier expr-call-suffix?
2026-
mutating func parseMacroExpansionDeclaration() -> RawMacroExpansionDeclSyntax {
2027-
let poundKeyword = self.consumeAnyToken()
2028-
let (unexpectedBeforeMacro, macro) = self.expectIdentifier()
2043+
mutating func parseMacroExpansionDeclaration(
2044+
_ attrs: DeclAttributes,
2045+
_ handle: RecoveryConsumptionHandle
2046+
) -> RawMacroExpansionDeclSyntax {
2047+
2048+
let (unexpectedBeforePound, poundKeyword) = self.eat(handle)
2049+
// Don't allow space between '#' and the macro name.
2050+
if poundKeyword.trailingTriviaByteLength != 0 || self.currentToken.leadingTriviaByteLength != 0 {
2051+
return RawMacroExpansionDeclSyntax(
2052+
attributes: attrs.attributes,
2053+
modifiers: attrs.modifiers,
2054+
unexpectedBeforePound,
2055+
poundToken: poundKeyword,
2056+
macro: self.missingToken(.identifier),
2057+
genericArguments: nil,
2058+
leftParen: nil,
2059+
argumentList: .init(elements: [], arena: self.arena),
2060+
rightParen: nil,
2061+
trailingClosure: nil,
2062+
additionalTrailingClosures: nil,
2063+
arena: self.arena
2064+
)
2065+
}
2066+
let (unexpectedBeforeMacro, macro) = self.expectIdentifier(keywordRecovery: true)
20292067

20302068
// Parse the optional generic argument list.
20312069
let generics: RawGenericArgumentClauseSyntax?
@@ -2063,6 +2101,9 @@ extension Parser {
20632101
}
20642102

20652103
return RawMacroExpansionDeclSyntax(
2104+
attributes: attrs.attributes,
2105+
modifiers: attrs.modifiers,
2106+
unexpectedBeforePound,
20662107
poundToken: poundKeyword,
20672108
unexpectedBeforeMacro,
20682109
macro: macro,

Sources/SwiftParser/Expressions.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1394,8 +1394,21 @@ extension Parser {
13941394
pattern: PatternContext,
13951395
flavor: ExprFlavor
13961396
) -> RawMacroExpansionExprSyntax {
1397+
if !atStartOfFreestandingMacroExpansion() {
1398+
return RawMacroExpansionExprSyntax(
1399+
poundToken: self.consumeAnyToken(),
1400+
macro: self.missingToken(.identifier),
1401+
genericArguments: nil,
1402+
leftParen: nil,
1403+
argumentList: .init(elements: [], arena: self.arena),
1404+
rightParen: nil,
1405+
trailingClosure: nil,
1406+
additionalTrailingClosures: nil,
1407+
arena: self.arena
1408+
)
1409+
}
13971410
let poundKeyword = self.consumeAnyToken()
1398-
let (unexpectedBeforeMacro, macro) = self.expectIdentifier()
1411+
let (unexpectedBeforeMacro, macro) = self.expectIdentifier(keywordRecovery: true)
13991412

14001413
// Parse the optional generic argument list.
14011414
let generics: RawGenericArgumentClauseSyntax?

Sources/SwiftParser/TokenSpecSet.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ enum DeclarationStart: TokenSpecSet {
272272
case typealiasKeyword
273273
case varKeyword
274274
case inoutKeyword
275+
case pound
275276

276277
init?(lexeme: Lexer.Lexeme) {
277278
switch PrepareForKeywordMatch(lexeme) {
@@ -295,6 +296,7 @@ enum DeclarationStart: TokenSpecSet {
295296
case TokenSpec(.typealias): self = .typealiasKeyword
296297
case TokenSpec(.var): self = .varKeyword
297298
case TokenSpec(.inout): self = .inoutKeyword
299+
case TokenSpec(.pound): self = .pound
298300
default: return nil
299301
}
300302
}
@@ -321,6 +323,7 @@ enum DeclarationStart: TokenSpecSet {
321323
case .typealiasKeyword: return .keyword(.typealias)
322324
case .varKeyword: return .keyword(.var)
323325
case .inoutKeyword: return TokenSpec(.inout, recoveryPrecedence: .declKeyword)
326+
case .pound: return TokenSpec(.pound, recoveryPrecedence: .openingPoundIf)
324327
}
325328
}
326329
}
@@ -396,20 +399,17 @@ enum OperatorLike: TokenSpecSet {
396399

397400
enum PoundDeclarationStart: TokenSpecSet {
398401
case poundIfKeyword
399-
case pound
400402

401403
init?(lexeme: Lexer.Lexeme) {
402404
switch lexeme.rawTokenKind {
403405
case .poundIfKeyword: self = .poundIfKeyword
404-
case .pound: self = .pound
405406
default: return nil
406407
}
407408
}
408409

409410
var spec: TokenSpec {
410411
switch self {
411412
case .poundIfKeyword: return .poundIfKeyword
412-
case .pound: return .pound
413413
}
414414
}
415415
}

Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String? {
236236
return "macro definition"
237237
case \MacroDeclSyntax.genericWhereClause:
238238
return "generic where clause"
239+
case \MacroExpansionDeclSyntax.attributes:
240+
return "attributes"
241+
case \MacroExpansionDeclSyntax.modifiers:
242+
return "modifiers"
239243
case \MemberAccessExprSyntax.base:
240244
return "base"
241245
case \MemberAccessExprSyntax.name:

Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,8 +1995,16 @@ public func childName(_ keyPath: AnyKeyPath) -> String? {
19951995
return "genericWhereClause"
19961996
case \MacroDeclSyntax.unexpectedAfterGenericWhereClause:
19971997
return "unexpectedAfterGenericWhereClause"
1998-
case \MacroExpansionDeclSyntax.unexpectedBeforePoundToken:
1999-
return "unexpectedBeforePoundToken"
1998+
case \MacroExpansionDeclSyntax.unexpectedBeforeAttributes:
1999+
return "unexpectedBeforeAttributes"
2000+
case \MacroExpansionDeclSyntax.attributes:
2001+
return "attributes"
2002+
case \MacroExpansionDeclSyntax.unexpectedBetweenAttributesAndModifiers:
2003+
return "unexpectedBetweenAttributesAndModifiers"
2004+
case \MacroExpansionDeclSyntax.modifiers:
2005+
return "modifiers"
2006+
case \MacroExpansionDeclSyntax.unexpectedBetweenModifiersAndPoundToken:
2007+
return "unexpectedBetweenModifiersAndPoundToken"
20002008
case \MacroExpansionDeclSyntax.poundToken:
20012009
return "poundToken"
20022010
case \MacroExpansionDeclSyntax.unexpectedBetweenPoundTokenAndMacro:

0 commit comments

Comments
 (0)