The Predicator.FunctionProvider carrying In/1 (spec 5.9.1), replacing
Statifier.Evaluator's former private closure-building helper.
A provider entry is named by {module, atom} rather than by a captured
function() value (deps/predicator/lib/predicator/functions/provider.ex),
so in_state/2 reads the current configuration from its
%Predicator.Context{} argument's host slot instead of closing over it.
Statifier.Evaluator.context/1 sets host to {machine, configuration}
and refreshes it per site with Predicator.Context.put_host/2 - see that
module's moduledoc for why this dissolves the "not a resumable position"
ground the closure used to force.
It also resolves a host's :function_providers list
(from_providers/1) into the full dispatch map a session stamps onto
Statifier.MachineState's functions field, which Statifier.Evaluator.context/1 then
uses in place of the constant's own map (ADR-0078).
Summary
Types
A resolved dispatch map: function name to {arity, {module, atom}}, the
shape Predicator.Context keeps in its functions field. The map
from_providers/1 returns holds every name base_context/0 holds plus
each host provider's names.
Functions
The fixed half of every context this library builds: an empty data, a
nil host, on_unbound: :error, and functions resolved once at
compile time to %{"In" => {1, {Statifier.Evaluator.Functions, :in_state}}} plus
the four builtin providers. Statifier.Evaluator.context/1 starts from
this constant on every call, then layers in host via
Predicator.Context.put_host/2 and the datamodel via
Statifier.Evaluator.bind/3 - so Predicator.Context.new/2 and
Predicator.Context.resolve_functions/1 never run on that hot path.
The names every chart can call without registering anything: In and
the builtin providers' names, sorted. Statifier.compile/2 adds the
names of its :function_providers to this set before it checks the
calls a chart makes.
Resolves a host's :function_providers list into the dispatch map an
evaluation context uses: base_context/0's map with every provider's
functions merged in.
from_providers/1, raising ArgumentError on a refusal. The form
Statifier.MachineState.new/2 and put_function_providers/2 use: a bad
provider list is host misuse, refused the way a bad :datamodel is.
This provider's one entry: In/1, dispatched to in_state/2.
In(stateId): true when stateId names a state in context.host's
configuration, false for an inactive or undeclared state id.
The names a :function_providers list registers, sorted, after the same
checks from_providers/1 makes. nil and [] answer {:ok, []}.
Types
@type registered() :: %{ required(String.t()) => {Predicator.Evaluator.function_arity(), {module(), atom()}} }
A resolved dispatch map: function name to {arity, {module, atom}}, the
shape Predicator.Context keeps in its functions field. The map
from_providers/1 returns holds every name base_context/0 holds plus
each host provider's names.
Functions
@spec base_context() :: Predicator.Context.t()
The fixed half of every context this library builds: an empty data, a
nil host, on_unbound: :error, and functions resolved once at
compile time to %{"In" => {1, {Statifier.Evaluator.Functions, :in_state}}} plus
the four builtin providers. Statifier.Evaluator.context/1 starts from
this constant on every call, then layers in host via
Predicator.Context.put_host/2 and the datamodel via
Statifier.Evaluator.bind/3 - so Predicator.Context.new/2 and
Predicator.Context.resolve_functions/1 never run on that hot path.
Two calls return the same term; nothing about this value varies at runtime.
@spec base_names() :: [String.t()]
The names every chart can call without registering anything: In and
the builtin providers' names, sorted. Statifier.compile/2 adds the
names of its :function_providers to this set before it checks the
calls a chart makes.
@spec from_providers(providers :: [module()] | nil) :: {:ok, registered() | nil} | {:error, {:not_a_list, term()} | {:invalid_provider, term(), String.t()} | {:shadowed_names, [String.t()]}}
Resolves a host's :function_providers list into the dispatch map an
evaluation context uses: base_context/0's map with every provider's
functions merged in.
nil and [] both answer {:ok, nil}, which means "no host function":
Statifier.Evaluator.context/1 then uses base_context/0 unchanged.
Refuses, without raising, with:
{:error, {:not_a_list, value}}- the option is not a list.{:error, {:invalid_provider, module, message}}- a list entry is not an atom, or names a module that does not load, exportfunctions/0, or export each named function at arity 2.Predicator.Context.resolve_functions/1does the check, andmessageis its text.{:error, {:shadowed_names, names}}- a provider names a function the base set already has (base_names/0), soInand the builtins always mean the same thing.namesis sorted.
@spec from_providers!(providers :: [module()] | nil) :: registered() | nil
from_providers/1, raising ArgumentError on a refusal. The form
Statifier.MachineState.new/2 and put_function_providers/2 use: a bad
provider list is host misuse, refused the way a bad :datamodel is.
@spec functions() :: %{required(String.t()) => {non_neg_integer(), atom()}}
This provider's one entry: In/1, dispatched to in_state/2.
@spec in_state(args :: [Predicator.Types.value()], context :: Predicator.Context.t()) :: {:ok, boolean()}
In(stateId): true when stateId names a state in context.host's
configuration, false for an inactive or undeclared state id.
context.host must be {machine, configuration}, the shape
Statifier.Evaluator.context/1 sets via Predicator.Context.put_host/2.
The names a :function_providers list registers, sorted, after the same
checks from_providers/1 makes. nil and [] answer {:ok, []}.