# `Statifier.Machine.Content.If`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.0.0/lib/statifier/machine/content/if.ex#L1)

A compiled `<if>` executable-content node (spec 4.3, 4.4, 4.5) - the
interned counterpart to `Statifier.Document.If`. `branches` is the
document-order partition list: each `Statifier.Machine.Content.If.Branch`
holds its compiled `cond` (`nil` for the `<else>` branch - spec 4.5.1:
"`<else>` ... is equivalent to an `<elseif>` with a 'cond' that always
evaluates to true"), the diagnostic span that `cond` compiled against, and
the dense `c_index` list assigned to that partition's own content
(`Statifier.Compiler`'s Decision 2), resolved through
`Statifier.Machine.content/2` at runtime rather than carried inline.

## Why this node's `execute/2` does not recurse through the block runner

`Statifier.Interpreter.Content`'s block-running function is not called
from here, for four reasons:

1. That function returns a bare `Statifier.MachineState.t()`, not a
   `Statifier.ExecutableContent.Context.t()` - it builds a *fresh*
   evaluator context for its own call and discards it on return, so an
   `<assign>` inside a selected partition could never thread its rebuilt
   datamodel context back to a node after the `</if>` in the same
   enclosing block. SCION's `if_else/test0` requires exactly that
   visibility, so recursing through that function would be wrong here,
   not merely inelegant.
2. That function is the sole site that turns a node's bare `{:error, _}`
   into the platform's own execution-failure notification (ADR-0003).
   Recursing through it would make this file an indirect raiser of that
   notification, which the structural sweep in
   `content_acceptance_test.exs` exists to catch - this file must never
   mention that notification's own name, nor construct one of the structs
   the platform uses to carry it.
3. That function emits one trace effect per call, carrying an `owner` -
   an `<if>` is not a block owner and has no `owner` value of its own to
   give it.
4. It would make this file depend on `Statifier.Interpreter`, reentering
   the very protocol dispatch this file is itself a leaf of.

So `execute/2` folds the selected branch's own `c_index` list directly:
resolve each through `Statifier.Machine.content/2`, dispatch through
`Statifier.ExecutableContent.execute/2` - the same two-line
resolve-then-dispatch shape the block runner's own per-node step takes -
accumulating effects in document order and halting on the first failure.
This ~dozen-line fold is deliberately duplicated rather than shared: every
candidate shared home either reintroduces reason 4's layering inversion or
turns a runner-only helper into one whose only other caller is a leaf.

Its `Statifier.ExecutableContent` implementation lives right below the
struct: this file is the whole node, top to bottom, with no dispatcher
anywhere else in the tree.

# `t`

```elixir
@type t() :: %Statifier.Machine.Content.If{
  branches: [Statifier.Machine.Content.If.Branch.t()],
  c_index: non_neg_integer(),
  location: Statifier.Parser.Location.t()
}
```

---

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