There are useful shorthands like quote
, but ultimately macros are transformations from AST to AST. For your example:
# INPUT
iex(1)> quote do: x > y
{
:>,
[context: Elixir, import: Kernel],
[
{:x, [if_undefined: :apply], Elixir},
{:y, [if_undefined: :apply], Elixir}
]
}
# OUTPUT
iex(2)> quote do: data.x > data.y
{
:>,
[context: Elixir, import: Kernel],
[
{
{
:.,
[],
[
{:data, [if_undefined: :apply], Elixir},
:x
]
},
[no_parens: true],
[]
},
{
{
:.,
[],
[
{:data, [if_undefined: :apply], Elixir},
:y
]
},
[no_parens: true],
[]
}
]
}
The underlying pattern looks like:
{:some_var, _, _} -> {{:., [], {:data, [], Elixir}, :some_var}
You’d apply a transformation like this using a function like Macro.prewalk
or your own recursive traversal code.
Once you’ve got the data
-fied expression, you’d wrap it in the AST corresponding to fn data -> ... end
. You can find that shape using quote
:
iex(4)> quote do: fn data -> :ok end
{:fn, [], [{:->, [], [[{:data, [if_undefined: :apply], Elixir}], :ok]}]}