Passing options to module

Macros always receive AST and are always required to return AST. So what you are seeing is normal. As the guide says:

… However, as we learned in the previous chapter, the macro will receive quoted expressions, inject them into the quote, and finally return another quoted expression.

I typically find the following construct useful for dealing with this when I want to use the macro arguments at compile time (and with @before_compile delegate the production of the final AST to a regular function).

bind_quoted is recommended in most cases and takes care compile-time unquoting. If you are passing something like a map you will have to Macro.escape/1 it first. The example below is from ex_cldr so its just an example. But you can see it is setting a module attribute.

  defmacro __using__(opts \\ []) do
    quote bind_quoted: [opts: opts] do
      @cldr_opts opts
      @before_compile Cldr.Backend.Compiler
    end
  end