Determine if a funtion/macro is available at compile and and what modules it belongs to

85 views
Skip to first unread message

eksperimental

unread,
Sep 4, 2016, 12:27:16 PM9/4/16
to elixir-l...@googlegroups.com
Hi,

I'm writing a macro and I need to determine at compile time if this macro is available
Let's say some modules have been imported, or aliased.
I will be calling this macro with no Module, just the macro itself: "foo/1".
I need to determine (at compile time) if "foo/1" is available, and if so, what is the module
it belongs too.

thank you guys

Michał Muskała

unread,
Sep 5, 2016, 5:07:51 AM9/5/16
to elixir-l...@googlegroups.com
You can get a list of all imported functions/macros looking in the __ENV__.functions and __ENV__.macros

Michał.
signature.asc

eksperimental

unread,
Sep 7, 2016, 7:34:16 PM9/7/16
to elixir-l...@googlegroups.com
thank you Michał, but __ENV__ holds no information about imported modules.
I will be calling the macros/funtions with no module, so somehow I need to figure out which Module
I'm going to be calling the macro/function from

OvermindDL1

unread,
Sep 7, 2016, 7:45:01 PM9/7/16
to elixir-lang-talk, eksper...@autistici.org
On Wednesday, September 7, 2016 at 5:34:16 PM UTC-6, eksperimental wrote:
thank you Michał, but __ENV__ holds no information about imported modules.
I will be calling the macros/funtions with no module, so somehow I need to figure out which Module
I'm going to be calling the macro/function from

Uh, you sure it does not hold the information?
```elixir
iex> import Ecto.Query
iex> __ENV__.macros[Ecto.Query]
[distinct: 2, distinct: 3, from: 1, from: 2, group_by: 2, group_by: 3,
 having: 2, having: 3, join: 3, join: 4, join: 5, limit: 2, limit: 3, lock: 2,
 offset: 2, offset: 3, order_by: 2, order_by: 3, preload: 2, preload: 3,
 select: 2, select: 3, update: 2, update: 3, where: 2, where: 3]
```
You should be able to just iterate through `__ENV__.macros` to find which module the macro belongs to.  There is also a `__ENV__.functions` for that one too.  Just remember to use the __ENV__ in the environment where you will be calling it in, not from the callee environment.

eksperimental

unread,
Sep 7, 2016, 8:24:10 PM9/7/16
to elixir-l...@googlegroups.com
that's the thing,
I don't know what modules had been imported (I'm planning on using this inside a macro, that's why
the requirements are that it needs to be available at compile-time).
pretty much I need to do what Elixir does to determine what is the module being called, when no
module is specified.

Eric Meadows-Jönsson

unread,
Sep 8, 2016, 6:05:37 AM9/8/16
to elixir-l...@googlegroups.com
Inside a macro the callers environment is available in __CALLER__. The imported modules are actually available in the environment as Michal said and OvermindDL1 showed:

iex(1)> __ENV__.macros
[{IEx.Helpers,
  [b: 1, h: 1, import_file: 1, import_file: 2, import_file_if_available: 1,
   import_if_available: 1, import_if_available: 2, s: 1, t: 1]},
 {Kernel,
  [!: 1, &&: 2, ..: 2, <>: 2, @: 1, alias!: 1, and: 2, binding: 0, binding: 1,
   def: 1, def: 2, defdelegate: 2, defexception: 1, defimpl: 2, defimpl: 3,
   defmacro: 1, defmacro: 2, defmacrop: 1, defmacrop: 2, defmodule: 2,
   defoverridable: 1, defp: 1, defp: 2, defprotocol: 2, defstruct: 1,
   destructure: 2, get_and_update_in: 2, if: 2, in: 2, is_nil: 1, match?: 2,
   or: 2, pop_in: 1, put_in: 2, raise: 1, raise: 2, reraise: 2, reraise: 3,
   sigil_C: 2, sigil_D: 2, sigil_N: 2, sigil_R: 2, sigil_S: 2, sigil_T: 2,
   sigil_W: 2, sigil_c: 2, sigil_r: 2, sigil_s: 2, ...]}]

In the code snippet above you can see the modules IEx.Helpers and Kernel. They are imported modules.

You can also see from where a function/macro was imported in the AST:

iex(2)> quote(do: is_nil(1))
{:is_nil, [context: Elixir, import: Kernel], [1]}

See the import: Kernel in the snippet above.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-talk+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/20160908072400.4bc10809.eksperimental%40autistici.org.
For more options, visit https://groups.google.com/d/optout.



--
Eric Meadows-Jönsson

eksperimental

unread,
Sep 9, 2016, 8:50:45 AM9/9/16
to elixir-l...@googlegroups.com
Thank you Eric,
all clear now.
For some reason I was thinking that the modules and macros/functions I was seeing in functions: and
macros: were the required modules, but they were the imported ones.

Thanks Michał and OvermindDL1 for clarifying as well.
have a nice day!
> > email to elixir-lang-ta...@googlegroups.com.

Benjamin Scherrey

unread,
Sep 9, 2016, 9:10:43 AM9/9/16
to elixir-l...@googlegroups.com
Where would one find this kind of stuff documented? Is it strictly in the source code? Any pointers would be appreciated. Thanx!

  -- Ben

Michał Muskała

unread,
Sep 9, 2016, 9:13:23 AM9/9/16
to elixir-l...@googlegroups.com

> On 09 Sep 2016, at 15:10, Benjamin Scherrey <sche...@proteus-tech.com> wrote:
>
> Where would one find this kind of stuff documented? Is it strictly in the source code? Any pointers would be appreciated. Thanx!
>
> -- Ben

You can find those in the documentation for Macro.Env http://elixir-lang.org/docs/master/elixir/Macro.Env.html that is referenced in documentation for __ENV__ http://elixir-lang.org/docs/master/elixir/Kernel.SpecialForms.html#__ENV__/0, but you'd need to know to look in __ENV__ in the first place. In general most of the information available to the compiler is inside __ENV__.

Michał.
signature.asc
Reply all
Reply to author
Forward
0 new messages