Says which parts of a quote run, without walking any of them.
A quote expression that is itself evaluated has three kinds of part, and parts/1 names
each value's state:
:live— an option value (bind_quoted:,unquote:,location:, …). It is ordinary code, evaluated where the quote expression is.:quoted— thedo:body while unquoting is enabled. It is data, except for the argument of anunquote/unquote_splicingin it, which is:liveagain.:inert— thedo:body underunquote: falseorbind_quoted:(which disables unquoting unlessunquote: truere-enables it). Nothing in it is ever evaluated.
Elixir rejects a quote whose arguments are not written as lists (a variable, a call), so
lists are all parts/1 reads, and anything else is a crash, not a guess. It does accept a
list element that is no pair (quote([{:line, 1} | []], do: …)); that element is :inert.
Inside :quoted data, quoted/1 reads one node: an escape whose argument is :live, a
nested quote, or plain data to keep descending. Elixir quotes a nested quote's body with
unquoting off, so neither quote(do: quote(do: unquote(f()))) nor its stacked form
unquote(unquote(f())) calls f/0, and there is no quote level to count: one escape
leads from :quoted to :live, and nothing leads out of :inert.
A nested quote's options depend on how it is written, because Elixir reads the
argument count. Given two arguments (quote bind_quoted: [v: unquote(f())] do … end) it
quotes the options as the data around them, escapes still on, and f/0 runs. Given one
list holding the options and do: together (quote(bind_quoted: [v: unquote(f())], do: v))
it quotes the whole list with unquoting off, and f/0 does not run. quoted/1 returns the
first as {:options, options, rebuild}, with options still :quoted, and the second as
:inert.
Resolve, body analysis, self-call rewriting, super forwarding and binding analysis share
this reading, not a traversal: each decides what it does with a live expression, and
whether a live option is its business at all.
Summary
Functions
The values in a live quote's arguments, in source order, each with its state, and a
rebuilder that puts replacement values back into the arguments' written shape.
One node met inside :quoted data: {:escape, argument, rebuild} when its argument is
live; for a nested quote, {:options, options, rebuild} when its options are still
:quoted, else :inert; :data for anything else.
Types
Functions
The values in a live quote's arguments, in source order, each with its state, and a
rebuilder that puts replacement values back into the arguments' written shape.
@spec quoted(Macro.t()) :: {:escape, Macro.t(), (Macro.t() -> Macro.t())} | {:options, Macro.t(), (Macro.t() -> Macro.t())} | :inert | :data
One node met inside :quoted data: {:escape, argument, rebuild} when its argument is
live; for a nested quote, {:options, options, rebuild} when its options are still
:quoted, else :inert; :data for anything else.