Initial commit
This commit is contained in:
commit
b10e75dcd9
|
@ -0,0 +1,8 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"originHash" : "e51397b3369f3d57e433298148acc6f90a2116f05c1952cc811f11150b1ce7c1",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "swift-syntax",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-syntax.git",
|
||||
"state" : {
|
||||
"revision" : "cb53fa1bd3219b0b23ded7dfdd3b2baff266fd25",
|
||||
"version" : "600.0.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// swift-tools-version: 6.0
|
||||
|
||||
import PackageDescription
|
||||
import CompilerPluginSupport
|
||||
|
||||
let package = Package(
|
||||
name: "Superman",
|
||||
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6), .macCatalyst(.v13)],
|
||||
products: [
|
||||
.library(
|
||||
name: "Superman",
|
||||
targets: ["Superman"]
|
||||
),
|
||||
.executable(
|
||||
name: "SupermanSample",
|
||||
targets: ["SupermanSample"]
|
||||
),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/apple/swift-syntax.git", from: "600.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.macro(
|
||||
name: "SupermanMacros",
|
||||
dependencies: [
|
||||
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
|
||||
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
|
||||
]
|
||||
),
|
||||
.target(name: "Superman", dependencies: ["SupermanMacros"]),
|
||||
.executableTarget(name: "SupermanSample", dependencies: ["Superman"]),
|
||||
.testTarget(
|
||||
name: "SupermanTests",
|
||||
dependencies: [
|
||||
"SupermanMacros",
|
||||
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
@attached(body)
|
||||
public macro SuperFirst() = #externalMacro(module: "SupermanMacros", type: "SuperFirstMacro")
|
||||
|
||||
@attached(body)
|
||||
public macro SuperLast() = #externalMacro(module: "SupermanMacros", type: "SuperLastMacro")
|
|
@ -0,0 +1,9 @@
|
|||
enum Error: Swift.Error, CustomStringConvertible {
|
||||
case message(String)
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .message(let text): return text
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
import SwiftCompilerPlugin
|
||||
import SwiftSyntax
|
||||
import SwiftSyntaxMacros
|
||||
|
||||
@main
|
||||
struct SupermanPlugin: CompilerPlugin {
|
||||
let providingMacros: [Macro.Type] = [
|
||||
SuperFirstMacro.self,
|
||||
SuperLastMacro.self,
|
||||
]
|
||||
}
|
||||
|
||||
public struct SuperFirstMacro: BodyMacro {
|
||||
public static func expansion(of node: AttributeSyntax,
|
||||
providingBodyFor declaration: some DeclSyntaxProtocol & WithOptionalCodeBlockSyntax,
|
||||
in context: some MacroExpansionContext) throws -> [CodeBlockItemSyntax] {
|
||||
// Only allow Functions
|
||||
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
|
||||
throw Error.message("@SuperFirst only works on functions")
|
||||
}
|
||||
|
||||
// Only allow Void Functions
|
||||
guard funcDecl.signature.returnClause?.type.as(IdentifierTypeSyntax.self)?.name.text != "Void" else {
|
||||
throw Error.message("@SuperFirst only works on Void functions")
|
||||
}
|
||||
|
||||
// Requires Function Body
|
||||
guard let funcBody = funcDecl.body else {
|
||||
throw Error.message("@SuperFirst only works on functions with bodies")
|
||||
}
|
||||
|
||||
let arguments = funcDecl.signature.parameterClause.parameters
|
||||
let callArgs = arguments.map { argument in
|
||||
"\(argument.firstName): \(argument.secondName ?? argument.firstName)"
|
||||
}.joined(separator: ", ")
|
||||
|
||||
return ["super.\(funcDecl.name)(\(raw: callArgs))"] + Array(funcBody.statements)
|
||||
}
|
||||
}
|
||||
|
||||
public struct SuperLastMacro: BodyMacro {
|
||||
public static func expansion(of node: AttributeSyntax,
|
||||
providingBodyFor declaration: some DeclSyntaxProtocol & WithOptionalCodeBlockSyntax,
|
||||
in context: some MacroExpansionContext) throws -> [CodeBlockItemSyntax] {
|
||||
// Only allow Functions
|
||||
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
|
||||
throw Error.message("@SuperLast only works on functions")
|
||||
}
|
||||
|
||||
// Requires Function Body
|
||||
guard let funcBody = funcDecl.body else {
|
||||
throw Error.message("@SuperLast only works on functions with bodies")
|
||||
}
|
||||
|
||||
let arguments = funcDecl.signature.parameterClause.parameters
|
||||
let callArgs = arguments.map { argument in
|
||||
"\(argument.firstName): \(argument.secondName ?? argument.firstName)"
|
||||
}.joined(separator: ", ")
|
||||
|
||||
return Array(funcBody.statements) + ["return super.\(funcDecl.name)(\(raw: callArgs))"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import Superman
|
||||
|
||||
class Base {
|
||||
func superFirst() {
|
||||
print("Base superFirst")
|
||||
}
|
||||
|
||||
func superFirstArgs(_ b: Bool, i: Int, double d: Double) {
|
||||
print("Base superFirstArgs (\(b), \(i), \(d))")
|
||||
}
|
||||
|
||||
func superLast() {
|
||||
print("Base superLast")
|
||||
}
|
||||
|
||||
func superLastArgs(_ b: Bool, i: Int, double d: Double) {
|
||||
print("Base superLastArgs (\(b), \(i), \(d))")
|
||||
}
|
||||
}
|
||||
|
||||
class Child: Base {
|
||||
@SuperFirst
|
||||
override func superFirst() {
|
||||
print("Child superFirst")
|
||||
}
|
||||
|
||||
@SuperFirst
|
||||
override func superFirstArgs(_ b: Bool, i: Int, double d: Double) {
|
||||
print("Child superFirstArgs (\(b), \(i), \(d))")
|
||||
}
|
||||
|
||||
@SuperLast
|
||||
override func superLast() {
|
||||
print("Child superLast")
|
||||
}
|
||||
|
||||
@SuperLast
|
||||
override func superLastArgs(_ b: Bool, i: Int, double d: Double) {
|
||||
print("Child superLastArgs (\(b), \(i), \(d))")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
let child = Child()
|
||||
child.superFirst()
|
||||
child.superLast()
|
||||
child.superFirstArgs(true, i: 1, double: 0.1)
|
||||
child.superLastArgs(false, i: 0, double: 1.0)
|
||||
}
|
||||
main()
|
|
@ -0,0 +1,79 @@
|
|||
import SwiftSyntaxMacros
|
||||
import SwiftSyntaxMacrosTestSupport
|
||||
import XCTest
|
||||
|
||||
#if canImport(SupermanMacros)
|
||||
import SupermanMacros
|
||||
|
||||
let testMacros: [String: Macro.Type] = [
|
||||
"SuperFirst": SuperFirstMacro.self,
|
||||
"SuperLast": SuperLastMacro.self,
|
||||
]
|
||||
|
||||
final class QSLibsTests: XCTestCase {
|
||||
func testSuperFirst() throws {
|
||||
assertMacroExpansion("""
|
||||
@SuperFirst
|
||||
func function() {
|
||||
print()
|
||||
}
|
||||
""",
|
||||
expandedSource: """
|
||||
func function() {
|
||||
super.function()
|
||||
print()
|
||||
}
|
||||
""",
|
||||
macros: testMacros)
|
||||
}
|
||||
|
||||
func testSuperLast() throws {
|
||||
assertMacroExpansion("""
|
||||
@SuperLast
|
||||
func function() {
|
||||
print()
|
||||
}
|
||||
""",
|
||||
expandedSource: """
|
||||
func function() {
|
||||
print()
|
||||
return super.function()
|
||||
}
|
||||
""",
|
||||
macros: testMacros)
|
||||
}
|
||||
|
||||
func testSuperFirstArgs() throws {
|
||||
assertMacroExpansion("""
|
||||
@SuperFirst
|
||||
func function(_ b: Bool, i: Int, double d: Double) {
|
||||
print()
|
||||
}
|
||||
""",
|
||||
expandedSource: """
|
||||
func function(_ b: Bool, i: Int, double d: Double) {
|
||||
super.function(_ : b, i: i, double : d)
|
||||
print()
|
||||
}
|
||||
""",
|
||||
macros: testMacros)
|
||||
}
|
||||
|
||||
func testSuperLastArgs() throws {
|
||||
assertMacroExpansion("""
|
||||
@SuperLast
|
||||
func function(_ b: Bool, i: Int, double d: Double) {
|
||||
print()
|
||||
}
|
||||
""",
|
||||
expandedSource: """
|
||||
func function(_ b: Bool, i: Int, double d: Double) {
|
||||
print()
|
||||
return super.function(_ : b, i: i, double : d)
|
||||
}
|
||||
""",
|
||||
macros: testMacros)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue