Is there a way to get the Meta part of the AST inside a Macro

When you generate an AST, like so:

quote do: foo(x)
#=> {:foo, [], [{:x, [], Elixir}]}

The second element in the tuple is the meta. Is it possible to access that in a macro?

defmacro foo(x) do
  # How could I access the meta here?
end

Alternatively, is there a way I could construct the meta from the Macro.Env?
I’m not sure all the things that are part of the meta. Is there a good place to learn what things are included in the meta?

Macro receives direct metadata as arguments, so all you need to do to get metadata is:

defmacro foo({_, meta, _}) do
  IO.inspect(meta)
end

@hauleth that’s the meta for the x parameter, not the meta for the foo macro call.

From what you said I think you want to do something like:

defmodule Example do
  require MyLibrary

  MyLibrary.sample(foo(x))

  # or:

  MyLibrary.sample foo(x) do
    # …
  end
end

If so then you would have:

defmodule MyLibrary do
  defmacro sample({_func_name, _func_meta, func_args}) do
    func_args |> MyLibrary.find_by_name(:x) |> elem(1)
  end

  defmacro sample2({_func_name, _func_meta, func_args}, do: {:__block__, [], _block}) do
    func_args |> MyLibrary.find_by_name(:x) |> elem(1)
  end

  def find_by_name(list, name), do: Enum.find(list, &(elem(&1, 0) == name))
end

defmodule Example do
  require MyLibrary

  MyLibrary.sample(foo(x))

  MyLibrary.sample2 foo(x) do
    y
    z
  end
end

Thanks @Eiji, I was hoping to get access to it without needing to wrap it in another macro.

I’ve noticed that the only thing in meta is typically the line number. So, for now I’ve just constructed the meta myself from the __ENV__ available in the macro.

3 Likes

Look at __CALLER__ as well, it’s the __ENV__ in the macro caller’s context. :slight_smile:

1 Like