🧪

Elixirのマクロの一覧を書き出す

2022/12/25に公開

intro

この記事は、「Elixir Advent Calendar 2022」カレンダー4の21日目の記事になります。

はじめに

Elixirにはマクロを定義する機能があり、言語中でも多数のマクロが使われています。
モジュールを定義するdefmoduleもマクロですし、マクロを定義するdefmacroもマクロです。

iex(1)> h defmodule

                      defmacro defmodule(alias, do_block)

Defines a module given by name with the given contents.

iex(2)>
iex(3)> h defmodule

                      defmacro defmodule(alias, do_block)

Defines a module given by name with the given contents.

Elixirでコードを書く上で当たり前のように存在するマクロですが、標準でどれくらいのマクロがあるのか興味が沸いたため、リストアップしてみました。

マクロのリストアップ

elixirリポジトリをローカルにダウンロードし、grepツールでdefmacroが書かれた行をリストアップします。
grepツールにはthe_silver_searcher(ag)を使います。

実行結果は下記のフォーマットで出力します(the_silver_searcherのデフォルト)
定義ファイルと行番号を出力しているため、マクロを調べる際にも役に立つと思います。

ファイルパス
行番号: ソースコード

検索結果からdefmacroの処理じゃない部分(コメントなど)は削除しています。

実行したコマンド

$ git checkout v1.14.2
HEAD is now at 0909940b0 Release v1.14.2
$ git status
HEAD detached at v1.14.2
$ ag "defmacro " lib/elixir/lib/

実行結果

マクロ一覧
lib/elixir/lib/agent.ex
202:  defmacro __using__(opts) do

lib/elixir/lib/application.ex
392:  defmacro __using__(_) do
530:  defmacro compile_env(app, key_or_path, default \\ nil) do
570:  defmacro compile_env!(app, key_or_path) do

lib/elixir/lib/behaviour.ex
21:  defmacro defcallback(spec) do
29:  defmacro defmacrocallback(spec) do
91:  defmacro __using__(_) do

lib/elixir/lib/bitwise.ex
26:  defmacro __using__(options) do

lib/elixir/lib/config.ex
209:  defmacro config_env() do
232:  defmacro config_target() do
263:  defmacro import_config(file) do

lib/elixir/lib/dict.ex
21:  defmacro __using__(_) do

lib/elixir/lib/dynamic_supervisor.ex
247:  defmacro __using__(opts) do

lib/elixir/lib/gen_event.ex
90:  defmacro __using__(_) do

lib/elixir/lib/gen_server.ex
750:  defmacro __using__(opts) do
853:  defmacro __before_compile__(env) do

lib/elixir/lib/inspect.ex
520:  defmacro __deriving__(module, struct, options) do

lib/elixir/lib/io/ansi.ex
4:  defmacro defsequence(name, code, terminator \\ "m") do

lib/elixir/lib/kernel/special_forms.ex
62:  defmacro unquote(:{})(args), do: error!([args])
82:  defmacro unquote(:%{})(args), do: error!([args])
154:  defmacro unquote(:%)(struct, map), do: error!([struct, map])
371:  defmacro unquote(:<<>>)(args), do: error!([args])
493:  defmacro unquote(:.)(left, right), do: error!([left, right])
554:  defmacro alias(module, opts), do: error!([module, opts])
581:  defmacro require(module, opts), do: error!([module, opts])
684:  defmacro import(module, opts), do: error!([module, opts])
692:  defmacro __ENV__, do: error!([])
700:  defmacro __MODULE__, do: error!([])
708:  defmacro __DIR__, do: error!([])
716:  defmacro __CALLER__, do: error!([])
728:  defmacro __STACKTRACE__, do: error!([])
760:  defmacro ^var, do: error!([var])
765:  defmacro left = right, do: error!([left, right])
786:  defmacro left :: right, do: error!([left, right])
873:  defmacro squared(x) do
922:  defmacro squared(x) do
937:  defmacro squared(x) do
974:  defmacro no_interference do
995:  defmacro interference do
1013:  defmacro write do
1019:  defmacro read do
1034:  defmacro write do
1040:  defmacro read do
1059:  defmacro no_interference do
1080:  defmacro no_interference do
1097:  defmacro no_interference do
1105:  defmacro interference do
1191:  defmacro defadd do
1236:  defmacro defkv(kv) do
1262:  defmacro defkv(kv) do
1283:  defmacro defkv(kv) do
1294:  defmacro quote(opts, block), do: error!([opts, block])
1348:  defmacro unquote(:unquote)(expr), do: error!([expr])
1364:  defmacro unquote(:unquote_splicing)(expr), do: error!([expr])
1517:  defmacro for(args), do: error!([args])
1652:  defmacro with(args), do: error!([args])
1676:  defmacro unquote(:fn)(clauses), do: error!([clauses])
1693:  defmacro unquote(:__block__)(args), do: error!([args])
1771:  defmacro unquote(:&)(expr), do: error!([expr])
1805:  defmacro unquote(:__aliases__)(args), do: error!([args])
1812:  defmacro super(args), do: error!([args])
1900:  defmacro case(condition, clauses), do: error!([condition, clauses])
1929:  defmacro cond(clauses), do: error!([clauses])
2238:  defmacro try(args), do: error!([args])
2292:  defmacro receive(args), do: error!([args])

lib/elixir/lib/kernel/utils.ex
321:  defmacro defguard(args, expr) do

lib/elixir/lib/kernel.ex
1201:  defmacro tap(value, fun) do
1797:  defmacro left or right do
1828:  defmacro left and right do
1865:  defmacro !value
1867:  defmacro !{:!, _, [value]} do
1880:  defmacro !value do
1913:  defmacro left <> right do
2005:  defmacro raise(message) do
2063:  defmacro raise(exception, attributes) do
2087:  defmacro reraise(message, stacktrace) do
2135:  defmacro reraise(exception, attributes, stacktrace) do
2400:  defmacro is_struct(term) do
2436:  defmacro is_struct(term, name) do
2480:  defmacro is_exception(term) do
2518:  defmacro is_exception(term, name) do
2568:  defmacro then(value, fun) do
2909:  defmacro put_in(path, value) do
2949:  defmacro pop_in(path) do
2986:  defmacro update_in(path, fun) do
3050:  defmacro get_and_update_in(path, fun) do
3183:  defmacro to_string(term) do
3196:  defmacro to_charlist(term) do
3215:  defmacro is_nil(term) do
3299:  defmacro match?(pattern, expr) do
3425:  defmacro @expr
3427:  defmacro @{:__aliases__, _meta, _args} do
3431:  defmacro @{name, meta, args} do
3652:  defmacro binding(context \\ nil) do
3709:  defmacro if(condition, clauses) do
3758:  defmacro unless(condition, clauses) do
3810:  defmacro destructure(left, right) when is_list(left) do
3840:  defmacro first..last do
3908:  defmacro first..last//step do
3972:  defmacro (..) do
4003:  defmacro left && right do
4043:  defmacro left || right do
4126:  defmacro left |> right do
4296:  defmacro left in right do
4495:  defmacro var!(var, context \\ nil)
4497:  defmacro var!({name, meta, atom}, context) when is_atom(name) and is_atom(atom) do
4512:  defmacro var!(other, _context) do
4523:  defmacro alias!(alias) when is_atom(alias) do
4527:  defmacro alias!({:__aliases__, meta, args}) do
4764:  defmacro defmodule(alias, do_block)
4766:  defmacro defmodule(alias, do: block) do
5005:  defmacro def(call, expr \\ nil) do
5035:  defmacro defp(call, expr \\ nil) do
5049:  defmacro unless(expr, opts) do
5063:  defmacro defmacro(call, expr \\ nil) do
5079:  defmacro defmacrop(call, expr \\ nil) do
5239:  defmacro defstruct(fields) do
5308:  defmacro defexception(fields) do
5367:  defmacro defprotocol(name, do_block)
5369:  defmacro defprotocol(name, do: block) do
5378:  defmacro defimpl(name, opts, do_block \\ []) do
5398:  defmacro __using__(_opts) do
5449:  defmacro __using__(_opts) do
5471:  defmacro defoverridable(keywords_or_behaviour) do
5519:  defmacro defguard(guard) do
5535:  defmacro defguardp(guard) do
5638:  defmacro __using__(opts) do
5656:  defmacro __using__(_opts) do
5671:  defmacro __using__(_opts) do
5688:  defmacro use(module, opts \\ []) do
5761:  defmacro defdelegate(funs, opts) do
5865:  defmacro dbg(code \\ quote(do: binding()), options \\ []) do
5895:  defmacro sigil_S(term, modifiers)
5896:  defmacro sigil_S({:<<>>, _, [binary]}, []) when is_binary(binary), do: binary
5916:  defmacro sigil_s(term, modifiers)
5918:  defmacro sigil_s({:<<>>, _, [piece]}, []) when is_binary(piece) do
5922:  defmacro sigil_s({:<<>>, line, pieces}, []) do
5942:  defmacro sigil_C(term, modifiers)
5944:  defmacro sigil_C({:<<>>, _meta, [string]}, []) when is_binary(string) do
5966:  defmacro sigil_c(term, modifiers)
5970:  defmacro sigil_c({:<<>>, _meta, [string]}, []) when is_binary(string) do
5974:  defmacro sigil_c({:<<>>, _meta, pieces}, []) do
5998:  defmacro sigil_r(term, modifiers)
6000:  defmacro sigil_r({:<<>>, _meta, [string]}, options) when is_binary(string) do
6006:  defmacro sigil_r({:<<>>, meta, pieces}, options) do
6027:  defmacro sigil_R(term, modifiers)
6029:  defmacro sigil_R({:<<>>, _meta, [string]}, options) when is_binary(string) do
6063:  defmacro sigil_D(date_string, modifiers)
6065:  defmacro sigil_D({:<<>>, _, [string]}, []) do
6103:  defmacro sigil_T(time_string, modifiers)
6105:  defmacro sigil_T({:<<>>, _, [string]}, []) do
6153:  defmacro sigil_N(naive_datetime_string, modifiers)
6155:  defmacro sigil_N({:<<>>, _, [string]}, []) do
6209:  defmacro sigil_U(datetime_string, modifiers)
6211:  defmacro sigil_U({:<<>>, _, [string]}, []) do
6303:  defmacro sigil_w(term, modifiers)
6305:  defmacro sigil_w({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do
6309:  defmacro sigil_w({:<<>>, meta, pieces}, modifiers) do
6333:  defmacro sigil_W(term, modifiers)
6335:  defmacro sigil_W({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do
6456:  defmacro to_char_list(arg) do

lib/elixir/lib/macro.ex
17:  defmacro macro_inspect(value) do
81:  defmacro sigil_x(term, [?r]) do
86:  defmacro sigil_x(term, _modifiers) do
89:  defmacro sigil_X(term, [?r]) do
94:  defmacro sigil_X(term, _modifiers) do
257:  defmacro left |> right do
1714:  defmacro defmodule_with_length(name, do: block) do
1753:  defmacro defmodule_with_length(name, do: block) do

lib/elixir/lib/module/types/helpers.ex
8:  defmacro is_var(expr) do

lib/elixir/lib/module.ex
459: defmacro __before_compile__(_env) do

lib/elixir/lib/protocol.ex
265:  defmacro def(signature)
267:  defmacro def({_, _, args}) when args == [] or is_atom(args) do
271:  defmacro def({name, _, args}) when is_atom(name) and is_list(args) do
304:  defmacro def(_) do
388:  defmacro __deriving__(module, struct, options) do
424:  defmacro derive(protocol, module, options \\ []) do

lib/elixir/lib/record.ex
251:  defmacro defrecord(name, tag \\ nil, kv) do
256:  defmacro unquote(name)(args \\ []) do
260:  defmacro unquote(name)(record, args) do
269:  defmacro defrecordp(name, tag \\ nil, kv) do

lib/elixir/lib/stream/reducers.ex
58:  defmacro dedup(callback, fun \\ nil) do
71:  defmacro drop(fun \\ nil) do
83:  defmacro drop_every(nth, fun \\ nil) do
95:  defmacro drop_while(callback, fun \\ nil) do
107:  defmacro filter(callback, fun \\ nil) do
119:  defmacro filter_map(filter, mapper, fun \\ nil) do
131:  defmacro map(callback, fun \\ nil) do
139:  defmacro map_every(nth, mapper, fun \\ nil) do
151:  defmacro reject(callback, fun \\ nil) do
163:  defmacro scan2(callback, fun \\ nil) do
176:  defmacro scan3(callback, fun \\ nil) do
185:  defmacro take(fun \\ nil) do
203:  defmacro take_every(nth, fun \\ nil) do
215:  defmacro take_while(callback, fun \\ nil) do
227:  defmacro uniq_by(callback, fun \\ nil) do
241:  defmacro with_index(fun \\ nil) do

lib/elixir/lib/supervisor.ex
456:  defmacro __using__(opts) do

lib/elixir/lib/task.ex
277:  defmacro __using__(opts) do

おわりに

Elixir言語に標準で定義されているマクロを、ソースコードから探して一覧にしてみました。
件数を数えると、実に199個ものマクロが定義されていました!(各モジュールの__using__マクロもカウント)

定義済マクロを使いこなして素敵なElixirライフを!

Discussion