Skip to content

Commit 75cb90a

Browse files
committed
Add 'GeneratedAttributeClauseFile' and 'GeneratedAcceesoBlockFile'
Also rename 'AvailabilityMacroDefinition' to `AvailabilityMacroDefinitionFile` and add 'endOfFileToken'. These are 'Compiler' SPI and parsed as a "file". In `CodeGeneration`, introduce `CompilerNodes.swift` and put all the 'Compiler' SPIs in it.
1 parent 3eedb6d commit 75cb90a

24 files changed

+1162
-116
lines changed

CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -181,30 +181,4 @@ public let AVAILABILITY_NODES: [Node] = [
181181
),
182182
]
183183
),
184-
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-
),
210184
]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
public let COMPILER_NODES: [Node] = [
14+
Node(
15+
kind: .availabilityMacroDefinitionFile,
16+
base: .syntax,
17+
spi: "Compiler",
18+
nameForDiagnostics: "availability macro definition",
19+
documentation: """
20+
Syntax for '-define-availability' compiler arguments, never appear in Swift source code.
21+
""",
22+
parserFunction: "parseAvailabilityMacroDefinitionFile",
23+
children: [
24+
Child(
25+
name: "platformVersion",
26+
kind: .node(kind: .platformVersion)
27+
),
28+
Child(
29+
name: "colon",
30+
kind: .token(choices: [.token(.colon)])
31+
),
32+
Child(
33+
name: "specs",
34+
kind: .collection(
35+
kind: .availabilityArgumentList,
36+
collectionElementName: "AvailabilityArgument"
37+
)
38+
),
39+
Child(
40+
name: "endOfFileToken",
41+
kind: .token(choices: [.token(.endOfFile)])
42+
),
43+
]
44+
),
45+
46+
Node(
47+
kind: .generatedAccessorBlockFile,
48+
base: .syntax,
49+
spi: "Compiler",
50+
nameForDiagnostics: "accessors",
51+
documentation: """
52+
Syntax for 'accessor' macro expansion, never appear in Swift source code.
53+
""",
54+
parserFunction: "parseGeneratedAccessorBlockFile",
55+
children: [
56+
Child(
57+
name: "leftBrace",
58+
kind: .token(choices: [.token(.leftBrace)]),
59+
isOptional: true
60+
),
61+
Child(
62+
name: "accessors",
63+
kind: .collection(
64+
kind: .accessorDeclList,
65+
collectionElementName: "Accessor"
66+
)
67+
),
68+
Child(
69+
name: "rightBrace",
70+
kind: .token(choices: [.token(.rightBrace)]),
71+
isOptional: true
72+
),
73+
Child(
74+
name: "endOfFileToken",
75+
kind: .token(choices: [.token(.endOfFile)])
76+
),
77+
]
78+
),
79+
80+
Node(
81+
kind: .generatedAttributeClauseFile,
82+
base: .syntax,
83+
spi: "Compiler",
84+
nameForDiagnostics: "attribute list",
85+
documentation: """
86+
Syntax for 'memberAttribute' macro expansion or 'swift_attr' attribute in Clang, never appear in Swift source code.
87+
""",
88+
parserFunction: "parseGeneratedAttributeClauseFile",
89+
traits: [
90+
"WithAttributes",
91+
"WithModifiers",
92+
],
93+
children: [
94+
Child(
95+
name: "attributes",
96+
kind: .collection(
97+
kind: .attributeList,
98+
collectionElementName: "Attribute"
99+
)
100+
),
101+
Child(
102+
name: "modifiers",
103+
kind: .collection(
104+
kind: .declModifierList,
105+
collectionElementName: "Modifier"
106+
)
107+
),
108+
Child(
109+
name: "endOfFileToken",
110+
kind: .token(choices: [.token(.endOfFile)])
111+
),
112+
]
113+
),
114+
]

CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
2222

2323
case _canImportExpr
2424
case _canImportVersionInfo
25+
case generatedAttributeClauseFile
26+
case generatedAccessorBlockFile
2527
case abiAttributeArguments
2628
case accessorBlock
2729
case accessorDecl
@@ -44,7 +46,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
4446
case availabilityArgumentList
4547
case availabilityCondition
4648
case availabilityLabeledArgument
47-
case availabilityMacroDefinition
49+
case availabilityMacroDefinitionFile
4850
case awaitExpr
4951
case backDeployedAttributeArguments
5052
case binaryOperatorExpr

CodeGeneration/Sources/SyntaxSupport/SyntaxNodes.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ private let unsortedSyntaxNodes: [Node] =
2020
+ TYPE_NODES
2121
+ PATTERN_NODES
2222
+ AVAILABILITY_NODES
23+
+ COMPILER_NODES
2324

2425
public let SYNTAX_NODES: [Node] =
2526
unsortedSyntaxNodes

CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,18 @@ class ValidateSyntaxNodes: XCTestCase {
300300
node: .sourceFile,
301301
message: "child 'endOfFileToken' has a token as its only token choice and should thus be named 'endOfFile'"
302302
),
303+
ValidationFailure(
304+
node: .availabilityMacroDefinitionFile,
305+
message: "child 'endOfFileToken' has a token as its only token choice and should thus be named 'endOfFile'"
306+
),
307+
ValidationFailure(
308+
node: .generatedAccessorBlockFile,
309+
message: "child 'endOfFileToken' has a token as its only token choice and should thus be named 'endOfFile'"
310+
),
311+
ValidationFailure(
312+
node: .generatedAttributeClauseFile,
313+
message: "child 'endOfFileToken' has a token as its only token choice and should thus be named 'endOfFile'"
314+
),
303315
ValidationFailure(
304316
node: .stringLiteralExpr,
305317
message:
@@ -573,7 +585,19 @@ class ValidateSyntaxNodes: XCTestCase {
573585
failures,
574586
expectedFailures: [
575587
// it's not obvious that the end of file is represented by a token, thus its good to highlight it in the name
576-
ValidationFailure(node: .sourceFile, message: "child 'endOfFileToken' should not end with 'Token'")
588+
ValidationFailure(node: .sourceFile, message: "child 'endOfFileToken' should not end with 'Token'"),
589+
ValidationFailure(
590+
node: .availabilityMacroDefinitionFile,
591+
message: "child 'endOfFileToken' should not end with 'Token'"
592+
),
593+
ValidationFailure(
594+
node: .generatedAccessorBlockFile,
595+
message: "child 'endOfFileToken' should not end with 'Token'"
596+
),
597+
ValidationFailure(
598+
node: .generatedAttributeClauseFile,
599+
message: "child 'endOfFileToken' should not end with 'Token'"
600+
),
577601
]
578602
)
579603
}

Sources/SwiftParser/Availability.swift

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -304,20 +304,3 @@ 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/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_swift_syntax_library(SwiftParser
1111
Availability.swift
1212
CharacterInfo.swift
1313
CollectionNodes+Parsable.swift
14+
CompilerGeneratedFiles.swift
1415
Declarations.swift
1516
Directives.swift
1617
ExpressionInterpretedAsVersionTuple.swift
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if compiler(>=6)
14+
@_spi(RawSyntax) @_spi(ExperimentalLanguageFeatures) internal import SwiftSyntax
15+
#else
16+
@_spi(RawSyntax) @_spi(ExperimentalLanguageFeatures) import SwiftSyntax
17+
#endif
18+
19+
extension Parser {
20+
/// Parse an argument for `-define-availability` compiler option.
21+
mutating func parseAvailabilityMacroDefinitionFile() -> RawAvailabilityMacroDefinitionFileSyntax {
22+
let namedAndVersion = self.parsePlatformVersion(allowStarAsVersionNumber: false)
23+
let (unexpectedBetweenPlatformVersionAndColon, colon) = self.expect(.colon)
24+
let specs = self.parseAvailabilitySpecList()
25+
let unexpectedBeforeEndOfFileToken = consumeRemainingTokens()
26+
let endOfFile = self.consume(if: .endOfFile)!
27+
28+
return RawAvailabilityMacroDefinitionFileSyntax(
29+
platformVersion: namedAndVersion,
30+
unexpectedBetweenPlatformVersionAndColon,
31+
colon: colon,
32+
specs: specs,
33+
RawUnexpectedNodesSyntax(unexpectedBeforeEndOfFileToken, arena: self.arena),
34+
endOfFileToken: endOfFile,
35+
arena: self.arena
36+
)
37+
}
38+
39+
/// Parse an `accessor` macro expansion.
40+
mutating func parseGeneratedAccessorBlockFile() -> RawGeneratedAccessorBlockFileSyntax {
41+
let leftBrace = self.consume(if: .leftBrace)
42+
let accessors = self.parseAccessorList()
43+
let unexpectedBeforeRightBrace: RawUnexpectedNodesSyntax?
44+
let rightBrace: RawTokenSyntax?
45+
if leftBrace != nil {
46+
(unexpectedBeforeRightBrace, rightBrace) = self.expect(.rightBrace)
47+
} else {
48+
(unexpectedBeforeRightBrace, rightBrace) = (nil, nil)
49+
}
50+
let (unexpectedBeforeEndOfFileToken, endOfFile) = self.expect(.endOfFile)
51+
52+
return RawGeneratedAccessorBlockFileSyntax(
53+
leftBrace: leftBrace,
54+
accessors: accessors ?? RawAccessorDeclListSyntax(elements: [], arena: self.arena),
55+
unexpectedBeforeRightBrace,
56+
rightBrace: rightBrace,
57+
unexpectedBeforeEndOfFileToken,
58+
endOfFileToken: endOfFile,
59+
arena: self.arena
60+
)
61+
}
62+
63+
/// Parse a `memberAttribute` macro expansion, or `swift_attr` clang attribute.
64+
mutating func parseGeneratedAttributeClauseFile() -> RawGeneratedAttributeClauseFileSyntax {
65+
let attributes = self.parseAttributeList()
66+
let modifiers = self.parseDeclModifierList()
67+
let (unexpectedBeforeEndOfFileToken, endOfFile) = self.expect(.endOfFile)
68+
69+
return RawGeneratedAttributeClauseFileSyntax(
70+
attributes: attributes,
71+
modifiers: modifiers,
72+
unexpectedBeforeEndOfFileToken,
73+
endOfFileToken: endOfFile,
74+
arena: self.arena
75+
)
76+
}
77+
}

Sources/SwiftParser/generated/LayoutNodes+Parsable.swift

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ extension AttributeSyntax: SyntaxParseable {
7676
}
7777
}
7878

79-
extension AvailabilityMacroDefinitionSyntax: SyntaxParseable {
79+
extension AvailabilityMacroDefinitionFileSyntax: SyntaxParseable {
8080
public static func parse(from parser: inout Parser) -> Self {
8181
// Keep the parser alive so that the arena in which `raw` is allocated
8282
// doesn’t get deallocated before we have a chance to create a syntax node
@@ -88,7 +88,7 @@ extension AvailabilityMacroDefinitionSyntax: SyntaxParseable {
8888
withExtendedLifetime(parser) {
8989
}
9090
}
91-
let node = parser.parseAvailabilityMacroDefinition()
91+
let node = parser.parseAvailabilityMacroDefinitionFile()
9292
let raw = RawSyntax(parser.parseRemainder(into: node))
9393
return Syntax(raw: raw, rawNodeArena: raw.arena).cast(Self.self)
9494
}
@@ -238,6 +238,42 @@ extension FunctionParameterSyntax: SyntaxParseable {
238238
}
239239
}
240240

241+
extension GeneratedAccessorBlockFileSyntax: SyntaxParseable {
242+
public static func parse(from parser: inout Parser) -> Self {
243+
// Keep the parser alive so that the arena in which `raw` is allocated
244+
// doesn’t get deallocated before we have a chance to create a syntax node
245+
// from it. We can’t use `parser.arena` as the parameter to
246+
// `Syntax(raw:arena:)` because the node might have been re-used during an
247+
// incremental parse and would then live in a different arena than
248+
// `parser.arena`.
249+
defer {
250+
withExtendedLifetime(parser) {
251+
}
252+
}
253+
let node = parser.parseGeneratedAccessorBlockFile()
254+
let raw = RawSyntax(parser.parseRemainder(into: node))
255+
return Syntax(raw: raw, rawNodeArena: raw.arena).cast(Self.self)
256+
}
257+
}
258+
259+
extension GeneratedAttributeClauseFileSyntax: SyntaxParseable {
260+
public static func parse(from parser: inout Parser) -> Self {
261+
// Keep the parser alive so that the arena in which `raw` is allocated
262+
// doesn’t get deallocated before we have a chance to create a syntax node
263+
// from it. We can’t use `parser.arena` as the parameter to
264+
// `Syntax(raw:arena:)` because the node might have been re-used during an
265+
// incremental parse and would then live in a different arena than
266+
// `parser.arena`.
267+
defer {
268+
withExtendedLifetime(parser) {
269+
}
270+
}
271+
let node = parser.parseGeneratedAttributeClauseFile()
272+
let raw = RawSyntax(parser.parseRemainder(into: node))
273+
return Syntax(raw: raw, rawNodeArena: raw.arena).cast(Self.self)
274+
}
275+
}
276+
241277
extension GenericParameterClauseSyntax: SyntaxParseable {
242278
public static func parse(from parser: inout Parser) -> Self {
243279
// Keep the parser alive so that the arena in which `raw` is allocated

Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ extension SyntaxKind {
5555
return "availability condition"
5656
case .availabilityLabeledArgument:
5757
return "availability argument"
58-
case .availabilityMacroDefinition:
58+
case .availabilityMacroDefinitionFile:
5959
return "availability macro definition"
6060
case .awaitExpr:
6161
return "'await' expression"
@@ -197,6 +197,10 @@ extension SyntaxKind {
197197
return "function signature"
198198
case .functionType:
199199
return "function type"
200+
case .generatedAccessorBlockFile:
201+
return "accessors"
202+
case .generatedAttributeClauseFile:
203+
return "attribute list"
200204
case .genericArgumentClause:
201205
return "generic argument clause"
202206
case .genericArgument:

0 commit comments

Comments
 (0)