Mutare.Transform.KeywordRouting (mutare v0.4.1)

Copy Markdown View Source

Interprets a normalized keyword route against one concrete argument, without walking it.

A literal keyword list becomes ordered pairs of {node, treatment} entries plus a shape-preserving rebuilder. A non-keyword argument gets its whole-argument fallback: the leading treatment for a keyed refinement, or :raw for positional keyword routing. Positional routing requires exactly one treatment per pair, and never pads or truncates: decode!/2 raises on a mismatch, and is what Resolve applies to the written call the route was stamped on; decode/2 reads a mismatch as the :raw fallback, since the only argument that can present one is a mutator's rebuild whose pairs a static positional route no longer fits (a rebuilt call is routed again before it is read, Mutare.Transform.Resolve.reroute/1; a classifier answers for the rebuilt pairs, a static list keeps its count) — a stamp that does not fit says nothing about the argument.

Keyed refinements choose each value's final treatment before any descent. Unnamed values and data keys inherit the leading treatment, except that :interior becomes :expression below the container. Block keys are always raw. Positional keyword routes leave all keys raw and assign treatments to values by order, including duplicate keys.

Resolve, body analysis, guard tagging, self-call rewriting and binding analysis share this interpretation, not a traversal. Each pass still decides what a treatment means for its task; the container's own offer and nested syntax scopes also remain with that pass. In particular, withholding mutation does not establish whether an expression executes.

Summary

Functions

decode/2, raising where a positional keyword route names a treatment count other than the argument's pair count — the route and the written call disagree about the argument's shape, which is the route's error to fix, loud and at transform time.

Types

decoded()

@type decoded() ::
  {:pairs, [{routed_node(), routed_node()}], rewrap()} | {:whole, position()}

position()

@type position() :: treatment() | routing()

rewrap()

@type rewrap() :: ([{Macro.t(), Macro.t()}] -> Macro.t())

routed_node()

@type routed_node() :: {Macro.t(), position()}

routing()

@type routing() ::
  {:keyed, treatment(), [{atom(), position()}]} | {:keyword, [position()]}

treatment()

@type treatment() :: atom() | {:hosted, [module()]}

Functions

decode(arg, arg)

@spec decode(Macro.t(), routing()) :: decoded()

decode!(arg, routing)

@spec decode!(Macro.t(), routing()) :: decoded()

decode/2, raising where a positional keyword route names a treatment count other than the argument's pair count — the route and the written call disagree about the argument's shape, which is the route's error to fix, loud and at transform time.