Help me implement this simple Macro

I want to implement a simple freestanding macro but having difficulty implementing it.

I have a macro that accepts an instance of a struct

@freestanding(expression)
public macro rawValue(_ value: MyStruct) -> String = #externalMacro(module: "MyMacros", type: "RawValueMacro")

struct MyStruct: RawRepresentable {
    let rawValue: String
}

extension MyStruct {
    static let foo: Self = .init(rawValue: "bar")
}

I want simply in the client to expand #rawValue(.foo) to be "bar".

Now in the MyMacros module, I have

public struct RawValueMacro: ExpressionMacro {
    
    public static func expansion(
        of node: some FreestandingMacroExpansionSyntax,
        in context: some MacroExpansionContext
    ) -> ExprSyntax {

       // ??
    }
}

I hope that my goal is possible with Swift Macros

The problem I see is how to access the rawValue property from inside the macro itself.

A macro only has access to the syntax it's invoked with, so it can't see syntax "in some other place".

I presume this is a simplified problem, but you could have your macro expand #rawValue(.foo) to MyStruct.foo.rawValue, which will have the desired string value.

Alternatively, you could embed the table of raw values into the macro, so it already knows to map .foo to "bar".

1 Like

MyStruct and MyStruct.foo have to be visible for #rawValue(.foo) to compile, so I don't see why MyStruct.foo.rawValue wouldn't?

1 Like

Here is my attempt as something sort of similar… passing a value from an app as a macro parameter and then "unboxing" that parameter at runtime in the macro expansion. For my example… it was a system type (SortOrder) that did not conform to RawRepresentable (which made things a little more difficult).

Since you have a parameter that does confirm to RawRepresentable… I think you have an extra option here. You could define a "shadow" declaration of MyStruct that lives along RawValueMacro (and then use that logic in your macro expansion)… or you could try to factor MyStruct out to some kind of "macro defs" module that can be imported by both the macro library and the client library (assuming this does not lead to some kind of dep cycle).

1 Like