Conveniences for working with macros.
Macro
Types #
Functions #
Specs
Decomposes a local or remote call into its remote part (when provided), function name and argument list.
Returns :error
when an invalid call syntax is provided.
Examples
iex> Macro.decompose_call(quote do: foo)
{:foo, []}
iex> Macro.decompose_call(quote do: foo())
{:foo, []}
iex> Macro.decompose_call(quote do: foo(1, 2, 3))
{:foo, [1, 2, 3]}
iex> Macro.decompose_call(quote do: Elixir.M.foo(1, 2, 3))
{{:__aliases__, [], [:Elixir, :M]}, :foo, [1, 2, 3]}
iex> Macro.decompose_call(quote do: 42)
:error
Specs
Recursively escapes a value so it can be inserted into a syntax tree.
One may pass unquote: true
to escape/2
which leaves unquote
statements unescaped, effectively
unquoting the contents on escape.
Examples
iex> Macro.escape(:foo)
:foo
iex> Macro.escape({:a, :b, :c})
{:{}, [], [:a, :b, :c]}
iex> Macro.escape({:unquote, [], [1]}, unquote: true)
1
Receives an AST node and expands it until it can no longer be expanded.
This function uses expand_once/2
under the hood. Check
expand_once/2
for more information and examples.
Receives an AST node and expands it once.
The following contents are expanded:
- Macros (local or remote)
- Aliases are expanded (if possible) and return atoms
- Pseudo-variables (
__ENV__
,__MODULE__
and__DIR__
) - Module attributes reader (
@foo
)
If the expression cannot be expanded, it returns the expression
itself. Notice that expand_once/2
performs the expansion just
once and it is not recursive. Check expand/2
for expansion
until the node can no longer be expanded.
Examples
In the example below, we have a macro that generates a module
with a function named name_length
that returns the length
of the module name. The value of this function will be calculated
at compilation time and not at runtime.
Consider the implementation below:
defmacro defmodule_with_length(name, do: block) do
length = length(Atom.to_char_list(name))
quote do
defmodule unquote(name) do
def name_length, do: unquote(length)
unquote(block)
end
end
end
When invoked like this:
defmodule_with_length My.Module do
def other_function, do: ...
end
The compilation will fail because My.Module
when quoted
is not an atom, but a syntax tree as follow:
{:__aliases__, [], [:My, :Module]}
That said, we need to expand the aliases node above to an atom, so we can retrieve its length. Expanding the node is not straight-forward because we also need to expand the caller aliases. For example:
alias MyHelpers, as: My
defmodule_with_length My.Module do
def other_function, do: ...
end
The final module name will be MyHelpers.Module
and not
My.Module
. With Macro.expand/2
, such aliases are taken
into consideration. Local and remote macros are also
expanded. We could rewrite our macro above to use this
function as:
defmacro defmodule_with_length(name, do: block) do
expanded = Macro.expand(name, __CALLER__)
length = length(Atom.to_char_list(expanded))
quote do
defmodule unquote(name) do
def name_length, do: unquote(length)
unquote(block)
end
end
end
Specs
Pipes expr
into the call_args
at the given position
.
Specs
Performs a depth-first, post-order traversal of quoted expressions.
Specs
Performs a depth-first, post-order traversal of quoted expressions using an accumulator.
Specs
Performs a depth-first, pre-order traversal of quoted expressions.
Specs
Performs a depth-first, pre-order traversal of quoted expressions using an accumulator.
Specs
Converts the given expression to a binary.
Examples
iex> Macro.to_string(quote do: foo.bar(1, 2, 3))
"foo.bar(1, 2, 3)"
Specs
Unescape the given chars.
This is the unescaping behaviour used by default in Elixir
single- and double-quoted strings. Check unescape_string/2
for information on how to customize the escaping map.
In this setup, Elixir will escape the following: \0
, \a
, \b
,
\d
, \e
, \f
, \n
, \r
, \s
, \t
and \v
. Hexadecimals
are also supported via \xNN
and \x{NN...}
syntax.
This function is commonly used on sigil implementations
(like ~r
, ~s
and others) which receive a raw, unescaped
string.
Examples
iex> Macro.unescape_string("example\\n")
"example\n"
In the example above, we pass a string with \n
escaped
and return a version with it unescaped.
Specs
Unescape the given chars according to the map given.
Check unescape_string/1
if you want to use the same map
as Elixir single- and double-quoted strings.
Map
The map must be a function. The function receives an integer representing the codepoint of the character it wants to unescape. Here is the default mapping function implemented by Elixir:
def unescape_map(?0), do: ?0
def unescape_map(?a), do: ?\a
def unescape_map(?b), do: ?\b
def unescape_map(?d), do: ?\d
def unescape_map(?e), do: ?\e
def unescape_map(?f), do: ?\f
def unescape_map(?n), do: ?\n
def unescape_map(?r), do: ?\r
def unescape_map(?s), do: ?\s
def unescape_map(?t), do: ?\t
def unescape_map(?v), do: ?\v
def unescape_map(?x), do: true
def unescape_map(e), do: e
If the unescape_map
function returns false
. The char is
not escaped and \
is kept in the char list.
Hexadecimals will be escaped if the map function returns true
for ?x
.
Examples
Using the unescape_map
function defined above is easy:
Macro.unescape_string "example\\n", &unescape_map(&1)
Specs
Unescape the given tokens according to the default map.
Check unescape_string/1
and unescape_string/2
for more
information about unescaping.
Only tokens that are binaries are unescaped, all others are
ignored. This function is useful when implementing your own
sigils. Check the implementation of Kernel.sigil_s/2
for examples.
Specs
Unescape the given tokens according to the given map.
Check unescape_tokens/1
and unescape_string/2
for more information.
Specs
Breaks a pipeline expression into a list.
Raises if the pipeline is ill-formed.
Specs
Applies the given function to the node metadata if it contains one.
This is often useful when used with Macro.prewalk/1
to remove
information like lines and hygienic counters from the expression
for either storage or comparison.
Examples
iex> quoted = quote line: 10, do: sample()
{:sample, [line: 10], []}
iex> Macro.update_meta(quoted, &Keyword.delete(&1, :line))
{:sample, [], []}
Specs
validate(term) :: :ok | {:error, term}
Validates the given expressions are valid quoted expressions.
Check the type:Macro.t
for the specification of a valid
quoted expression.
Specs
var(var, context) :: {var, [], context} when var: atom, context: atom
Genrates a AST node representing the variable given
by the atoms var
and context
.
Examples
In order to build a variable, a context is expected.
Most of the times, in order to preserve hygiene, the
context must be __MODULE__
:
iex> Macro.var(:foo, __MODULE__)
{:foo, [], __MODULE__}
However, if there is a need to access the user variable, nil can be given:
iex> Macro.var(:foo, nil)
{:foo, [], nil}