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

One compiled `<invoke>` element (spec 6.4) - the interned counterpart to
`Statifier.Document.Invoke`, reachable only through its owning state as
`elem(machine.states, i).invoke`, in document order.

`index` is this invocation's position within its own state's `invoke`
list - what `{:invoke, state_index, invoke_index}` and `{:finalize,
state_index, invoke_index}` name, `Statifier.Compiler.Expressions.owner_ref/0`'s
and `Statifier.Machine.Content.owner/0`'s own new arms.

`type` and `src` each fold their own static/expr attribute pair into a
single `Machine.expr() | nil`, mirroring `Statifier.Machine.Donedata.expr`:
`{:static, v}` from `type`/`src`, `{:compiled, ...}` from
`typeexpr`/`srcexpr`, `nil` when neither was written (an already-validated
document never writes both - 6.4.1's "Must not occur with" pair).

`id` is the author's literal `id` attribute, used verbatim
(ADR-0008 as amended - "document-authored IDs are always respected").
`idlocation` stays a **raw, uncompiled location path string**, never a
compiled expression - the same reason
`Statifier.Machine.Content.Assign`'s moduledoc gives for its own
`location` field: a location path cannot be resolved any earlier than
execute time, even in principle.

`namelist` and `params` are kept as two separate lists of
`Statifier.Machine.Param.t()`, every `namelist` entry compiled with
`kind: :location`, even though 6.4's data-sharing rule treats the two
channels identically at the invoked service - they stay apart here only so
the validator can enforce 6.4.1's "namelist Must not occur with the
`<param>` element" and so a later empty-`<finalize>` auto-assign can find
its write targets by name. A `namelist` entry that fails to compile as a
location expression does not fail `Statifier.Compiler.compile/1`: it
carries `{:invalid, error}` on the entry's `expr` (5.9.4 deferral, see
`Statifier.Machine.Param`) and aborts the invocation at execute time -
`Interpreter.resolve_params/2` - rather than at load time.

`content` folds `<content>`'s markup into a single `Machine.expr()`,
exactly as `Machine.Donedata.expr` does - `nil` when `<invoke>` has no
`<content>` child.

`finalize` is `nil` when `<invoke>` has no `<finalize>` child at all, and a
`Statifier.Machine.Block.t()` (possibly with an empty `content` list) when
it does - the same absent-versus-empty distinction
`Statifier.Document.Invoke`'s moduledoc describes, carried through
compilation structurally. Unlike every other field here, its `c_index`es
come from the same dense, whole-machine counter every `<onentry>`/`<onexit>`
block uses - `<finalize>` is executable content, the other fields are not.

`attribute_locations` is `Statifier.Document.Invoke`'s own map, carried
through unchanged rather than distilled into individual `*_location`
fields the way most other compiled nodes are: an `<invoke>` has eight
source attributes and this struct has no per-field diagnostic use for most
of them, so the one shared map stands in for all of them at once.

# `t`

```elixir
@type t() :: %Statifier.Machine.Invoke{
  attribute_locations: Statifier.Document.attribute_locations(),
  autoforward: boolean(),
  content: Statifier.Machine.expr() | nil,
  finalize: Statifier.Machine.Block.t() | nil,
  id: String.t() | nil,
  idlocation: String.t() | nil,
  index: non_neg_integer(),
  location: Statifier.Parser.Location.t(),
  namelist: [Statifier.Machine.Param.t()],
  params: [Statifier.Machine.Param.t()],
  src: Statifier.Machine.expr() | nil,
  type: Statifier.Machine.expr() | nil
}
```

---

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