# Elixir v1.10.3 Macro View Source

Macros are compile-time constructs that are invoked with Elixir's AST as input and a superset of Elixir's AST as output.

Let's see a simple example that shows the difference between functions and macros:

    defmodule Example do
      defmacro macro_inspect(value) do
        IO.inspect(value)
        value
      end

      def fun_inspect(value) do
        IO.inpect(value)
        value
      end
    end

Now let's give it a try:

    import Example

    macro_inspect(1)
    #=> 1
    #=> 1

    fun_inspect(1)
    #=> 1
    #=> 1

So far they behave the same, as we are passing an integer as argument. But what happens when we pass an expresion:

    macro_inspect(1 + 2)
    #=> {:+, [line: 3], [1, 2]}
    #=> 3

    fun_inspect(1 + 2)
    #=> 3
    #=> 3

The macro receives the representation of the code given as argument, while a function receives the result of the code given as argument. A macro must return a superset of the code representation. See `t:input/0` and `t:output/0` for more information.

To learn more about Elixir's AST and how to build them programmatically, see `quote/2`.

## Custom Sigils

Macros are also commonly used to implement custom sigils. To create a custom sigil, define a function with the name `sigil_{identifier}` that takes two arguments. The first argument will be the string, the second will be a charlist containing any modifiers. If the sigil is lower case (such as `sigil_x`) then the string argument will allow interpolation. If the sigil is upper case (such as `sigil_X`) then the string will not be interpolated.

Valid modifiers include only lower and upper case letters. Other characters will cause a syntax error.

The module containing the custom sigil must be imported before the sigil syntax can be used.

### Examples

    defmodule MySigils do
      defmacro sigil_x(term, [?r]) do
        quote do
          unquote(term) |> String.reverse()
        end
      end
      defmacro sigil_x(term, _modifiers) do
        term
      end
      defmacro sigil_X(term, [?r]) do
        quote do
          unquote(term) |> String.reverse()
        end
      end
      defmacro sigil_X(term, _modifiers) do
        term
      end
    end

    import MySigils

    ~x(with #{"inter" <> "polation"})
    #=>"with interpolation"

    ~x(with #{"inter" <> "polation"})r
    #=>"noitalopretni htiw"

    ~X(without #{"interpolation"})
    #=>"without \#{"interpolation"}"

    ~X(without #{"interpolation"})r
    #=>"}\"noitalopretni\"{# tuohtiw"

# Link to this section Summary

## Types

captured_remote_function()

A captured remote function in the format of &Mod.fun/arity

input()

The inputs of a macro

metadata()

A keyword list of AST metadata.

output()

The output of a macro

t()

Abstract Syntax Tree (AST)

## Functions

camelize(string)

Converts the given string to CamelCase format.

decompose_call(ast)

Decomposes a local or remote call into its remote part (when provided), function name and argument list.

escape(expr, opts \\ [])

Recursively escapes a value so it can be inserted into a syntax tree.

expand(ast, env)

Receives an AST node and expands it until it can no longer be expanded.

expand_once(ast, env)

Receives an AST node and expands it once.

generate_arguments(amount, context)

Generates AST nodes for a given number of required argument variables using `Macro.var/2`.

operator?(name, arity)

Returns `true` if the given name and arity is an operator.

pipe(expr, call_args, position)

Pipes `expr` into the `call_args` at the given `position`.

postwalk(ast, fun)

Performs a depth-first, post-order traversal of quoted expressions.

postwalk(ast, acc, fun)

Performs a depth-first, post-order traversal of quoted expressions using an accumulator.

prewalk(ast, fun)

Performs a depth-first, pre-order traversal of quoted expressions.

prewalk(ast, acc, fun)

Performs a depth-first, pre-order traversal of quoted expressions using an accumulator.

quoted_literal?(term)

Returns `true` if the given quoted expression represents a quoted literal.

special_form?(name, arity)

Returns `true` if the given name and arity is a special form.

struct!(module, env)

Expands the struct given by `module` in the given `env`.

to_string(tree, fun \\ fn _ast, string -> string end)

Converts the given expression AST to a string.

traverse(ast, acc, pre, post)

Performs a depth-first traversal of quoted expressions using an accumulator.

underscore(atom)

Converts the given atom or binary to underscore format.

unescape_string(chars)

Unescapes the given chars.

unescape_string(chars, map)

Unescapes the given chars according to the map given.

unpipe(expr)

Breaks a pipeline expression into a list.

update_meta(quoted, fun)

Applies the given function to the node metadata if it contains one.

validate(expr)

Validates the given expressions are valid quoted expressions.

var(var, context)

Generates an AST node representing the variable given by the atoms `var` and `context`.

# Link to this section Types

Link to this type

# captured_remote_function()

View Source

## Specs

    captured_remote_function() :: (... -> any())

A captured remote function in the format of &Mod.fun/arity

Link to this type

# input()

View Source

## Specs

    input() ::
      input_expr() | {input(), input()} | [input()] | atom() | number() | binary()

The inputs of a macro

Link to this type

# metadata()

View Source

## Specs

    metadata() :: keyword()

A keyword list of AST metadata.

The metadata in Elixir AST is a keyword list of values. Any key can be used and different parts of the compiler may use different keys. For example, the AST received by a macro will always include the `:line` annotation, while the AST emitted by `quote/2` will only have the `:line` annotation if the `:line` option is provided.

The following metadata keys are public:

- `:context` - Defines the context in which the AST was generated. For example, `quote/2` will include the module calling `quote/2` as the context. This is often used to distinguish regular code from code generated by a macro or by `quote/2`.
- `:counter` - The variable counter used for variable hygiene. In terms of the compiler, each variable is identified by the combination of either `name` and `metadata[:counter]`, or `name` and `context`.
- `:generated` - Whether the code should be considered as generated by the compiler or not. This means the compiler and tools like Dialyzer may not emit certain warnings.
- `:keep` - Used by `quote/2` with the option `location: :keep` to annotate the file and the line number of the quoted source.
- `:line` - The line number of the AST node.

The following metadata keys are enabled by `Code.string_to_quoted/2`:

- `:closing` - contains metadata about the closing pair, such as a `}` in a tuple or in a map, or such as the closing `)` in a function call with parens. The `:closing` does not delimit the end of expression if there are `:do` and `:end` metadata (when `:token_metadata` is true)
- `:column` - the column number of the AST node (when `:columns` is true)
- `:delimiter` - contains the opening delimiter for sigils, strings, and charlists as a string (such as `"{"`, `"/"`, `"'"`, and the like)
- `:format` - set to `:keyword` when an atom is defined as a keyword
- `:do` - contains metadata about the `do` location in a function call with `do/end` blocks (when `:token_metadata` is true)
- `:end` - contains metadata about the `end` location in a function call with `do/end` blocks (when `:token_metadata` is true)
- `:end_of_expression` - denotes when the end of expression effectively happens. Available for all expressions except the last one inside a `__block__` (when `:token_metadata` is true)

The following metadata keys are private:

- `:alias` - Used for alias hygiene.
- `:ambiguous_op` - Used for improved error messages in the compiler.
- `:import` - Used for import hygiene.
- `:var` - Used for improved error messages on undefined variables.

Do not rely on them as they may change or be fully removed in future versions of the language. They are often used by `quote/2` and the compiler to provide features like hygiene, better error messages, and so forth.

If you introduce custom keys into the AST metadata, please make sure to prefix them with the name of your library or application, so that they will not conflict with keys that could potentially be introduced by the compiler in the future.

Link to this type

# output()

View Source

## Specs

    output() ::
      output_expr()
      | {output(), output()}
      | [output()]
      | atom()
      | number()
      | binary()
      | captured_remote_function()
      | pid()

The output of a macro

Link to this type

# t()

View Source

## Specs

    t() :: input()

Abstract Syntax Tree (AST)

# Link to this section Functions

Link to this function

# camelize(string)

View Source

## Specs

    camelize(String.t()) :: String.t()

Converts the given string to CamelCase format.

This function was designed to camelize language identifiers/tokens, that's why it belongs to the `Macro` module. Do not use it as a general mechanism for camelizing strings as it does not support Unicode or characters that are not valid in Elixir identifiers.

## Examples

    iex> Macro.camelize("foo_bar")
    "FooBar"

If uppercase characters are present, they are not modified in any way as a mechanism to preserve acronyms:

    iex> Macro.camelize("API.V1")
    "API.V1"
    iex> Macro.camelize("API_SPEC")
    "API_SPEC"

Link to this function

# decompose_call(ast)

View Source

## Specs

    decompose_call(t()) :: {atom(), [t()]} | {t(), atom(), [t()]} | :error

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

Link to this function

# escape(expr, opts \\ [])

View Source

## Specs

    escape(term(), keyword()) :: t()

Recursively escapes a value so it can be inserted into a syntax tree.

## Examples

    iex> Macro.escape(:foo)
    :foo

    iex> Macro.escape({:a, :b, :c})
    {:{}, [], [:a, :b, :c]}

    iex> Macro.escape({:unquote, [], [1]}, unquote: true)
    1

## Options

- `:unquote` - when true, this function leaves `unquote/1` and `unquote_splicing/1` statements unescaped, effectively unquoting the contents on escape. This option is useful only when escaping ASTs which may have quoted fragments in them. Defaults to false.

- `:prune_metadata` - when true, removes metadata from escaped AST nodes. Note this option changes the semantics of escaped code and it should only be used when escaping ASTs, never values. Defaults to false.

  As an example, `ExUnit` stores the AST of every assertion, so when an assertion fails we can show code snippets to users. Without this option, each time the test module is compiled, we get a different MD5 of the module byte code, because the AST contains metadata, such as counters, specific to the compilation environment. By pruning the metadata, we ensure that the module is deterministic and reduce the amount of data `ExUnit` needs to keep around.

## Comparison to `Kernel.SpecialForms.quote/2`

The `escape/2` function is sometimes confused with `Kernel.SpecialForms.quote/2`, because the above examples behave the same with both. The key difference is best illustrated when the value to escape is stored in a variable.

    iex> Macro.escape({:a, :b, :c})
    {:{}, [], [:a, :b, :c]}
    iex> quote do: {:a, :b, :c}
    {:{}, [], [:a, :b, :c]}

    iex> value = {:a, :b, :c}
    iex> Macro.escape(value)
    {:{}, [], [:a, :b, :c]}

    iex> quote do: value
    {:value, [], __MODULE__}

    iex> value = {:a, :b, :c}
    iex> quote do: unquote(value)
    {:a, :b, :c}

`escape/2` is used to escape values (either directly passed or variable bound), while `Kernel.SpecialForms.quote/2` produces syntax trees for expressions.

Link to this function

# expand(ast, env)

View Source

Receives an AST node and expands it until it can no longer be expanded.

Note this function does not traverse the AST, only the root node is expanded.

This function uses `expand_once/2` under the hood. Check it out for more information and examples.

Link to this function

# expand_once(ast, env)

View Source

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
- Compilation environment macros (`__CALLER__/0`, `__DIR__/0`, `__ENV__/0` and `__MODULE__/0`)
- Module attributes reader (`@foo`)

If the expression cannot be expanded, it returns the expression itself. This function does not traverse the AST, only the root node is expanded.

`expand_once/2` performs the expansion just once. Check `expand/2` to perform 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_charlist(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 follows:

    {:__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 straightforward 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_charlist(expanded))

      quote do
        defmodule unquote(name) do
          def name_length, do: unquote(length)
          unquote(block)
        end
      end
    end

Link to this function

# generate_arguments(amount, context)

View Source (since 1.5.0)

## Specs

    generate_arguments(0, context :: atom()) :: []

    generate_arguments(pos_integer(), context) :: [{atom(), [], context}, ...]
    when context: atom()

Generates AST nodes for a given number of required argument variables using `Macro.var/2`.

## Examples

    iex> Macro.generate_arguments(2, __MODULE__)
    [{:arg1, [], __MODULE__}, {:arg2, [], __MODULE__}]

Link to this function

# operator?(name, arity)

View Source (since 1.7.0)

## Specs

    operator?(name :: atom(), arity()) :: boolean()

Returns `true` if the given name and arity is an operator.

Link to this function

# pipe(expr, call_args, position)

View Source

## Specs

    pipe(t(), t(), integer()) :: t()

Pipes `expr` into the `call_args` at the given `position`.

Link to this function

# postwalk(ast, fun)

View Source

## Specs

    postwalk(t(), (t() -> t())) :: t()

Performs a depth-first, post-order traversal of quoted expressions.

Link to this function

# postwalk(ast, acc, fun)

View Source

## Specs

    postwalk(t(), any(), (t(), any() -> {t(), any()})) :: {t(), any()}

Performs a depth-first, post-order traversal of quoted expressions using an accumulator.

Link to this function

# prewalk(ast, fun)

View Source

## Specs

    prewalk(t(), (t() -> t())) :: t()

Performs a depth-first, pre-order traversal of quoted expressions.

Link to this function

# prewalk(ast, acc, fun)

View Source

## Specs

    prewalk(t(), any(), (t(), any() -> {t(), any()})) :: {t(), any()}

Performs a depth-first, pre-order traversal of quoted expressions using an accumulator.

Link to this function

# quoted_literal?(term)

View Source (since 1.7.0)

## Specs

    quoted_literal?(t()) :: boolean()

Returns `true` if the given quoted expression represents a quoted literal.

Atoms, numbers, and functions are always literals. Binaries, lists, tuples, maps, and structs are only literals if all of their terms are also literals.

## Examples

    iex> Macro.quoted_literal?(quote(do: "foo"))
    true
    iex> Macro.quoted_literal?(quote(do: {"foo", 1}))
    true
    iex> Macro.quoted_literal?(quote(do: {"foo", 1, :baz}))
    true
    iex> Macro.quoted_literal?(quote(do: %{foo: "bar"}))
    true
    iex> Macro.quoted_literal?(quote(do: %URI{path: "/"}))
    true
    iex> Macro.quoted_literal?(quote(do: URI.parse("/")))
    false
    iex> Macro.quoted_literal?(quote(do: {foo, var}))
    false

Link to this function

# special_form?(name, arity)

View Source (since 1.7.0)

## Specs

    special_form?(name :: atom(), arity()) :: boolean()

Returns `true` if the given name and arity is a special form.

Link to this function

# struct!(module, env)

View Source (since 1.8.0)

## Specs

    struct!(module, Macro.Env.t()) :: %module{} when module: module()

Expands the struct given by `module` in the given `env`.

This is useful when a struct needs to be expanded at compilation time and the struct being expanded may or may not have been compiled. This function is even capable of expanding structs defined under the module being compiled.

It will raise `CompileError` if the struct is not available.

Link to this function

# to_string(tree, fun \\ fn _ast, string -> string end)

View Source

## Specs

    to_string(t(), (t(), String.t() -> String.t())) :: String.t()

Converts the given expression AST to a string.

The given `fun` is called for every node in the AST with two arguments: the AST of the node being printed and the string representation of that same node. The return value of this function is used as the final string representation for that AST node.

This function discards all formatting of the original code.

## Examples

    iex> Macro.to_string(quote(do: foo.bar(1, 2, 3)))
    "foo.bar(1, 2, 3)"

    iex> Macro.to_string(quote(do: 1 + 2), fn
    ...>   1, _string -> "one"
    ...>   2, _string -> "two"
    ...>   _ast, string -> string
    ...> end)
    "one + two"

Link to this function

# traverse(ast, acc, pre, post)

View Source

## Specs

    traverse(t(), any(), (t(), any() -> {t(), any()}), (t(), any() -> {t(), any()})) ::
      {t(), any()}

Performs a depth-first traversal of quoted expressions using an accumulator.

Link to this function

# underscore(atom)

View Source

## Specs

    underscore(atom() | String.t()) :: String.t()

Converts the given atom or binary to underscore format.

If an atom is given, it is assumed to be an Elixir module, so it is converted to a binary and then processed.

This function was designed to underscore language identifiers/tokens, that's why it belongs to the `Macro` module. Do not use it as a general mechanism for underscoring strings as it does not support Unicode or characters that are not valid in Elixir identifiers.

## Examples

    iex> Macro.underscore("FooBar")
    "foo_bar"

    iex> Macro.underscore("Foo.Bar")
    "foo/bar"

    iex> Macro.underscore(Foo.Bar)
    "foo/bar"

In general, `underscore` can be thought of as the reverse of `camelize`, however, in some cases formatting may be lost:

    iex> Macro.underscore("SAPExample")
    "sap_example"

    iex> Macro.camelize("sap_example")
    "SapExample"

    iex> Macro.camelize("hello_10")
    "Hello10"

Link to this function

# unescape_string(chars)

View Source

## Specs

    unescape_string(String.t()) :: String.t()

Unescapes 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`. Bytes can be given as hexadecimals via `\xNN` and Unicode code points as `\uNNNN` escapes.

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.

Link to this function

# unescape_string(chars, map)

View Source

## Specs

    unescape_string(String.t(), (non_neg_integer() -> non_neg_integer() | false)) ::
      String.t()

Unescapes 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 code point of the character it wants to unescape. Here is the default mapping function implemented by Elixir:

    def unescape_map(unicode), do: true
    def unescape_map(hex), do: true
    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(e), do: e

If the `unescape_map/1` function returns `false`, the char is not escaped and the backslash is kept in the string.

Hexadecimals and Unicode code points will be escaped if the map function returns `true` for `?x`. Unicode code points if the map function returns `true` for `?u`.

## Examples

Using the `unescape_map/1` function defined above is easy:

    Macro.unescape_string("example\\n", &unescape_map(&1))

Link to this function

# unpipe(expr)

View Source

## Specs

    unpipe(t()) :: [t()]

Breaks a pipeline expression into a list.

The AST for a pipeline (a sequence of applications of `|>`) is similar to the AST of a sequence of binary operators or function applications: the top-level expression is the right-most `:|>` (which is the last one to be executed), and its left-hand and right-hand sides are its arguments:

    quote do: 100 |> div(5) |> div(2)
    #=> {:|>, _, [arg1, arg2]}

In the example above, the `|>` pipe is the right-most pipe; `arg1` is the AST for `100 |> div(5)`, and `arg2` is the AST for `div(2)`.

It's often useful to have the AST for such a pipeline as a list of function applications. This function does exactly that:

    Macro.unpipe(quote do: 100 |> div(5) |> div(2))
    #=> [{100, 0}, {{:div, [], [5]}, 0}, {{:div, [], [2]}, 0}]

We get a list that follows the pipeline directly: first the `100`, then the `div(5)` (more precisely, its AST), then `div(2)`. The `0` as the second element of the tuples is the position of the previous element in the pipeline inside the current function application: `{{:div, [], [5]}, 0}` means that the previous element (`100`) will be inserted as the 0th (first) argument to the `div/2` function, so that the AST for that function will become `{:div, [], [100, 5]}` (`div(100, 5)`).

Link to this function

# update_meta(quoted, fun)

View Source

## Specs

    update_meta(t(), (keyword() -> keyword())) :: t()

Applies the given function to the node metadata if it contains one.

This is often useful when used with `Macro.prewalk/2` 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, [], []}

Link to this function

# validate(expr)

View Source

## Specs

    validate(term()) :: :ok | {:error, term()}

Validates the given expressions are valid quoted expressions.

Checks the `t:Macro.t/0` for the specification of a valid quoted expression.

It returns `:ok` if the expression is valid. Otherwise it returns a tuple in the form of `{:error, remainder}` where `remainder` is the invalid part of the quoted expression.

## Examples

    iex> Macro.validate({:two_element, :tuple})
    :ok
    iex> Macro.validate({:three, :element, :tuple})
    {:error, {:three, :element, :tuple}}

    iex> Macro.validate([1, 2, 3])
    :ok
    iex> Macro.validate([1, 2, 3, {4}])
    {:error, {4}}

Link to this function

# var(var, context)

View Source

## Specs

    var(var, context) :: {var, [], context} when var: atom(), context: atom()

Generates an 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__/0`:

    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}