# `Feel.Backend.Interpreter`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/backend/interpreter.ex#L1)

The backend that walks the resolved form of an expression.

It generates no code. Its executable is the IR itself, and `run/3` evaluates it
node by node, calling `Feel.Runtime` for every operation. Nothing is loaded into the
VM and no atoms are created, so it is the backend to use for expressions that come
from sources that are not trusted. It is also the reference that the BEAM backend is
tested against.

Each operation returns an outcome (`t:Feel.Runtime.Env.outcome/0`), and the
interpreter passes it to `Feel.Runtime.Env.settle/3` with the span of the node, so a
diagnostic points at the text it came from and strict mode ends the run there.

## Bindings

A `:var` node is looked up with `Feel.Runtime.Bindings.lookup/4` (D-37), the same
function the generated code of the BEAM backend calls, so both find the same value.

## Operands

Both operands of a binary operator are always evaluated, `and` and `or` included:
the specification gives them no order, and a `false` decides a conjunction whatever
the other operand is, an error included (D-53). So an error in the operand that does
not matter is still reported, and in strict mode it ends the run.

A conditional is the exception, as the specification has it: it evaluates the condition and
then only the branch it takes, the `then` branch for a condition that is `true` and the `else`
branch for any other value. So nothing in the other branch is reported, and in strict mode it
does not end the run.

## Lists and contexts

The elements of a list are evaluated in order. The entries of a context are evaluated in the order the
node has them, which is the order they depend on each other in, and the value of each is bound to its
key for the ones after it: a `:local` node reads it. The bindings of the run hold them under `{:local,
name}`, which no name of the bindings can be, and the context's own copy of the bindings is what the
entries after see, so a key that an inner context has again shadows the outer one only inside it.

## Loops

`for`, `some` and `every` are run by `Feel.Runtime.Iteration`, which takes a function for each domain and one for the
body: the walk of the nodes, with the iterators bound as `{:local, name}` in the bindings (D-86). A domain with more
than 16 iterators before it is given and binds only the ones its code names (`Feel.IR.local_names/1`), where binding
all of them for each domain made a loop of `n` iterators `n * n / 2` bindings (D-86).

## Nodes

`run/3` evaluates every node that the analyzer produces (see `Feel.IR`, which also says which
nodes of its set are not produced yet). A node that it has no clause for raises `ArgumentError`:
that is a mistake of the analyzer and not of the expression, which is why it is not a diagnostic.

## The walk and the monitor

The walk of the nodes is in `Feel.Backend.Interpreter.Walk`, one text that is two modules: `Feel.Backend.Interpreter.Plain`
for `run/3`, and `Feel.Backend.Interpreter.Monitored` for `run_monitored/4`, which tells a function the value of every node
(`Feel.Paranoid`, D-159). A run does not ask at each node whether there is a monitor: the question cost 3 to 14% of a run of a
few operations on names.

# `monitor`

```elixir
@type monitor() :: (Feel.IR.t(), Feel.Value.t() -&gt; term())
```

What a monitored run tells of each node: the node, and the value it made.

# `t`

```elixir
@type t() :: %Feel.Backend.Interpreter{
  binding_names: MapSet.t(Feel.Name.t()) | nil,
  dialect: Feel.Dialect.t(),
  env: Feel.Runtime.Env.t() | nil,
  extensions: Feel.Extensions.t(),
  ir: Feel.Backend.ir()
}
```

# `compile`

```elixir
@spec compile(Feel.Backend.ir(), [Feel.Backend.compile_option()]) :: {:ok, t()}
```

Wraps the IR in an executable, with the dialect and the extensions it was prepared with (D-49, D-81). The
interpreter has nothing to compile, so the other options are only checked. The profile `:explain` is not
implemented yet and raises `ArgumentError` (`Feel.Backend.validate_profile!/1`).

    iex> {:ok, executable} = Feel.Backend.Interpreter.compile(:an_ir, [])
    iex> executable.ir
    :an_ir

# `evaluate`

```elixir
@spec evaluate(Feel.IR.t(), Feel.bindings(), Feel.Runtime.Env.t()) ::
  {Feel.Value.t(), Feel.Runtime.Env.t()}
```

Evaluates an IR on a set of bindings and an environment, as `run/3` does, and returns `{value, env}` without catching
the end of a run (`Feel.Runtime.Env.run/2` is what does).

It is the walk itself, for what runs the interpreter in the middle of a run: the guarded fast path of the BEAM backend
(`Feel.Backend.Beam.Scalar`) runs an expression this way from the environment it was given when it finds that it
cannot answer, through `Feel.Runtime.Interpret` (D-164).

    iex> ir = {:arithmetic, %{span: {0, 5}}, :add, {:const, %{span: {0, 1}}, Decimal.new(1)}, {:var, %{span: {4, 5}}, "x"}}
    iex> {value, _env} = Feel.Backend.Interpreter.evaluate(ir, %{"x" => Decimal.new(2)}, Feel.Runtime.Env.new())
    iex> value
    Decimal.new(3)

# `run`

```elixir
@spec run(t(), Feel.bindings(), [Feel.run_option()]) :: Feel.result(Feel.Value.t())
```

Evaluates an executable on a set of bindings.

Takes the run options of `Feel.run/3` and raises `ArgumentError` for any other.

    iex> ir = {:const, %{span: {0, 1}, type: :number}, Decimal.new(7)}
    iex> {:ok, executable} = Feel.Backend.Interpreter.compile(ir, [])
    iex> Feel.Backend.Interpreter.run(executable, %{}, [])
    {:ok, Decimal.new(7), []}

    iex> ir = {:var, %{span: {0, 1}, type: :any}, "x"}
    iex> {:ok, executable} = Feel.Backend.Interpreter.compile(ir, [])
    iex> Feel.Backend.Interpreter.run(executable, %{"x" => "a"}, [])
    {:ok, "a", []}

# `run_monitored`

```elixir
@spec run_monitored(t(), Feel.bindings(), [Feel.run_option()], monitor()) ::
  Feel.result(Feel.Value.t())
```

Evaluates an executable and tells `monitor`, a function of a node and its value, the value of every node as it is made
(`Feel.Paranoid`). The run is the run of `run/3`.

    iex> ir = {:const, %{span: {0, 1}, type: :number}, Decimal.new(7)}
    iex> {:ok, executable} = Feel.Backend.Interpreter.compile(ir, [])
    iex> test = self()
    iex> Feel.Backend.Interpreter.run_monitored(executable, %{}, [], fn _node, value -> send(test, {:value, value}) end)
    {:ok, Decimal.new(7), []}
    iex> receive do {:value, value} -> value end
    Decimal.new(7)

---

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