Skip to content

Commit e14b79c

Browse files
authored
[Macros] Support user-defined macros as compiler plugins (#1022)
Make `Macro` refine `_CompilerPlugin` protocol when `_CompilerPluginSupport` exists. (`_CompilerPluginSupport` may not exist when ASTGen or SwiftCompilerSources is built with host tools.) This enables macros to talk to the compiler without an ABI-stable SwiftSyntax. Friend PR: swiftlang/swift#61734
1 parent ecce219 commit e14b79c

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

Sources/_SwiftSyntaxMacros/ExpressionMacro.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import SwiftSyntax
14+
import SwiftParser
15+
#if canImport(_CompilerPluginSupport)
16+
import _CompilerPluginSupport
17+
#endif
1418

1519
/// Describes a macro that is explicitly expanded as an expression.
1620
public protocol ExpressionMacro: Macro {
@@ -20,3 +24,57 @@ public protocol ExpressionMacro: Macro {
2024
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
2125
) -> MacroResult<ExprSyntax>
2226
}
27+
28+
#if canImport(_CompilerPluginSupport)
29+
extension ExpressionMacro {
30+
public static func _kind() -> _CompilerPluginKind {
31+
.expressionMacro
32+
}
33+
34+
public static func _rewrite(
35+
targetModuleName: UnsafePointer<UInt8>,
36+
targetModuleNameCount: Int,
37+
filePath: UnsafePointer<UInt8>,
38+
filePathCount: Int,
39+
sourceFileText: UnsafePointer<UInt8>,
40+
sourceFileTextCount: Int,
41+
localSourceText: UnsafePointer<UInt8>,
42+
localSourceTextCount: Int
43+
) -> (UnsafePointer<UInt8>?, count: Int) {
44+
let targetModuleNameBuffer = UnsafeBufferPointer(
45+
start: filePath, count: targetModuleNameCount)
46+
let targetModuleName = String(
47+
decoding: targetModuleNameBuffer, as: UTF8.self)
48+
let filePathBuffer = UnsafeBufferPointer(
49+
start: filePath, count: filePathCount)
50+
let filePath = String(decoding: filePathBuffer, as: UTF8.self)
51+
let sourceFileTextBuffer = UnsafeBufferPointer(
52+
start: sourceFileText, count: sourceFileTextCount)
53+
let sourceFileString = String(decoding: sourceFileTextBuffer, as: UTF8.self)
54+
let sourceFileSyntax = Parser.parse(source: sourceFileString)
55+
let converter = SourceLocationConverter(
56+
file: filePath, tree: sourceFileSyntax)
57+
let context = MacroEvaluationContext(
58+
moduleName: targetModuleName, sourceLocationConverter: converter)
59+
let meePosition = AbsolutePosition(
60+
utf8Offset: localSourceText.distance(to: localSourceText))
61+
guard let meeStartToken = sourceFileSyntax.token(at: meePosition),
62+
let mee = meeStartToken.parent?.as(MacroExpansionExprSyntax.self)
63+
else {
64+
fatalError("Unable to locate 'MacroExpansionExprSyntax'")
65+
}
66+
67+
// Evaluate the macro.
68+
let evalResult = apply(mee, in: context)
69+
70+
var resultString = "\(evalResult.rewritten)"
71+
return resultString.withUTF8 { buffer in
72+
let result = UnsafeMutableBufferPointer<UInt8>.allocate(
73+
capacity: buffer.count + 1)
74+
_ = result.initialize(from: buffer)
75+
result[buffer.count] = 0
76+
return (UnsafePointer(result.baseAddress), buffer.count)
77+
}
78+
}
79+
}
80+
#endif

Sources/_SwiftSyntaxMacros/Macro.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,16 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
1213
import SwiftSyntax
14+
#if canImport(_CompilerPluginSupport)
15+
import _CompilerPluginSupport
16+
#else
17+
public typealias _CompilerPlugin = Any
18+
#endif
1319

1420
/// Describes a macro.
15-
public protocol Macro {
21+
public protocol Macro: _CompilerPlugin {
1622
/// The name of this macro.
1723
static var name: String { get }
1824

@@ -39,3 +45,16 @@ extension Macro {
3945
/// Default, empty documentation string for macros.
4046
public static var documentation: String { "" }
4147
}
48+
49+
#if canImport(_CompilerPluginSupport)
50+
extension Macro {
51+
public static func _name() -> (UnsafePointer<UInt8>, count: Int) {
52+
var name = name
53+
return name.withUTF8 { buffer in
54+
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
55+
result.initialize(from: buffer.baseAddress!, count: buffer.count)
56+
return (UnsafePointer(result), count: buffer.count)
57+
}
58+
}
59+
}
60+
#endif

0 commit comments

Comments
 (0)