I have two versions. The version using the local unquote construct does exactly what I intend. Whenever I try to migrate it to a macro defined in another file it fails. I have tried many variations. I tried replicating what was in the record.ex of the language.I even have tried just building the syntax tree by hand. How is the macro supposed to be defined?
[code]defmodule Works do
require ConstantExtractor
create one function representing each name/value pair
for {name, value} <- ConstantExtractor.extractAllConstants(“include/asn1/S1AP.hrl”) do
def unquote({name, [context: MODULE], MODULE}), do: unquote(value)
end
end
defmodule Fails do
require ConstantExtractor
create one function representing each name/value pair
for {name, value} <- ConstantExtractor.extractAllConstants(“include/asn1/S1AP.hrl”) do
ConstantExtractor.defconst name, value
end
end
defmodule ConstantExtractor do # failing version
…
defmacro defconst(name, value) do
quote do
defmacro(unquote(name)()) do
(unquote(value))
end
end
end
end[/code]
Fails with:
lib/asn1/s1ap.ex:15: warning: variable name is unused
lib/asn1/s1ap.ex:15: warning: variable value is unused
…
== Compilation error on file lib/asn1/s1ap.ex ==
** (CompileError) lib/asn1/s1ap.ex:17: invalid syntax in defmacro name()
lib/asn1/s1ap.ex:17: anonymous fn/2 in :elixir_compiler_2.MODULE/1
(elixir) lib/enum.ex:1473: Enum."-reduce/3-lists^foldl/2-0-"/3
lib/asn1/s1ap.ex:15: (module)
[code]defmodule Test do
defmacro test(key, value) do
def unquote(key)() do
unquote(value)
end
end
end
defmodule Example do
require Test
Test.test(:hello, :world)
end[/code]
This is as I suspected - if I call with literals the macro works. If I call it from within a loop, instead I get some variable contexts and it no longer works. How to fix this?
Just a quick guess, but you are passing name to your function, and just yesterday we had the discussion about Macro.escape/2. So I’d try to escape name and value before passing them. I don’t know exactly thow, if you need to do it before calling the macro, or if you can do it inside of the macro (before quote-block).
Perhaps, it might also be, that you need to use Macro.expand/2. I’m always confused about how and when I need which of the functions from Macro module, so as soon as something doesn’t work without them randomly until it works, or I just change my plan and try to do something similar without using metaprogramming at all
I guess bind_quoted defines bindings inside the caller context, and then I can use the rebound values inside the macro. Record.defrecord does it, it made my solution work too…
I tried working with Macro.escape but had no satisfactory results so far…