Pretty macroexpand in Base?

Whenever I talk to someone about macros, I always suggest they start by looking at the expansion of the macro. But the default expansion isn’t super readable because of LineNumberNode’s, gensyms, etc.

So I almost always end up using MacroTools.prettify:

MacroTools.prettify(@macroexpand @everywhere x = 1)

Should Base Julia have the equivalent of this composition in it? It seems like it could make macros more accessible.

6 Likes

Agreed! I’ll just add that I sometimes prefer

 MacroTools.prewalk(rmlines, @macroexpand @everywhere x = 1)

to see the original variable names (even if they’re mangled) as this can give a much better idea of what’s going on for larger macros. A way to get the original symbols (unmangled) would be even better…

3 Likes

This looks equivalent to Base.remove_linenums! unless I am missing something? It should be pretty trivial to support a kwarg to @macroexpand that just remove linenumbers (similar to e.g. @code_llvm which has debuginfo as a kwarg).

2 Likes

Nice, I didn’t know there was already a way to do it in Base!

This sounds great. Arguably the “brief” printout is more commonly needed than the verbose one, so maybe brief=true should even be the default?

The MacroTools version catches some line-numbers that the Base one misses:

julia> Base.remove_linenums!(@macroexpand1 @assert 1 == @view A[1])
:(if 1 == #= REPL[57]:1 =# @view(A[1])
      nothing
  else
      Base.throw(Base.AssertionError("1 == #= REPL[57]:1 =# @view(A[1])"))
  end)

julia> MacroTools.prewalk(rmlines, @macroexpand1 @assert 1 == @view A[1])
:(if 1 == @view(A[1])
      nothing
  else
      Base.throw(Base.AssertionError("1 == #= REPL[58]:1 =# @view(A[1])"))
  end)
1 Like

I think that the best solution is to make MacroTools a standard library (ideally after stdlib version numbers are decoupled from Julia proper).

It has a lot of useful functionality, and is practically indispensable for working with macros in Julia.

Yes, it doesn’t strip out LineNumberNodes from macrocall expressions. I think rmlines actually replaces those with nothing.