# `Mutare.Metamutant`
[🔗](https://github.com/foxbenjaminfox/mutare/blob/v0.2.1/lib/mutare/metamutant.ex#L1)

The shape of a selector `case` subject in the metamutant.

This is the one piece of generated structure that `Mutare.Transform` writes
and that `Mutare.Manifest` recognises for `Mutare.Poison` readback.
Owning it in a single module keeps the producer from hand-building the same AST
literal twice and keeps the consumer from re-deriving how to spot a selector.

A selector `case` looks like:

    case :persistent_term.get(:mutare_active, 0) do
      17 -> <mutated>     # one clause per mutant id hosted here
      18 -> <mutated>
      _  -> <original>    # the catch-all: baseline + every inactive mutant
    end

The subject is one of two shapes. A module-level / `:scaffold` / head-default
selector reads `:persistent_term` **inline** (the form above). A selector inside a
function *body* instead reads the **hoisted** active id — a bare reference to the
dispatch variable `mutare_active`, bound once per function activation (the lifted
dispatcher threads it as the base clause's first parameter; a non-lifted function
binds it in a `:do`-block prologue), so the per-site `:persistent_term.get` is gone:

    case mutare_active do          # the hoisted read — same shape, cheaper subject
      17 -> <mutated>
      mutare_active -> <original>
    end

Recognising the subject is enough to find every selector:

  * `subject_ast/0` builds the inline subject `Transform` splices in,
  * `subject?/2` recognises *either* shape — the inline read unconditionally, the
    hoisted bare variable only when the active-id variable name is supplied (the
    predicate `Mutare.Manifest` uses to walk a rendered metamutant, under the name the
    transform recorded for the file — `Mutare.Transform.Result.dispatch_var`).

`subject?/2` is tolerant of how the subject is *parsed back*: bare ASTs may keep
`:persistent_term`/`:mutare_active` as atoms, while `Mutare.Manifest`
re-parses with `Code.string_to_quoted!` plus a literal encoder that wraps literals as
`{:__block__, _, [literal]}` for `Sourceror.get_range/1` compatibility. The
predicate must match both shapes.

`Mutare.Selector` defines the runtime constants (the `:persistent_term` key and
the baseline id); this module builds their AST.

Schema builds pass a file namespace to `subject_ast/1`. Its read projects the
single global selection before it is used by any local selector or lifted guard:

    case :persistent_term.get(:mutare_active, 0) do
      {:"lib/example.ex", mutare_local_id} when :erlang.is_integer(mutare_local_id) ->
        mutare_local_id

      0 ->
        0

      _ ->
        :inactive
    end

This projection is hoisted with the read in function bodies; default arguments
and other inline positions keep it self-contained. Local gates and exclusions
remain integer-based. `:inactive` differs from baseline so other files' coverage
gates short-circuit without consulting the tracking flag. `subject?/2` recognises
the complete projection, including after literal-encoded reparse. Its inner case
has no positive integer branches and therefore contributes no mutant to Manifest.

# `pattern_subject?`

```elixir
@spec pattern_subject?(Macro.t(), atom() | nil) :: boolean()
```

Returns whether `node` is a tupled selector subject.

The tuple-the-scrutinee path starts with `{<selector_subject>, <scrutinee>}`.
A generated single-clause case records coverage after evaluating this tuple and returns
the tuple unchanged; its temporary bindings stay outside source clause scopes. Recognise
that wrapper only through its coverage record and matching input/output variables.
The mutant clauses gate on the active id in guards.

`var` is compared against the variable the *pattern* binds, not against anything inside
the record: `Mutare.Coverage.Recorder.record?/1` deliberately ignores the gate, so the
gate may later become a hoisted boolean without breaking attribution. That the gate and
the pattern name the same variable is therefore an emitter invariant now, held by
`pattern_subject_ast/5` and its caller building both from one `Config.active_var`, and
not something this reader can re-check.

Both the bare two-tuple and the `{:__block__, _, [{first, scrutinee}]}` wrapper
produced by literal-encoded reparse are accepted. `var` is passed through so the
hoisted selector-variable form is recognised too.

## Examples

    iex> subject = {Mutare.Metamutant.subject_ast(), {:value, [], nil}}
    iex> Mutare.Metamutant.pattern_subject?(subject)
    true

    iex> subject = {{:mutare_active, [], nil}, {:value, [], nil}}
    iex> Mutare.Metamutant.pattern_subject?(subject)
    false
    iex> Mutare.Metamutant.pattern_subject?(subject, :mutare_active)
    true

# `pattern_subject_ast`

```elixir
@spec pattern_subject_ast(Macro.t(), Macro.t(), atom(), atom(), Macro.t()) ::
  Macro.t()
```

Build the tupled selector subject with one recording point after both inputs
succeed. The clause-local temporaries never enter source clause scopes, and the
original scrutinee's bindings escape unchanged. `pattern_subject?/2` reads this
same structure after rendering; coverage gate construction belongs to Recorder.

`active_var` must be the same variable the `record` was gated on — this function is
the one place that pairs them, because the reader no longer can (see
`pattern_subject?/2`).

# `subject?`

```elixir
@spec subject?(Macro.t(), atom() | nil) :: boolean()
```

Returns whether `node` is a selector subject.

`Mutare.Manifest` uses this while walking rendered metamutant source. Three shapes
match:

  * the inline read built by `subject_ast/0`:
    `:persistent_term.get(<key>, <baseline>)`
  * the namespace projection built by `subject_ast/1`
  * the hoisted read used inside function bodies: a bare reference to the active
    mutant variable `var`

The hoisted form is recognised only when `var` is supplied. That prevents an
ordinary source-level `case some_var do ...` from being treated as a selector.

Literal wrappers added by `Mutare.Manifest`'s readback parse are accepted,
as are bare atoms from ordinary quoted ASTs.

## Examples

    iex> Mutare.Metamutant.subject?(Mutare.Metamutant.subject_ast())
    true
    iex> Mutare.Metamutant.subject?({:mutare_active, [], nil})
    false
    iex> Mutare.Metamutant.subject?({:mutare_active, [], nil}, :mutare_active)
    true

# `subject_ast`

```elixir
@spec subject_ast(String.t() | nil) :: Macro.t()
```

The selector subject `Transform` splices into every selector/dispatcher `case`:
`:persistent_term.get(<key>, <baseline>)`, optionally projected into a file namespace.

## Examples

    iex> Mutare.Metamutant.subject_ast() |> Mutare.Metamutant.subject?()
    true

---

*Consult [api-reference.md](api-reference.md) for complete listing*
