Stable, resolved view of a known-macro call passed to routing and hosting callbacks.
arguments contains only arguments visible in the written call. For a piped call, the pipe's
left side is the macro's effective argument zero but is not part of the call node; pipe_left
carries it, and pipe_mode and effective_arity are derived from it. rebuild.(name, arguments)
preserves the source's bare, qualified, or aliased call form.
The pipe's left side
pipe_left is :unpiped, or {:piped, left} with the left side of the |> the call is the
right side of. It lets a classifier route the piped position by the shape of what is piped
(Post |> from(…) and build(x) |> from(…) want different treatments), and lets a host or
mutator read a declaration written there ((p in Post) |> from(…)).
Two limits:
- Read-only.
rebuildand a host'ssplicerewrite the visible call only. Nothing a callback returns can replace the left side, which is why the piped position cannot be routed:hosted. - As written, never resolved.
leftis the source AST, without the alias and import resolution Mutare records on the nodes it walks.Mutare.Calls.resolved_call/1on a call inside it returnsnil, whatever the call resolves to in the source — match it by shape. In a chain,leftis the whole upstream pipe (a |> b()for thec()stage ofa |> b() |> c()).
The struct is produced by Mutare. Extension callbacks should match only the fields they need so
additional fields can be added compatibly. To build one in a test, use new/5: it derives the
dependent fields, so a later addition cannot break the test.
Summary
Functions
Build a call value from its independent facts: the written call node, the resolved module
and name, the pipe_left, and the rebuild function.
The Mutare.Mutator.pipe_mode/0 a pipe_left/0 implies.
Types
@type pipe_left() :: :unpiped | {:piped, Macro.t()}
Whether a call is a pipe's right side, and if so the left side as written.
Functions
@spec new( Macro.t(), module() | atom() | nil, atom(), pipe_left(), (atom(), [Macro.t()] -> Macro.t()) ) :: t()
Build a call value from its independent facts: the written call node, the resolved module
and name, the pipe_left, and the rebuild function.
arguments are read off node, and pipe_mode and effective_arity follow from pipe_left,
so the derived fields always agree with their sources.
iex> node = quote(do: where(x > 1))
iex> call = Mutare.CallRouting.Call.new(node, Ecto.Query, :where, {:piped, quote(do: Post)},
...> fn name, args -> {name, [], args} end)
iex> {call.pipe_mode, call.effective_arity, length(call.arguments)}
{:piped, 2, 1}
@spec pipe_mode(pipe_left()) :: Mutare.Mutator.pipe_mode()
The Mutare.Mutator.pipe_mode/0 a pipe_left/0 implies.
iex> Mutare.CallRouting.Call.pipe_mode(:unpiped)
:unpiped
iex> Mutare.CallRouting.Call.pipe_mode({:piped, quote(do: query)})
:piped