Skip to content

Commit eddb50d

Browse files
committed
Parse IfConfigs in Attribute Lists
1 parent 51050ae commit eddb50d

File tree

4 files changed

+91
-2
lines changed

4 files changed

+91
-2
lines changed

Sources/SwiftParser/Attributes.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
extension Parser {
1616
mutating func parseAttributeList() -> RawAttributeListSyntax? {
17-
guard self.at(.atSign) else {
17+
guard self.at(any: [.atSign, .poundIfKeyword]) else {
1818
return nil
1919
}
2020

@@ -23,13 +23,21 @@ extension Parser {
2323
repeat {
2424
let attribute = self.parseAttribute()
2525
elements.append(attribute)
26-
} while self.at(.atSign) && loopProgress.evaluate(currentToken)
26+
} while self.at(any: [.atSign, .poundIfKeyword]) && loopProgress.evaluate(currentToken)
2727
return RawAttributeListSyntax(elements: elements, arena: self.arena)
2828
}
2929
}
3030

3131
extension Parser {
3232
mutating func parseAttribute() -> RawSyntax {
33+
if self.at(.poundIfKeyword) {
34+
return RawSyntax(self.parsePoundIfDirective { parser -> RawSyntax in
35+
return parser.parseAttribute()
36+
} syntax: { parser, attributes in
37+
return RawSyntax(RawAttributeListSyntax(elements: attributes, arena: parser.arena))
38+
})
39+
}
40+
3341
guard let declAttr = DeclarationAttribute(rawValue: self.peek().tokenText) else {
3442
return RawSyntax(self.parseCustomAttribute())
3543
}

Sources/SwiftParser/Declarations.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ extension TokenConsumer {
4747
}
4848
}
4949

50+
if subparser.at(.poundIfKeyword) {
51+
var attrLookahead = subparser.lookahead()
52+
return attrLookahead.consumeIfConfigOfAttributes()
53+
}
54+
5055
let declStartKeyword: DeclarationStart?
5156
if allowRecovery {
5257
declStartKeyword = subparser.canRecoverTo(

Sources/SwiftParser/Lookahead.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,44 @@ extension Parser.Lookahead {
197197
}
198198
return true
199199
}
200+
201+
mutating func consumeIfConfigOfAttributes() -> Bool {
202+
while true {
203+
// #if / #else / #elseif
204+
self.consumeAnyToken()
205+
206+
// <expression>
207+
self.skipUntilEndOfLine()
208+
209+
while true {
210+
if self.at(.atSign) {
211+
_ = self.consumeAttributeList()
212+
continue
213+
}
214+
215+
if self.at(.poundIfKeyword) {
216+
_ = self.consumeIfConfigOfAttributes()
217+
continue
218+
}
219+
220+
break
221+
}
222+
223+
guard self.at(any: [ .poundElseifKeyword, .poundElseKeyword ]) else {
224+
break
225+
}
226+
}
227+
228+
// If we ran out of tokens, say we consumed the rest.
229+
if self.at(.eof) {
230+
return true
231+
}
232+
233+
guard self.currentToken.isAtStartOfLine else {
234+
return false
235+
}
236+
return self.consume(if: .poundEndifKeyword) != nil
237+
}
200238
}
201239

202240
// MARK: Lookahead

Tests/SwiftParserTest/Directives.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,42 @@ final class DirectiveTests: XCTestCase {
111111
)
112112
}
113113

114+
func testHasAttribute() {
115+
AssertParse(
116+
"""
117+
@frozen
118+
#if hasAttribute(foo)
119+
@foo
120+
#endif
121+
public struct S2 { }
122+
""")
123+
124+
AssertParse(
125+
"""
126+
struct Inner {
127+
@frozen
128+
#if hasAttribute(foo)
129+
#if hasAttribute(bar)
130+
@foo @bar
131+
#endif
132+
#endif
133+
public struct S2 { }
134+
135+
#if hasAttribute(foo)
136+
@foo
137+
#endif
138+
@inlinable
139+
func f1() { }
140+
141+
#if hasAttribute(foo)
142+
@foo
143+
#else
144+
@available(*, deprecated, message: "nope")
145+
@frozen
146+
#endif
147+
public struct S3 { }
148+
}
149+
""")
150+
}
151+
114152
}

0 commit comments

Comments
 (0)