hst337
How to get an AST and Macro.Env of a function by name and arity?
Summary
Is there any way to write a function which can be invoked in compile time and which can return an AST and Macro.Env of given function.
Example
We have a module
defmodule MMM do
def fff(x), do: x + 1
end
And we can execute some function in compile time which will work like
iex> Macro.get_ast(MMM, :fff, 1)
{
{:def, [context: Elixir, import: Kernel],
[
{:f, [context: Elixir], [{:x, [], Elixir}]},
[do: {:+, [context: Elixir, import: Kernel], [{:x, [], Elixir}, 1]}]
]},
%Macro.Env{}
}
PS
I know there is no such function, but how can something like this be implemented? What problems should I expect while implementing this function?
Most Liked
ityonemo
this is possible using Elixir compiler tracer hooks. I am pretty sure it broadcasts the AST and __ENV__ of a function being compiled.
https://hexdocs.pm/elixir/Code.html#module-compilation-tracers
Worst case scenario, collect em’ all, serialize them using :erlang.term_to_binary, and then stash everything into some file in /priv
OvermindDL1
In the erlang side things like -compile({inline,24}). are specified to inline module-local functions with a given weight or less, 24 is the default weight, so most ‘shortish’ functions will get inlined directly and always. It can be overridden though with a different weight, like 1000 if you want to inline almost everything, or you can force inline specific functions by giving it a list.
Do note though, inlining larger can help with some optimizations, but overall it usually doesn’t and it’s best to leave it at default as the size overhead doesn’t help the speed at that point, and calling module-local functions require no indirected call so their only cost is a stack frame at that point (if that’s even needed).
OvermindDL1
Such a function like that doesn’t exist because the AST is long long gone at that point. You could always make your own macro, say defmodulex or so and just use it instead of defmodule and have it build a new hidden function called __ASTS__/1 where you pass it an option of what to return and it can return the AST for whatever you asked for. Basically compile the compile and add in that function that just returns the AST of the module that was passed in?
Better question though, ‘why’ do you want it?







