How to print human-readable macro expansion?

Sometimes I’d like to check what a macro is doing, by displaying its expansion. For simple cases, this is not a problem:

julia> @macroexpand(@assert 0<1)
:(if 0 < 1
      nothing
  else
      Base.throw(Base.AssertionError("0 < 1"))
  end)

The output is very understandable here. But when I try to expand the @enum macro, the output seems completely incomprehensible:

julia> Base.remove_linenums!(
           @macroexpand(@enum Fruit apple)
       )
:($(Expr(:toplevel, :(#= Enums.jl:190 =#), quote
    $(Expr(:meta, :doc))
    primitive type Fruit <: Base.Enums.Enum{Int32} 32 end
end, :(#= Enums.jl:191 =#), :(function Fruit(var"#3#x"::Base.Enums.Integer)
      (0 Base.Enums.:<= var"#3#x" Base.Enums.:<= 0) || Base.Enums.enum_argument_error(:Fruit, var"#3#x")
      return Base.Enums.bitcast(Fruit, Base.Enums.convert(Int32, var"#3#x"))
  end), :(#= Enums.jl:195 =#), :((Base.Enums.Enums).namemap(::Base.Enums.Type{Fruit}) = begin
          Dict{Int32, Symbol}(0 => :apple)
      end), :(#= Enums.jl:196 =#), :((Base.Enums.Base).typemin(var"#5#x"::Base.Enums.Type{Fruit}) = begin
          Fruit(0)
      end), :(#= Enums.jl:197 =#), :((Base.Enums.Base).typemax(var"#6#x"::Base.Enums.Type{Fruit}) = begin
          Fruit(0)
      end), :(#= Enums.jl:198 =#), :(let var"#1#insts" = (Base.Enums.Any[Fruit(var"#2#v") for var"#2#v" = Int32[0]]...,)
      (Base.Enums.Base).instances(::Base.Enums.Type{Fruit}) = begin
              var"#1#insts"
          end
  end), :(const apple = Fruit(0)), :(Base.Enums.nothing))))

Is there some way to understand the code above? Generally, is it possible to print macro expansions in a form that looks like human-authored source code, e.g. if you want to directly insert the expanded code into a source file?

The code is often better to read/comprehend:

julia> @less @enum Fruit apple
macro enum(T::Union{Symbol,Expr}, syms...)
    if isempty(syms)
        throw(ArgumentError("no arguments given for Enum $T"))
    end
    basetype = Int32
    ...

You can also open the source file:

julia> @which @enum Fruit apple
var"@enum"(__source__::LineNumberNode, __module__::Module, T::Union{Expr, Symbol}, syms...)
 in Base.Enums at Enums.jl:123

with an editor of your choice.

MacroTools.@expand was written to help with this problem IIUC, but I find it’s choice of variable names more confusing than the var"#3#x" etc. of @macroexpand. Give it a try and see if you prefer it.

That’s nice to know, but MacroTools.@expand(@enum Fruit apple) still generates rather complicated output. One issue is that there are nested quoted expressions, but Base.remove_linenums! does not recursively descends into inner levels to remove the line number information that clutters the output.

Maybe prettify from MacroTools can help?

Thanks, MacroTools.prettify works wonderfully! All the clutter has been removed, and variables have been renamed to look sane (and cute). I still have questions about the actual code generated by expanding @enum (maybe I should do this in a new thread). I see a sub-expression,

quote
    $(Expr(:meta, :doc))
    primitive type Fruit <: Base.Enums.Enum{Int32} 32 end
end

What’s the meaning of $(Expr(:meta, :doc))? Is this some kind of docstring for the enum?