@@ -29,18 +29,25 @@ extension DeclarationModifier {
2929}
3030
3131extension 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,
0 commit comments