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

Turns the resolved form of an expression into Erlang abstract format.

The result is a list of forms that `:compile.forms/2` accepts: the module
attribute, the export of `run/2`,
and the function that runs the expression. The generated function calls only
`Feel.Runtime` and the built-in functions; it never calls anything chosen by the
expression.

Abstract format is emitted directly, not Elixir or Erlang source text, so no
string from the expression is ever interpreted as code. Strings and numbers in the
expression become literal terms. Names from the expression are never turned into
atoms: the variables of generated code are numbered (`V1`, `E1`, and so on), and the
names of bindings are binaries.

## The generated function

`run(Bindings, Env0)` takes the bindings and the run environment
(`Feel.Runtime.Env`) and returns `{Value, Env}`, as the interpreter's evaluation
does. The body is a straight line of matches, one for each operation, in the order
the interpreter evaluates them (left operand, right operand, operation), so the
diagnostics of a run come out in the same order:

    run(_Bindings, E0) ->
        {V1, E1} = 'Elixir.Feel.Runtime.Env':settle(E0,
            'Elixir.Feel.Runtime.Arithmetic':multiply(2, 3), {4, 9}, E0),
        {V2, E2} = 'Elixir.Feel.Runtime.Env':settle(E1,
            'Elixir.Feel.Runtime.Arithmetic':add(1, V1), {0, 9}, E0),
        {V2, E2}.

The last argument of `settle` is the environment from before the operands of the operation, which tells the
diagnostics that the operands reported (the ones that can explain a `null` operand, D-103) from the ones before them
(D-103). Only the arithmetic operators, the inclusive comparisons, `between` and the tests of `in` have it.

A constant is a literal in the call that uses it. The span is the one of the node, so a
diagnostic points at the same text as the interpreter's. A name is a call to
`Feel.Runtime.Bindings.lookup/4`, with the name as a binary, and the first parameter
is called `Bindings` only when the expression reads one. Both operands of every binary
operator are evaluated, left then right, with no short cut, as the interpreter does
(D-53).

The constants above are shown as numbers to keep the example short; a number is a
`Decimal`, a literal map in the generated code.

## The fast path

An expression that only does scalar work on declared names is not emitted as above but by
`Feel.Backend.Beam.Scalar` (D-164): one function that reads the names it needs from the bindings, does the operations
with no environment and no outcome, accounting for constructed strings; a `fallback/2` that runs the expression in the
interpreter from the environment it was given is what it does for anything it is not sure of. `emit/2` asks it first and
uses its forms if it makes any, so the straight line of this module is what is left: lists, contexts, loops, functions,
calls of built-in functions, paths, dates, unary tests, allowed values and a declared result, an expression that
reads no name, and one of more than 32 nodes.

## Nodes

It emits every node that the analyzer produces (see `Feel.IR`), and raises `ArgumentError` for any
other. A new kind of node needs a clause here as well as in `Feel.Backend.Interpreter.Walk`. The
`:profile` option is accepted and does not change the code yet.

## Lists and contexts

The elements of a list are evaluated in order and put in a list expression. The entries of a context
are evaluated in the order the node has them, and the value of each is kept for the ones after it:
a `:local` node is the variable that holds it, and a context ends in a map expression of its keys
and those variables. A key is a binary in the map and never an atom or a name of a variable, so
nothing from the expression becomes code. Both are passed through `Feel.Runtime.Env.settle/3` as a
value, so a list that is too long ends the run as it does in the interpreter.

If every value of a list were a variable that is alive until the list is built, the Erlang compiler would take more
than linear time for the function (a hundred values compile in a fifth of a second, five hundred in four seconds, and
about a thousand are more than a function can hold, which is a `:backend` error, `:compile_failed`), and the cuts of
`Feel.Backend.Beam.Chunks` (below) would find no place at which few variables are alive. So the values of a long list
are put in a variable of their own as they are made, `L33 = [V1, …, V16]` and then `L50 = L33 ++ [V34, …]`, and the
entries of a context in a map that a group of entries updates at a time (`L50` is `L33` with the next entries), in
which the entries that later entries read are read (`map_get(Key, L50)`) and are not kept as variables. The same is done for the
arguments of a call and the tests of `in` and of unary tests, which are lists as well (D-113). A group ends after the
item at which it has bound 16 variables, wherever that is; a list that binds fewer is the list of its values.

## Funs with many parameters

The funs of a function value, of a loop's domains and of its body get their parameters as one list. Up to 16
parameters the head is the list of their variables (`fun (E, [P3_0, P3_1])`). With more, a pattern with so many
variables, read in the body, costs the Erlang compiler more than linear time (and a `for` with `n` iterators has
`n * n / 2` of them, since each domain gets the iterators before it), so the fun takes the list as one variable,
its body begins with `T = list_to_tuple(Args)` and reads the parameter `i` as `element(i, T)`. A tuple that the body
does not read is not made (D-113). A domain with more than 16 iterators before it is told, in the `reads` option of
the call of the loop, the places of the ones its code names, and is given the values at them and no others, so its
head is the list of those variables (D-86); the loop would otherwise make the list of all the ones before it for
each domain, which is `n * n / 2` for a loop of `n` iterators.

## Long bodies

The Erlang compiler takes more than linear time for one long function, and a body is as long as the expression:
`x and x and …` of 400 terms took it 4.9 s (D-113). `emit/2` therefore gives the function it made to
`Feel.Backend.Beam.Chunks`, which cuts a body of more than 32 statements, where few variables are alive, into
functions that call one another: `run/2` ends in a tail call of `run_1/N`, which takes the variables that the rest of
the body reads, and so on. The statements are the same and in the same order, so a run reports what it did. The bodies of
the branches of a conditional and of the functions below are cut in the same way.

## Conditionals

A conditional runs only the branch it takes, so it is the one node that is not a straight line
of matches: the two branches are the clauses of a `case` on the condition, each with statements
of its own that end in the value and the environment, and the result of the `case` is matched
like any other operation. The numbers of the variables go on across the branches, so that no
variable is bound twice, and both branches start from the environment that the condition gave.
For `if c then 2 else 3 / z`:

    run(Bindings, E0) ->
        {V1, E1} = 'Elixir.Feel.Runtime.Bindings':lookup(E0, Bindings, <<"c">>, {3, 4}),
        {V4, E4} = case V1 of
            true ->
                {2, E1};
            _ ->
                {V2, E2} = 'Elixir.Feel.Runtime.Bindings':lookup(E1, Bindings, <<"z">>, {21, 22}),
                {V3, E3} = 'Elixir.Feel.Runtime.Env':settle(E2,
                    'Elixir.Feel.Runtime.Arithmetic':divide(3, V2), {17, 22}, E1),
                {V3, E3}
        end,
        {V4, E4}.

Only `true` takes the first clause: `false`, `null` and a value that is not a boolean all take
the second (Table 50). The choice itself requires no runtime call.

## Allowed values

A value with allowed values (D-138) is a call to `Feel.Runtime.AllowedValues.verify/5`, which
gets the value, who it is, where it is, and a function of the environment that runs the tests.
The function is a closure in the generated code: it binds `?` in a copy of the bindings
(`Feel.Runtime.Bindings.bind_input/2`) and runs the tests in a straight line of their own,
with numbers that go on from those of the function around it, since a variable that is bound
inside a function and has the name of one outside it is a match and not a new variable:

    run(Bindings, E0) ->
        {V1, E1} = 'Elixir.Feel.Runtime.Bindings':lookup(E0, Bindings, <<"age">>, {0, 3}),
        {V3, E3} = 'Elixir.Feel.Runtime.AllowedValues':verify(E1, V1, <<"age">>, {0, 3},
            fun (E2) ->
                B2 = 'Elixir.Feel.Runtime.Bindings':bind_input(Bindings, V1),
                ...
                {'Elixir.Feel.Runtime.UnaryTests':satisfied(positive, [V2]), E2}
            end),
        {V3, E3}.

# `forms`

```elixir
@type forms() :: [:erl_parse.abstract_form()]
```

A list of forms in Erlang abstract format.

# `option`

```elixir
@type option() :: {:module, module()} | {:profile, :fast | :explain}
```

Options for `emit/2`.

  * `:module` - the name of the module to generate. Required.
  * `:profile` - `:fast` (default) or `:explain`, as in `t:Feel.Backend.compile_option/0`. `:explain` is not
    implemented yet and raises `ArgumentError` (`Feel.Backend.validate_profile!/1`).

# `emit`

```elixir
@spec emit(Feel.Backend.ir(), [option()]) :: {:ok, forms()} | {:error, Feel.Error.t()}
```

Emits the forms of a module with a `run/2` function for the given IR.

The generated `run/2` takes the bindings and the run environment and returns the
value of the expression and the environment. Raises `KeyError` without `:module`,
`ArgumentError` for an unknown option or for a node that cannot be emitted yet.

    iex> ir = {:const, %{span: {0, 1}, type: :number}, Decimal.new(1)}
    iex> {:ok, forms} = Feel.Backend.Beam.Emitter.emit(ir, module: Feel.Generated.Doc)
    iex> {:attribute, _, :module, module} = hd(forms)
    iex> module
    Feel.Generated.Doc

---

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