Creating a type from a Symbol inside a macro of a submodule?

I am sorry if this is trivial, but I am trying to access the fields of a type, which is passed as a Symbol to a macro inside a submodule (in an imported one).

Here is what I mean:

struct Foo end
​
macro macro1(ex)
    eval(ex)
end
​
module SomeModule
    macro macro2(ex)
        eval(ex)
    end
end
​
println(@macro1 Foo)
# Foo

println(@SomeModule.macro2 Foo)
# UndefVarError: Foo not defined

Background: I am trying to retrieve the fieldnames and their types to create new structs dynamically. For this, I want to pass into a macro a series of types (which arrive there as Symbols. As far as I can see this is the most transparent way for the user, i.e. @stack Foo Bar Baz…) and return an expression which creates a new struct with the concatenated fields.

This works:

julia> module SM
       macro m2(ex)
       Core.eval(__module__, ex)
       end
       end
Main.SM

julia> @SM.m2(Foo)
Foo

Presumably, you are aware of “don’t use eval in macros”.

PS: where did your code come from, if I paste it I get ERROR: syntax: invisible character \u200b near column 1?

1 Like

Thanks Mauro, I was playing around with @__MODULE__ but could not get it to work.

Presumably, you are aware of “don’t use eval in macros”.

Yes, I just used it in the example. I will use getfield() to get the actual type. I should have used that in my example…

I guess this is the right way then? I am however not sure about that warning.

struct Foo end
​
macro macro1(ex)
    getfield(@__MODULE__, ex)
end
​
module SomeModule
    macro macro2(ex)
        getfield(__module__, ex)
    end
end
​
println(@macro1 Foo)
println(@SomeModule.macro2 Foo)
# Foo
# Foo
# WARNING: replacing module SomeModule.

PS: where did your code come from, if I paste it I get ERROR: syntax: invisible character \u200b near column 1 ?

oh, well, that was coming from Jupyter, that’s weird… I had some issues in the past with some invisibles coming from TAB completion, probably that’s the reason.

To end the story, this is what I got:

macro stack(into, structs...)
     fields = []
     for _struct in structs
         names = fieldnames(getfield(__module__, _struct))
         types = fieldtypes(getfield(__module__, _struct))
         for (n, t) in zip(names, types)
             push!(fields, :($n::$t))
         end
     end

     esc(
         quote
             struct $into
                 $(fields...)
             end
         end
     )
 end

Here is it in action:

julia> using Mixers

julia> struct Foo
         x::Int32
       end

julia> struct Bar
         y::Int64
       end

julia> @stack Baz Foo Bar

julia> fieldnames(Baz)
(:x, :y)

julia> fieldtypes(Baz)
(Int32, Int64)

…and I think it fits into Add @stack which stacks multiple structs into one. Closes #4 by tamasgal · Pull Request #5 · rafaqz/Mixers.jl · GitHub

1 Like