# `Feel.Runtime.Invoke`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/runtime/invoke.ex#L1)

Function values, and the call of one (DMN 1.6, section 10.3.2.13, Table 64; D-82).

A function is a `Feel.Value.Function` of one of three kinds, and a call runs any of them the same
way: `call/4` takes the value of the callee, the values of the arguments, and the span of the call.

  * `:feel`, a closure. `closure/3` builds it from the parameters, the type of the result, and a
    function of the environment and the values of the arguments that evaluates the body in the scope
    the function was written in. Both backends build it: the interpreter from a function that walks the
    body, and the generated code from a fun of its own.
  * `:native`, a function of the host (`Feel.Value.Function.native/2`). Its arguments are converted to
    the boundary types it was built with, and its result back.
  * `:builtin`, a built-in function, which a name stands for where nothing else has it (`builtin/2`, D-82). A call
    finds the function by its name and calls it as the call of the built-in does, by position or by name: the
    function takes the arguments as they are, and does not convert them to the types of its parameters. The one
    that a declared function type was given in place of a built-in with a signature for each kind (`abs` for a
    `function<number> -> number`, D-197) is the exception: it has the one signature, and takes the arguments as a
    function of FEEL with those parameters does, as below.

## The arguments

A call has its arguments by position, `{:positional, values}`, or by name, `{:named, pairs}`. By
position they are all supplied (Table 64): a number that is not the arity of the function is `null`
with an `:arity_mismatch` error. By name, the names have to be parameters of the function, and the ones
a call leaves out are `null`. An argument is then converted to the declared type of its parameter by
the implicit conversions of section 10.3.2.9.4 (`Feel.Type.Conversion`, reported as an `:info`, as
D-46 has them), and one that cannot be made to conform makes the whole call `null` with a
`:type_mismatch` error (Table 64: "the result of the invocation is null"). `null` conforms to every
type, and a parameter without a declared type is `Any`.

## What is not a function

The callee of a call that is not a function value, `null` included, gives `null` with a
`:not_a_function` error (section 10.3.2.13.2).

## Depth

A call is one level deeper than the call it is made in, and `Feel.Limits` has `max_call_depth`: a run
that passes it ends in either mode, with an error of kind `:limit`. A function can call itself only by
being passed to itself (a context entry cannot refer to its own key, D-58), and
`{f: function(g) g(g), r: f(f)}.r` would otherwise not end.

## The number of calls

The depth does not bound how many calls a run makes (a function that calls itself twice at each level makes about
2ⁿ at a depth of `n`), so every call of a function of FEEL is counted too, and a run that passes `max_calls` ends
the same way (D-154). The calls that `sort` and `list replace` make of the function they are given are counted, as
their outcome carries the environment. A call of a built-in or of a host function runs no expression and is not
counted; a loop of them is bounded by `max_iterations`.

# `arguments`

```elixir
@type arguments() ::
  {:positional, [Feel.Value.t()]} | {:named, [{Feel.Name.t(), Feel.Value.t()}]}
```

The values of the arguments of a call: in the order of the parameters, or with the names they were given.

# `body`

```elixir
@type body() :: (Feel.Runtime.Env.t(), [Feel.Value.t()] -&gt;
             {Feel.Value.t(), Feel.Runtime.Env.t()})
```

What a closure runs: the environment and the values of the arguments, one for each parameter.

# `builtin`

```elixir
@spec builtin(Feel.Runtime.Env.t(), Feel.Name.t()) :: Feel.Value.Function.t()
```

The built-in function of this name as a value (D-82), with the signatures that the extensions of the run give it.
The analyzer has seen that there is one.

    iex> env = Feel.Runtime.Env.new()
    iex> function = Feel.Runtime.Invoke.builtin(env, "abs")
    iex> {value, _env} = Feel.Runtime.Invoke.call(env, function, {:positional, [Decimal.new(-3)]}, {0, 3})
    iex> Decimal.equal?(value, 3)
    true

# `call`

```elixir
@spec call(
  Feel.Runtime.Env.t(),
  Feel.Value.t(),
  arguments(),
  Feel.Diagnostic.span() | nil
) ::
  {Feel.Value.t(), Feel.Runtime.Env.t()}
```

Calls the value of a callee on the values of the arguments, and settles the outcome at `span`.

    iex> env = Feel.Runtime.Env.new()
    iex> double = Feel.Runtime.Invoke.closure([{"a", :number}], :number, fn env, [a] ->
    ...>   {:ok, twice} = Feel.Runtime.Arithmetic.multiply(a, Decimal.new(2))
    ...>   {twice, env}
    ...> end)
    iex> {value, _env} = Feel.Runtime.Invoke.call(env, double, {:positional, [Decimal.new(4)]}, {0, 4})
    iex> Decimal.equal?(value, 8)
    true
    iex> {nil, env} = Feel.Runtime.Invoke.call(env, Decimal.new(1), {:positional, []}, {0, 3})
    iex> Enum.map(Feel.Runtime.Env.diagnostics(env), & &1.code)
    [:not_a_function]

# `closure`

```elixir
@spec closure([{Feel.Name.t(), Feel.Type.t()}], Feel.Type.t(), body()) ::
  Feel.Value.Function.t()
```

Builds the value of `function(...) body`: a closure with these parameters (names and declared types,
`:any` for a parameter without one), the type of what its body gives, and the function that runs the
body.

    iex> impl = fn env, [a] -> {a, env} end
    iex> function = Feel.Runtime.Invoke.closure([{"a", :number}], :number, impl)
    iex> {function.kind, Feel.Value.Function.type(function)}
    {:feel, {:function, [:number], :number}}

# `closure`

```elixir
@spec closure(
  [{Feel.Name.t(), Feel.Type.t()}],
  Feel.Type.t(),
  body(),
  Feel.Runtime.Env.t()
) ::
  Feel.Value.Function.t()
```

Builds the value of `function(...) body` written in the text that `env` is running (D-201): the closure of `closure/3`,
with the origin of `env` as its own. A call runs its body under that origin, whatever origin the text that calls it has,
so the diagnostics of the body say whose text their spans are in. Only the origin is kept of `env`, so the function
holds nothing of the run that made it.

    iex> impl = fn env, [a] -> {a, env} end
    iex> env = Feel.Runtime.Env.new(origin: :decision)
    iex> function = Feel.Runtime.Invoke.closure([{"a", :number}], :number, impl, env)
    iex> function.origin
    {:origin, :decision}

---

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