Define functions in macro based on a list

I am trying to do something with macros just to get hang of them.
I am working on a module to be able to define constants. Here is the module.

defmodule Constant do
  defmacro __using__(_opts) do
    quote do
      require Constant

      Module.register_attribute(__MODULE__, :name, accumulate: true)
      Module.register_attribute(__MODULE__, :value, accumulate: true)

      @before_compile Constant
    end
  end

  defmacro __before_compile__(_env) do
    quote do
      @name |> Enum.each(fn(name) ->
        Module.eval_quoted(__MODULE__, quote do
          def unquote(name), do: unquote(name)
        end)
      end)
    end
  end
end

defmodule Test do
  use Constant

  @name :asd
  @value :dsa

  @name :dddd
  @value :aaaa
end

Running iex test.exs yields

Erlang/OTP 19 [erts-8.1.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

** (CompileError) nofile:1: invalid syntax in def :dddd
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    /path/to/test.exs:24: Constant.__before_compile__/1

Basically, I am trying to define functions based on a list of key/values. I tried nested quotes too, but that just does not define functions. I guess that is because I have to return a proper quoted expression from a macro, but doing Enum.each on a list, and doing quote there just gives a list of quoted expressions, that can not be unquoted.

Any help is appreciated!

Seems like the fix is a silly (),

    Module.eval_quoted(__MODULE__, quote do
      def unquote(name)(), do: unquote(name)
    end)

I still don’t get it. The error was not that helpful.

1 Like

Macro errors often aren’t, that is the nature of screwing around with the AST before it is actually parsed. ^.^