Statifier.Machine.Content.If (Statifier v2.0.0)

Copy Markdown View Source

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.

Summary

Types

t()

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