Reputation: 337
defmodule DemoMacro do
defmacro i_am_macro do
quote do
# ……
end
end
i_am_macro # (CompileError) example.exs:10: undefined function i_am_macro/0
end
But imported from other modules, can be successfully called:
defmodule SecondModule do
require DemoMacro
DemoMacro.i_am_macro
end
What should I do to make the first piece of code compile?
Upvotes: 3
Views: 667
Reputation: 121000
You are calling the macro from the module body, meaning during the compilation stage. On the compiler stage, this module content is obviously not accessible yet because the module is not compiled.
Move macro into a function:
defmodule DemoMacro do
defmacro i_am_macro do
quote do
IO.puts "Inside a macro"
end
end
def test_macro(), do: i_am_macro()
end
DemoMacro.test_macro()
#⇒ "Inside a macro"
Macro content is an AST that is being injected inplace on each macro call. During the compilation stage, you might use already compiled Elixir code. Understanding the difference between compilation stage and runtime requires kinda mental shift, mostly because in both stages we use same Elixir syntax. But the thing is Elixir, being a compiled language, cannot use the code unless it’s compiled into BEAMs.
You also can use your macro inside @after_compile
callback, during compilation stage, immediately after the module BEAM becomes available (compiled):
defmodule DemoMacro do
defmacro i_am_macro do
quote do
IO.puts "Inside a macro"
end
end
@after_compile __MODULE__
def __after_compile__(env, _bytecode) do
i_am_macro()
end
end
#⇒ immediately prints "Inside a macro"
Upvotes: 5