How to generate an enum with associated values using swift macros?

63 Views Asked by At

When trying to generate an enum with associated values, the generated enum is missing comma separating it's values.

This is the my expansion function (I'm using a PeermMacro)

public enum MyMacro: PeerMacro {

    public static func expansion(
        of _: AttributeSyntax,
        providingPeersOf _: some DeclSyntaxProtocol,
        in _: some MacroExpansionContext
    ) throws -> [DeclSyntax] {
        [
            DeclSyntax(
                EnumDeclSyntax(name: "MyEnum") {
                    EnumCaseDeclSyntax {
                        EnumCaseElementSyntax(
                            name: "myCase",
                            parameterClause: EnumCaseParameterClauseSyntax(
                                parameters: EnumCaseParameterListSyntax(
                                    [
                                        EnumCaseParameterSyntax(type: TypeSyntax("Int")),
                                        EnumCaseParameterSyntax(type: TypeSyntax("String"))
                                    ]
                                )
                            )
                        )
                    }
                }
            )
        ]
    }
}

The code above generates the following code, which doesn't compile because there's a comma missing between the associated values:

enum MyEnum {
    case myCase(Int String)
}

How can I update my expansion code so that the generated code contains comma between my associated values?

1

There are 1 best solutions below

0
Sweeper On BEST ANSWER

In the same way that you passed a result builder closure to EnumDeclSyntax and EnumCaseDeclSyntax, you can do that to EnumCaseParameterListSyntax too.

EnumCaseParameterListSyntax {
    EnumCaseParameterSyntax(type: TypeSyntax("Int")),
    EnumCaseParameterSyntax(type: TypeSyntax("String"))
)

Many of the AST nodes conform to ExpressibleByStringInterpolation, so you can further simplify this to

EnumCaseParameterListSyntax {
    "Int"
    "String"
)

In fact, given a list of enum case parameters, you can generate the whole enum declaration using an interpolated string literal:

static func enumDeclWithParameters(_ list: [EnumCaseParameterSyntax]) -> DeclSyntax {
    let parameterList = EnumCaseParameterListSyntax {
        for elem in list {
            elem
        }
    }
    return """
    enum MyEnum {
        case myCase(\(parameterList)
    }
    """
}