Skip to content

Commit 36bd1ac

Browse files
committed
Introduce 'AvailabilityMacroDefinitionSyntax'
Under 'Compier' SPI. This is for parsing arguments for '-define-availability' compiler option: <identifier> <version-tuple>? ':' <availability-spec-list>
1 parent af26da4 commit 36bd1ac

25 files changed

+514
-20
lines changed

CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift

+25
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,29 @@ public let AVAILABILITY_NODES: [Node] = [
182182
]
183183
),
184184

185+
Node(
186+
kind: .availabilityMacroDefinition,
187+
base: .syntax,
188+
spi: "Compiler",
189+
nameForDiagnostics: "availability macro definition",
190+
documentation: "Syntax for '-define-availability' compiler arguments, never appear in Swift source code",
191+
parserFunction: "parseAvailabilityMacroDefinition",
192+
children: [
193+
Child(
194+
name: "platformVersion",
195+
kind: .node(kind: .platformVersion)
196+
),
197+
Child(
198+
name: "colon",
199+
kind: .token(choices: [.token(.colon)])
200+
),
201+
Child(
202+
name: "specs",
203+
kind: .collection(
204+
kind: .availabilityArgumentList,
205+
collectionElementName: "AvailabilityArgument"
206+
)
207+
),
208+
]
209+
),
185210
]

CodeGeneration/Sources/SyntaxSupport/Node.swift

+24-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public class Node: NodeChoiceConvertible {
4242

4343
public let experimentalFeature: ExperimentalFeature?
4444

45+
/// SPI name if this node is only available for the SPI.
46+
public let spi: TokenSyntax?
47+
4548
/// When the node name is printed for diagnostics, this name is used.
4649
/// If `nil`, `nameForDiagnostics` will print the parent node’s name.
4750
public let nameForDiagnostics: String?
@@ -103,6 +106,14 @@ public class Node: NodeChoiceConvertible {
103106
"""
104107
experimentalSPI.with(\.trailingTrivia, .newline)
105108
}
109+
if let spi = self.spi {
110+
let spiAttr: AttributeListSyntax = """
111+
#if compiler(>=5.8)
112+
@_spi(\(spi))
113+
#endif
114+
"""
115+
spiAttr.with(\.trailingTrivia, .newline)
116+
}
106117
if forRaw {
107118
"@_spi(RawSyntax)"
108119
}
@@ -119,6 +130,7 @@ public class Node: NodeChoiceConvertible {
119130
kind: SyntaxNodeKind,
120131
base: SyntaxNodeKind,
121132
experimentalFeature: ExperimentalFeature? = nil,
133+
spi: TokenSyntax? = nil,
122134
nameForDiagnostics: String?,
123135
documentation: String? = nil,
124136
parserFunction: TokenSyntax? = nil,
@@ -132,6 +144,7 @@ public class Node: NodeChoiceConvertible {
132144
self.kind = kind
133145
self.base = base
134146
self.experimentalFeature = experimentalFeature
147+
self.spi = spi
135148
self.nameForDiagnostics = nameForDiagnostics
136149
self.documentation = SwiftSyntax.Trivia.docCommentTrivia(from: documentation)
137150
self.parserFunction = parserFunction
@@ -141,6 +154,10 @@ public class Node: NodeChoiceConvertible {
141154
self.data = .layout(children: childrenWithUnexpected, childHistory: childHistory, traits: traits)
142155
}
143156

157+
public var hiddenInDocumentation: Bool {
158+
self.isExperimental || self.spi != nil || self.kind.isDeprecated
159+
}
160+
144161
/// A doc comment that lists all the nodes in which this node occurs as a child in.
145162
public var containedIn: SwiftSyntax.Trivia {
146163
if kind == .unexpectedNodes {
@@ -149,7 +166,10 @@ public class Node: NodeChoiceConvertible {
149166
return []
150167
}
151168
var childIn: [(node: SyntaxNodeKind, child: Child?)] = []
152-
for node in SYNTAX_NODES where !node.isExperimental {
169+
for node in SYNTAX_NODES {
170+
if !self.hiddenInDocumentation && node.hiddenInDocumentation {
171+
continue
172+
}
153173
if let layout = node.layoutNode {
154174
for child in layout.children {
155175
if child.kinds.contains(self.kind) {
@@ -202,7 +222,7 @@ public class Node: NodeChoiceConvertible {
202222

203223
let list =
204224
SYNTAX_NODES
205-
.filter { $0.base == self.kind && !$0.isExperimental && !$0.kind.isDeprecated }
225+
.filter { $0.base == self.kind && (!$0.hiddenInDocumentation || self.hiddenInDocumentation) }
206226
.map { "- \($0.kind.doccLink)" }
207227
.joined(separator: "\n")
208228

@@ -226,6 +246,7 @@ public class Node: NodeChoiceConvertible {
226246
kind: SyntaxNodeKind,
227247
base: SyntaxNodeKind,
228248
experimentalFeature: ExperimentalFeature? = nil,
249+
spi: TokenSyntax? = nil,
229250
nameForDiagnostics: String?,
230251
documentation: String? = nil,
231252
parserFunction: TokenSyntax? = nil,
@@ -235,6 +256,7 @@ public class Node: NodeChoiceConvertible {
235256
precondition(base == .syntaxCollection)
236257
self.base = base
237258
self.experimentalFeature = experimentalFeature
259+
self.spi = spi
238260
self.nameForDiagnostics = nameForDiagnostics
239261
self.documentation = SwiftSyntax.Trivia.docCommentTrivia(from: documentation)
240262
self.parserFunction = parserFunction

CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
4444
case availabilityArgumentList
4545
case availabilityCondition
4646
case availabilityLabeledArgument
47+
case availabilityMacroDefinition
4748
case awaitExpr
4849
case backDeployedAttributeArguments
4950
case binaryOperatorExpr

CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/LayoutNodesParsableFile.swift

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@ import SyntaxSupport
1616
import Utils
1717

1818
let layoutNodesParsableFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
var importingAttrs = AttributeListSyntax {
20+
var seen: Set<String> = []
21+
AttributeSyntax("@_spi(RawSyntax)").with(\.trailingTrivia, .space)
22+
AttributeSyntax("@_spi(ExperimentalLanguageFeatures)").with(\.trailingTrivia, .space)
23+
for node in NON_BASE_SYNTAX_NODES {
24+
if let spi = node.spi, seen.insert(spi.text).inserted {
25+
AttributeSyntax("@_spi(\(spi))").with(\.trailingTrivia, .space)
26+
}
27+
}
28+
}
1929
DeclSyntax(
2030
"""
2131
#if compiler(>=6)
22-
@_spi(RawSyntax) public import SwiftSyntax
32+
\(importingAttrs) public import SwiftSyntax
2333
#else
24-
@_spi(RawSyntax) import SwiftSyntax
34+
\(importingAttrs) import SwiftSyntax
2535
#endif
2636
"""
2737
)

CodeGeneration/Sources/generate-swift-syntax/templates/swiftparserdiagnostics/SyntaxKindNameForDiagnosticsFile.swift

+11-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,21 @@ import SyntaxSupport
1616
import Utils
1717

1818
let syntaxKindNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
var importingAttrs = AttributeListSyntax {
20+
var seen: Set<String> = []
21+
AttributeSyntax("@_spi(ExperimentalLanguageFeatures)").with(\.trailingTrivia, .space)
22+
for node in NON_BASE_SYNTAX_NODES {
23+
if let spi = node.spi, seen.insert(spi.text).inserted {
24+
AttributeSyntax("@_spi(\(spi))").with(\.trailingTrivia, .space)
25+
}
26+
}
27+
}
1928
DeclSyntax(
2029
"""
2130
#if compiler(>=6)
22-
@_spi(ExperimentalLanguageFeatures) internal import SwiftSyntax
31+
\(importingAttrs) internal import SwiftSyntax
2332
#else
24-
@_spi(ExperimentalLanguageFeatures) import SwiftSyntax
33+
\(importingAttrs) import SwiftSyntax
2534
#endif
2635
"""
2736
)

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/SwiftSyntaxDoccIndex.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ let nodesSections: String = {
3939
let baseTypes = ["\(baseKind.syntaxType)", "\(baseKind.syntaxType)Protocol", "Missing\(baseKind.syntaxType)"]
4040
let leafTypes =
4141
SYNTAX_NODES
42-
.filter({ $0.base == baseKind && !$0.kind.isMissing && !$0.isExperimental && !$0.kind.isDeprecated })
42+
.filter({ $0.base == baseKind && !$0.kind.isMissing && !$0.hiddenInDocumentation })
4343
.map(\.kind.syntaxType.description)
4444
addSection(heading: heading, types: baseTypes + leafTypes)
4545
}
@@ -51,26 +51,26 @@ let nodesSections: String = {
5151
"SyntaxChildrenIndex",
5252
]
5353
+ SYNTAX_NODES.flatMap({ (node: Node) -> [String] in
54-
guard let node = node.collectionNode, !node.isExperimental else {
54+
guard let node = node.collectionNode, !node.hiddenInDocumentation else {
5555
return []
5656
}
5757
return [node.kind.syntaxType.description]
5858
+ node.elementChoices
59-
.filter { SYNTAX_NODE_MAP[$0] != nil && !SYNTAX_NODE_MAP[$0]!.isExperimental && !$0.isDeprecated }
59+
.filter { SYNTAX_NODE_MAP[$0] != nil && !SYNTAX_NODE_MAP[$0]!.hiddenInDocumentation }
6060
.map(\.syntaxType.description)
6161
.filter { !handledSyntaxTypes.contains($0) }
6262
})
6363
)
6464

6565
addSection(
6666
heading: "Attributes",
67-
types: ATTRIBUTE_NODES.filter({ !$0.isExperimental && !$0.kind.isDeprecated }).map(\.kind.syntaxType.description)
67+
types: ATTRIBUTE_NODES.filter({ !$0.hiddenInDocumentation }).map(\.kind.syntaxType.description)
6868
.sorted()
6969
)
7070

7171
addSection(
7272
heading: "Miscellaneous Syntax",
73-
types: SYNTAX_NODES.filter({ !$0.isExperimental && !$0.kind.isDeprecated }).map(\.kind.syntaxType.description)
73+
types: SYNTAX_NODES.filter({ !$0.hiddenInDocumentation }).map(\.kind.syntaxType.description)
7474
.filter({
7575
!handledSyntaxTypes.contains($0)
7676
})

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntaxbuilder/SyntaxExpressibleByStringInterpolationConformancesFile.swift

+13-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@ import SyntaxSupport
1616
import Utils
1717

1818
let syntaxExpressibleByStringInterpolationConformancesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
20+
var importingAttrs = AttributeListSyntax {
21+
var seen: Set<String> = []
22+
AttributeSyntax("@_spi(ExperimentalLanguageFeatures)").with(\.trailingTrivia, .space)
23+
for node in NON_BASE_SYNTAX_NODES {
24+
if let spi = node.spi, seen.insert(spi.text).inserted {
25+
AttributeSyntax("@_spi(\(spi))").with(\.trailingTrivia, .space)
26+
}
27+
}
28+
}
29+
1930
DeclSyntax(
2031
"""
2132
#if compiler(>=6)
22-
internal import SwiftSyntax
33+
\(importingAttrs) internal import SwiftSyntax
2334
#else
24-
import SwiftSyntax
35+
\(importingAttrs) import SwiftSyntax
2536
#endif
2637
"""
2738
)

Sources/SwiftParser/Availability.swift

+17
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,20 @@ extension Parser {
304304
}
305305
}
306306
}
307+
308+
extension Parser {
309+
/// Parse an argument for '-define-availability' compiler option.
310+
mutating func parseAvailabilityMacroDefinition() -> RawAvailabilityMacroDefinitionSyntax {
311+
let namedAndVersion = self.parsePlatformVersion(allowStarAsVersionNumber: false)
312+
let (unexpectedBetweenPlatformVersionAndColon, colon) = self.expect(.colon)
313+
let specs = self.parseAvailabilitySpecList()
314+
315+
return RawAvailabilityMacroDefinitionSyntax(
316+
platformVersion: namedAndVersion,
317+
unexpectedBetweenPlatformVersionAndColon,
318+
colon: colon,
319+
specs: specs,
320+
arena: self.arena
321+
)
322+
}
323+
}

Sources/SwiftParser/CollectionNodes+Parsable.swift

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ extension AccessorDeclListSyntax: SyntaxParseable {
7272
parameters: nil,
7373
effectSpecifiers: nil,
7474
body: nil,
75+
RawUnexpectedNodesSyntax(remainingTokens, arena: arena),
7576
arena: arena
7677
)
7778
}
@@ -89,6 +90,7 @@ extension AttributeListSyntax: SyntaxParseable {
8990
leftParen: nil,
9091
arguments: nil,
9192
rightParen: nil,
93+
RawUnexpectedNodesSyntax(remainingTokens, arena: arena),
9294
arena: arena
9395
)
9496
}
@@ -104,6 +106,7 @@ extension CodeBlockItemListSyntax: SyntaxParseable {
104106
RawCodeBlockItemSyntax(
105107
item: .init(expr: RawMissingExprSyntax(arena: arena)),
106108
semicolon: nil,
109+
RawUnexpectedNodesSyntax(remainingTokens, arena: arena),
107110
arena: arena
108111
)
109112
}

Sources/SwiftParser/generated/LayoutNodes+Parsable.swift

+20-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
#if compiler(>=6)
16-
@_spi(RawSyntax) public import SwiftSyntax
16+
@_spi(RawSyntax) @_spi(ExperimentalLanguageFeatures) @_spi(Compiler) public import SwiftSyntax
1717
#else
18-
@_spi(RawSyntax) import SwiftSyntax
18+
@_spi(RawSyntax) @_spi(ExperimentalLanguageFeatures) @_spi(Compiler) import SwiftSyntax
1919
#endif
2020

2121
public protocol SyntaxParseable: SyntaxProtocol {
@@ -76,6 +76,24 @@ extension AttributeSyntax: SyntaxParseable {
7676
}
7777
}
7878

79+
extension AvailabilityMacroDefinitionSyntax: SyntaxParseable {
80+
public static func parse(from parser: inout Parser) -> Self {
81+
// Keep the parser alive so that the arena in which `raw` is allocated
82+
// doesn’t get deallocated before we have a chance to create a syntax node
83+
// from it. We can’t use `parser.arena` as the parameter to
84+
// `Syntax(raw:arena:)` because the node might have been re-used during an
85+
// incremental parse and would then live in a different arena than
86+
// `parser.arena`.
87+
defer {
88+
withExtendedLifetime(parser) {
89+
}
90+
}
91+
let node = parser.parseAvailabilityMacroDefinition()
92+
let raw = RawSyntax(parser.parseRemainder(into: node))
93+
return Syntax(raw: raw, rawNodeArena: parser.arena).cast(Self.self)
94+
}
95+
}
96+
7997
extension CatchClauseSyntax: SyntaxParseable {
8098
public static func parse(from parser: inout Parser) -> Self {
8199
// Keep the parser alive so that the arena in which `raw` is allocated

Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
#if compiler(>=6)
16-
@_spi(ExperimentalLanguageFeatures) internal import SwiftSyntax
16+
@_spi(ExperimentalLanguageFeatures) @_spi(Compiler) internal import SwiftSyntax
1717
#else
18-
@_spi(ExperimentalLanguageFeatures) import SwiftSyntax
18+
@_spi(ExperimentalLanguageFeatures) @_spi(Compiler) import SwiftSyntax
1919
#endif
2020

2121
extension SyntaxKind {
@@ -55,6 +55,8 @@ extension SyntaxKind {
5555
return "availability condition"
5656
case .availabilityLabeledArgument:
5757
return "availability argument"
58+
case .availabilityMacroDefinition:
59+
return "availability macro definition"
5860
case .awaitExpr:
5961
return "'await' expression"
6062
case .backDeployedAttributeArguments:

Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift

+14
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,20 @@ public func childName(_ keyPath: AnyKeyPath) -> String? {
301301
return "value"
302302
case \AvailabilityLabeledArgumentSyntax.unexpectedAfterValue:
303303
return "unexpectedAfterValue"
304+
case \AvailabilityMacroDefinitionSyntax.unexpectedBeforePlatformVersion:
305+
return "unexpectedBeforePlatformVersion"
306+
case \AvailabilityMacroDefinitionSyntax.platformVersion:
307+
return "platformVersion"
308+
case \AvailabilityMacroDefinitionSyntax.unexpectedBetweenPlatformVersionAndColon:
309+
return "unexpectedBetweenPlatformVersionAndColon"
310+
case \AvailabilityMacroDefinitionSyntax.colon:
311+
return "colon"
312+
case \AvailabilityMacroDefinitionSyntax.unexpectedBetweenColonAndSpecs:
313+
return "unexpectedBetweenColonAndSpecs"
314+
case \AvailabilityMacroDefinitionSyntax.specs:
315+
return "specs"
316+
case \AvailabilityMacroDefinitionSyntax.unexpectedAfterSpecs:
317+
return "unexpectedAfterSpecs"
304318
case \AwaitExprSyntax.unexpectedBeforeAwaitKeyword:
305319
return "unexpectedBeforeAwaitKeyword"
306320
case \AwaitExprSyntax.awaitKeyword:

Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift

+14
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,20 @@ open class SyntaxAnyVisitor: SyntaxVisitor {
238238
visitAnyPost(node._syntaxNode)
239239
}
240240

241+
#if compiler(>=5.8)
242+
@_spi(Compiler)
243+
#endif
244+
override open func visit(_ node: AvailabilityMacroDefinitionSyntax) -> SyntaxVisitorContinueKind {
245+
return visitAny(node._syntaxNode)
246+
}
247+
248+
#if compiler(>=5.8)
249+
@_spi(Compiler)
250+
#endif
251+
override open func visitPost(_ node: AvailabilityMacroDefinitionSyntax) {
252+
visitAnyPost(node._syntaxNode)
253+
}
254+
241255
override open func visit(_ node: AwaitExprSyntax) -> SyntaxVisitorContinueKind {
242256
return visitAny(node._syntaxNode)
243257
}

Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift

+1
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,7 @@ extension Syntax {
15401540
.node(AvailabilityArgumentSyntax.self),
15411541
.node(AvailabilityConditionSyntax.self),
15421542
.node(AvailabilityLabeledArgumentSyntax.self),
1543+
.node(AvailabilityMacroDefinitionSyntax.self),
15431544
.node(AwaitExprSyntax.self),
15441545
.node(BackDeployedAttributeArgumentsSyntax.self),
15451546
.node(BinaryOperatorExprSyntax.self),

0 commit comments

Comments
 (0)