Swift 宏:ReturnClause语法

Swift Macros: ReturnClauseSyntax

提问人:Mar-k 提问时间:8/23/2023 更新时间:8/24/2023 访问量:77

问:

我正在对新的 Swift 宏进行一些测试和弄清楚,但我遇到了一个我似乎无法弄清楚的障碍,也是因为还没有很多有用的指南。

因此,首先,如果宏的设备是个好主意,我们暂时将其放在一边。

我试图实现的是创建一个宏,该宏会自动将服务添加到具有所有基本 REST 操作(如 、 、 等)的 服务。@attached(member)structget(id: String)patch()getAll()delete(id: String)

所以我在实现方面走得很远,但我似乎无法弄清楚如何创建它应该只返回添加宏的类型的实例。请参阅下面的代码示例:ReturnClauseSyntax

public struct ServiceMacro: MemberMacro {
    public static func expansion(
        of node: SwiftSyntax.AttributeSyntax,
        providingMembersOf declaration: some SwiftSyntax.DeclGroupSyntax,
        in context: some SwiftSyntaxMacros.MacroExpansionContext
    ) throws -> [SwiftSyntax.DeclSyntax] {
        guard let structDecl = declaration.as(StructDeclSyntax.self) else {
            // TODO: Emit an error
            return []
        }
        
        let initializer = try EnumDeclSyntax("enum Service") {
            FunctionDeclSyntax(
                funcKeyword: "static func",
                name: "get",
                signature: FunctionSignatureSyntax(
                    parameterClause: FunctionParameterClauseSyntax(
                        parameters: FunctionParameterListSyntax(
                            arrayLiteral: FunctionParameterSyntax(
                                stringLiteral: "id: String"
                            )
                        )
                    ),
                    trailingTrivia: .init(stringLiteral: " -> \(structDecl.name.trimmed)")
                ),
                bodyBuilder: {
                    "return \(structDecl.name.trimmed)()"
                }
            )
        }

        return [DeclSyntax(initializer)]
    }
}

因此,这导致了以下扩展:

@Service
struct Recipe {
    enum Service {
       static func get(id: String) -> Recipe {
           return Recipe()
       }
    }
}

但是,正如您在宏实现代码中看到的那样,我正在使用 一个感觉不对且可能不对的 来设置尾随琐事。stringLiteral

现在我想知道如何通过使用期望 .我现在只是希望它返回它所应用的结构的实例。returnClauseReturnClauseSyntax

也许这真的很容易,但我在文档中找不到它,而且这整个语法对我来说都是新的,所以如果有人能为我指出正确的方向,那将非常有帮助。

此外,我们非常欢迎关于实施的其他建议,因为这对我和很多人来说可能是新的。

swift-macro

评论


答:

1赞 La pieuvre 8/24/2023 #1

事实上,这并不难。

您可以像这样检索您正在处理的结构的类型名称

guard let name = declaration.as(StructDeclSyntax.self)?.name.text
else {return []}

然后你可以把它转换成一个TypeSyntax,并将其传递给初始化器的type参数,如下所示:ReturnClauseSyntax

ReturnClauseSyntax(type: TypeSyntax(stringLiteral: name)

现在您可以将所有这些组合在一起:

public struct ServiceMacro: MemberMacro {
    public static func expansion(
        of node: SwiftSyntax.AttributeSyntax,
        providingMembersOf declaration: some SwiftSyntax.DeclGroupSyntax,
        in context: some SwiftSyntaxMacros.MacroExpansionContext
    ) throws -> [SwiftSyntax.DeclSyntax] {
        guard let structDecl = declaration.as(StructDeclSyntax.self) else {
            // TODO: Emit an error
            return []
        }
        let name = structDecl.name.text
        let initializer = try EnumDeclSyntax("enum Service") {
            FunctionDeclSyntax(
                funcKeyword: "static func",
                name: "get",
                signature: FunctionSignatureSyntax(
                    parameterClause: FunctionParameterClauseSyntax(
                        parameters: FunctionParameterListSyntax(
                            arrayLiteral: FunctionParameterSyntax(
                                stringLiteral: "id: String"
                            )
                        )
                    ),
                    returnClause: ReturnClauseSyntax(type: TypeSyntax(stringLiteral: name)
                ),
                bodyBuilder: {
                    "return \(structDecl.name.trimmed)()"
                }
            )
        }

        return [DeclSyntax(initializer)]
    }
}