Skip to content

Commit 6342a41

Browse files
committed
[Macro plugin] Thread language mode and experimental features into the parser
The language mode and experimental features are available in the new static build configuration. When it's thread, thread them down into the parser used to create the syntax tree passed along macro implementations. This is the swift-syntax part of rdar://129687671.
1 parent 6666202 commit 6342a41

File tree

7 files changed

+127
-25
lines changed

7 files changed

+127
-25
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ let package = Package(
166166

167167
.target(
168168
name: "SwiftIfConfig",
169-
dependencies: ["SwiftSyntax", "SwiftSyntaxBuilder", "SwiftDiagnostics", "SwiftOperators"],
169+
dependencies: ["SwiftSyntax", "SwiftSyntaxBuilder", "SwiftDiagnostics", "SwiftOperators", "SwiftParser"],
170170
exclude: ["CMakeLists.txt"]
171171
),
172172

Sources/SwiftCompilerPluginMessageHandling/Macros.swift

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@
1313
#if compiler(>=6)
1414
internal import SwiftBasicFormat
1515
internal import SwiftDiagnostics
16-
internal import SwiftIfConfig
16+
@_spi(ExperimentalLanguageFeatures) internal import SwiftIfConfig
1717
internal import SwiftOperators
18+
@_spi(ExperimentalLanguageFeatures) internal import SwiftParser
1819
internal import SwiftSyntax
1920
@_spi(MacroExpansion) @_spi(ExperimentalLanguageFeature) internal import SwiftSyntaxMacroExpansion
2021
@_spi(ExperimentalLanguageFeature) internal import SwiftSyntaxMacros
2122
#else
2223
import SwiftBasicFormat
2324
import SwiftDiagnostics
24-
import SwiftIfConfig
25+
@_spi(ExperimentalLanguageFeatures) import SwiftIfConfig
2526
import SwiftOperators
27+
@_spi(ExperimentalLanguageFeatures) import SwiftParser
2628
import SwiftSyntax
2729
@_spi(MacroExpansion) @_spi(ExperimentalLanguageFeature) import SwiftSyntaxMacroExpansion
2830
@_spi(ExperimentalLanguageFeature) import SwiftSyntaxMacros
@@ -38,6 +40,8 @@ extension PluginProviderMessageHandler {
3840
private static func resolveLexicalContext(
3941
_ lexicalContext: [PluginMessage.Syntax]?,
4042
sourceManager: SourceManager,
43+
swiftVersion: Parser.SwiftVersion?,
44+
experimentalFeatures: Parser.ExperimentalFeatures?,
4145
operatorTable: OperatorTable,
4246
fallbackSyntax: some SyntaxProtocol
4347
) -> [Syntax] {
@@ -47,7 +51,14 @@ extension PluginProviderMessageHandler {
4751
return fallbackSyntax.allMacroLexicalContexts()
4852
}
4953

50-
return lexicalContext.map { sourceManager.add($0, foldingWith: operatorTable) }
54+
return lexicalContext.map {
55+
sourceManager.add(
56+
$0,
57+
swiftVersion: swiftVersion,
58+
experimentalFeatures: experimentalFeatures,
59+
foldingWith: operatorTable
60+
)
61+
}
5162
}
5263

5364
/// Expand `@freestainding(XXX)` macros.
@@ -60,13 +71,22 @@ extension PluginProviderMessageHandler {
6071
lexicalContext: [PluginMessage.Syntax]?
6172
) -> PluginToHostMessage {
6273
let sourceManager = SourceManager(syntaxRegistry: syntaxRegistry)
63-
let syntax = sourceManager.add(expandingSyntax, foldingWith: .standardOperators)
74+
let swiftVersion = staticBuildConfiguration?.parserSwiftVersion
75+
let experimentalFeatures = staticBuildConfiguration?.experimentalFeatures
76+
let syntax = sourceManager.add(
77+
expandingSyntax,
78+
swiftVersion: swiftVersion,
79+
experimentalFeatures: experimentalFeatures,
80+
foldingWith: .standardOperators
81+
)
6482

6583
let context = PluginMacroExpansionContext(
6684
sourceManager: sourceManager,
6785
lexicalContext: Self.resolveLexicalContext(
6886
lexicalContext,
6987
sourceManager: sourceManager,
88+
swiftVersion: swiftVersion,
89+
experimentalFeatures: experimentalFeatures,
7090
operatorTable: .standardOperators,
7191
fallbackSyntax: syntax
7292
),
@@ -126,17 +146,27 @@ extension PluginProviderMessageHandler {
126146
lexicalContext: [PluginMessage.Syntax]?
127147
) -> PluginToHostMessage {
128148
let sourceManager = SourceManager(syntaxRegistry: syntaxRegistry)
129-
let attributeNode = sourceManager.add(
130-
attributeSyntax,
131-
foldingWith: .standardOperators
132-
).cast(AttributeSyntax.self)
133-
let declarationNode = sourceManager.add(declSyntax)
134-
let parentDeclNode = parentDeclSyntax.map { sourceManager.add($0).cast(DeclSyntax.self) }
149+
let swiftVersion = staticBuildConfiguration?.parserSwiftVersion
150+
let experimentalFeatures = staticBuildConfiguration?.experimentalFeatures
151+
152+
func addToSourceManager(_ syntax: PluginMessage.Syntax) -> Syntax {
153+
sourceManager.add(
154+
attributeSyntax,
155+
swiftVersion: swiftVersion,
156+
experimentalFeatures: experimentalFeatures,
157+
foldingWith: .standardOperators
158+
)
159+
}
160+
161+
let attributeNode = addToSourceManager(attributeSyntax)
162+
.cast(AttributeSyntax.self)
163+
let declarationNode = addToSourceManager(declSyntax)
164+
let parentDeclNode = parentDeclSyntax.map { addToSourceManager($0).cast(DeclSyntax.self) }
135165
let extendedType = extendedTypeSyntax.map {
136-
sourceManager.add($0).cast(TypeSyntax.self)
166+
addToSourceManager($0).cast(TypeSyntax.self)
137167
}
138168
let conformanceList = conformanceListSyntax.map {
139-
let placeholderStruct = sourceManager.add($0).cast(StructDeclSyntax.self)
169+
let placeholderStruct = addToSourceManager($0).cast(StructDeclSyntax.self)
140170
return placeholderStruct.inheritanceClause!.inheritedTypes
141171
}
142172

@@ -145,6 +175,8 @@ extension PluginProviderMessageHandler {
145175
lexicalContext: Self.resolveLexicalContext(
146176
lexicalContext,
147177
sourceManager: sourceManager,
178+
swiftVersion: swiftVersion,
179+
experimentalFeatures: experimentalFeatures,
148180
operatorTable: .standardOperators,
149181
fallbackSyntax: declarationNode
150182
),

Sources/SwiftCompilerPluginMessageHandling/PluginMacroExpansionContext.swift

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
internal import SwiftDiagnostics
1515
internal import SwiftIfConfig
1616
internal import SwiftOperators
17-
internal import SwiftParser
17+
@_spi(ExperimentalLanguageFeatures) internal import SwiftParser
1818
internal import SwiftSyntax
1919
internal import SwiftSyntaxMacros
2020
#else
2121
import SwiftDiagnostics
2222
import SwiftIfConfig
2323
import SwiftOperators
24-
import SwiftParser
24+
@_spi(ExperimentalLanguageFeatures) import SwiftParser
2525
import SwiftSyntax
2626
import SwiftSyntaxMacros
2727
#endif
@@ -31,6 +31,8 @@ class ParsedSyntaxRegistry {
3131
struct Key: Hashable {
3232
let source: String
3333
let kind: PluginMessage.Syntax.Kind
34+
let swiftVersion: Parser.SwiftVersion
35+
let experimentalFeatures: Parser.ExperimentalFeatures
3436
}
3537

3638
private var storage: LRUCache<Key, Syntax>
@@ -39,8 +41,17 @@ class ParsedSyntaxRegistry {
3941
self.storage = LRUCache(capacity: cacheCapacity)
4042
}
4143

42-
private func parse(source: String, kind: PluginMessage.Syntax.Kind) -> Syntax {
43-
var parser = Parser(source)
44+
private func parse(
45+
source: String,
46+
kind: PluginMessage.Syntax.Kind,
47+
swiftVersion: Parser.SwiftVersion,
48+
experimentalFeatures: Parser.ExperimentalFeatures
49+
) -> Syntax {
50+
var parser = Parser(
51+
source,
52+
swiftVersion: swiftVersion,
53+
experimentalFeatures: experimentalFeatures
54+
)
4455
switch kind {
4556
case .declaration:
4657
return Syntax(DeclSyntax.parse(from: &parser))
@@ -57,13 +68,30 @@ class ParsedSyntaxRegistry {
5768
}
5869
}
5970

60-
func get(source: String, kind: PluginMessage.Syntax.Kind) -> Syntax {
61-
let key = Key(source: source, kind: kind)
71+
func get(
72+
source: String,
73+
kind: PluginMessage.Syntax.Kind,
74+
swiftVersion: Parser.SwiftVersion?,
75+
experimentalFeatures: Parser.ExperimentalFeatures?
76+
) -> Syntax {
77+
let swiftVersion = swiftVersion ?? Parser.defaultSwiftVersion
78+
let experimentalFeatures = experimentalFeatures ?? Parser.ExperimentalFeatures()
79+
let key = Key(
80+
source: source,
81+
kind: kind,
82+
swiftVersion: swiftVersion,
83+
experimentalFeatures: experimentalFeatures
84+
)
6285
if let cached = storage[key] {
6386
return cached
6487
}
6588

66-
let node = parse(source: source, kind: kind)
89+
let node = parse(
90+
source: source,
91+
kind: kind,
92+
swiftVersion: swiftVersion,
93+
experimentalFeatures: experimentalFeatures
94+
)
6795
storage[key] = node
6896
return node
6997
}
@@ -126,10 +154,17 @@ class SourceManager {
126154
/// are cached in the source manager to provide `location(of:)` et al.
127155
func add(
128156
_ syntaxInfo: PluginMessage.Syntax,
129-
foldingWith operatorTable: OperatorTable? = nil
157+
swiftVersion: Parser.SwiftVersion?,
158+
experimentalFeatures: Parser.ExperimentalFeatures?,
159+
foldingWith operatorTable: OperatorTable?,
130160
) -> Syntax {
131161

132-
var node = syntaxRegistry.get(source: syntaxInfo.source, kind: syntaxInfo.kind)
162+
var node = syntaxRegistry.get(
163+
source: syntaxInfo.source,
164+
kind: syntaxInfo.kind,
165+
swiftVersion: swiftVersion,
166+
experimentalFeatures: experimentalFeatures
167+
)
133168
if let operatorTable {
134169
node = operatorTable.foldAll(node, errorHandler: { _ in /*ignore*/ })
135170
}

Sources/SwiftIfConfig/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ target_link_swift_syntax_libraries(SwiftIfConfig PUBLIC
2828
SwiftSyntax
2929
SwiftSyntaxBuilder
3030
SwiftDiagnostics
31-
SwiftOperators)
31+
SwiftOperators
32+
SwiftParser)

Sources/SwiftIfConfig/StaticBuildConfiguration.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#if compiler(>=6)
14+
@_spi(ExperimentalLanguageFeatures) public import SwiftParser
15+
public import SwiftSyntax
16+
#else
17+
@_spi(ExperimentalLanguageFeatures) import SwiftParser
1318
import SwiftSyntax
19+
#endif
1420

1521
/// A statically-determined build configuration that can be used with any
1622
/// API that requires a build configuration. Static build configurations can
@@ -366,3 +372,31 @@ extension StaticBuildConfiguration {
366372
case canImportUnavailable
367373
}
368374
}
375+
376+
extension StaticBuildConfiguration {
377+
/// The Swift version that can be set for the parser.
378+
public var parserSwiftVersion: Parser.SwiftVersion {
379+
if languageVersion < VersionTuple(5) {
380+
return .v4
381+
} else if languageVersion < VersionTuple(6) {
382+
return .v5
383+
} else if languageVersion < VersionTuple(7) {
384+
return .v6
385+
} else {
386+
return Parser.defaultSwiftVersion
387+
}
388+
}
389+
390+
/// Determine the set of experimental features that are enabled by this
391+
/// static build configuration.
392+
@_spi(ExperimentalLanguageFeatures)
393+
public var experimentalFeatures: Parser.ExperimentalFeatures {
394+
var result: Parser.ExperimentalFeatures = []
395+
for feature in features {
396+
if let experimentalFeature = Parser.ExperimentalFeatures(name: feature) {
397+
result.insert(experimentalFeature)
398+
}
399+
}
400+
return result
401+
}
402+
}

Sources/SwiftParser/Parser.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public struct Parser {
137137
#endif
138138

139139
/// The Swift version as which source files should be parsed if no Swift version is explicitly specified in the parser.
140-
static let defaultSwiftVersion: SwiftVersion = .v6
140+
public static let defaultSwiftVersion: SwiftVersion = .v6
141141

142142
var _emptyRawMultipleTrailingClosureElementListSyntax: RawMultipleTrailingClosureElementListSyntax?
143143

Sources/SwiftParser/generated/ExperimentalFeatures.swift

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)