Superman/Sources/SupermanMacros/SupermanMacro.swift

63 lines
2.1 KiB
Swift
Raw Permalink Normal View History

2024-09-17 22:06:48 +00:00
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))"]
}
}