Elixir Macro Debugging
Macro debugging is checking what code a macro produces before that code runs. It compares the produced code with the code that was wanted.
Text form shows the tree as code
The tree for 1 + 2 reads back as code text. No line details get in the way.
IO.puts(Macro.to_string(quote do: 1 + 2))Expansion shows the doubled call
Expanding the call shows the repeated expression. Running the expansion gives 42.
defmodule Twice do
defmacro double(call) do
quote do
unquote(call) + unquote(call)
end
end
end
defmodule Caller do
require Twice
def expanded_text do
quoted = quote do: Twice.double(21)
Macro.to_string(Macro.expand(quoted, __ENV__))
end
def expanded_value do
quoted = quote do: Twice.double(21)
elem(Code.eval_quoted(Macro.expand(quoted, __ENV__)), 0)
end
end
IO.puts(Caller.expanded_text())
IO.puts(Caller.expanded_value())A macro can print its own input
The macro prints its input as code text while it expands. The caller then runs the same input and prints 3.
defmodule Debugger do
defmacro show(expr) do
IO.puts("AST: " <> Macro.to_string(expr))
quote do
unquote(expr)
end
end
end
defmodule Caller do
require Debugger
def value, do: Debugger.show(1 + 2)
end
IO.puts(Caller.value())Example
IO.puts(Macro.to_string(quote do: 1 + 2))
defmodule Twice do
defmacro double(call) do
quote do
unquote(call) + unquote(call)
end
end
end
defmodule Caller do
require Twice
def expanded_text do
quoted = quote do: Twice.double(21)
Macro.to_string(Macro.expand(quoted, __ENV__))
end
def expanded_value do
quoted = quote do: Twice.double(21)
elem(Code.eval_quoted(Macro.expand(quoted, __ENV__)), 0)
end
end
IO.puts(Caller.expanded_text())
IO.puts(Caller.expanded_value())Key points
- Expansion: expansion is the code a macro produces for a call.
- Macro.to_string: Macro.to_string turns a tree into readable code text.
- Macro.expand: Macro.expand produces the expansion of a macro call in a given environment.
- Print in macro: a macro can print its input while it expands, so the input shows during compilation.
- Separate module: a macro call for debugging still lives in a caller module that is separate from the macro module.
In this example, the first line shows a tree as code text, and the next lines show a macro expansion and the value that expansion gives.
Note
printing the expansion never runs the expanded code, so a second step must run it to check its value.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Which function turns a syntax tree into readable code text?