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

A set of additions to FEEL that a caller switches on when it prepares an expression (D-81).

DMN 1.6 defines FEEL, and the engines that run it add to it: functions that DMN does not have, more
signatures for the ones it has, other spellings of a date. An extension is a module that says what it
adds, and the core asks the extensions that are on, at the few places where it decides. Nothing in the
core names an extension.

    Feel.prepare("shout(name)", extensions: [MyApp.Shout])

The option takes modules that implement this behaviour, and names (`registry/0`) that stand for one or
more of them. It is `[]` by default, and then the library is DMN 1.6 and nothing else. The extensions go
with the prepared expression into every run of it, as the dialect does (D-49), and a run cannot choose
other ones.

## What an extension can do

An extension **adds**: it never changes the result of an expression that is valid without it. What it
adds was an error before (an unknown function, a call with a number of arguments that no signature
takes, a string that is not a date), or was not FEEL at all. This is what makes it safe to switch on, and
`apps/bdm_tck/scripts/tck.exs --extensions` checks it: with an extension on, every result of the TCK that was
right stays right. The TCK pins a few errors, though (`number("1.000.000,01", ".")` is "an error when too few params", 0058
#016), and an extension that accepts such a call deviates from it on purpose: it names the nodes, and any other
that stops passing is a bug of the extension (D-81).

| Callback | Adds |
| -------- | ---- |
| `c:functions/0` | functions with names that DMN 1.6 does not have. A name of several words is read as one name wherever the extension is on, as `string length` is |
| `c:overloads/0` | signatures for a function that DMN 1.6 has (`Feel.Builtin.Function.with_overloads/2`) |
| `c:temporal_text/1` | other spellings of the text of a time or a date and time, which `time(...)`, `date and time(...)` and `@"..."` then read as DMN 1.6 writes them, and report |

The first two are lists of `Feel.Builtin.Function`s, with parameters, types and a `call`, like the built-in
functions (D-56), and are called in the same way. The third is the spelling of a text, and is reported when it
is used (D-81). Syntax is not an extension: names in backticks are read always, and reported (D-83).

`c:data_only?/0` is not an addition but a declaration (D-222): an extension that never returns a function and makes no
diagnostic with an `:origin` can say so, and a host that copies a run into a worker then need not copy the source of the
elements the run does not use. An extension that does not declare it is taken to be able to return a function written
elsewhere.

## An overload is the second choice

The function of DMN 1.6 runs first. Only when it reports an error does an overload get its turn, in the
order of the extensions, and its `call` may return `:next` to say that the arguments are not for it. If
every overload does, the error of the function of DMN 1.6 is the result, as it is with the extensions
off. A function of DMN 1.6 that gives `null` because an argument is `null` (`:missing`) is not asked
about again: that is a result and not an error.

## A module

    defmodule MyApp.Shout do
      @behaviour Feel.Extension
      alias Feel.Builtin.Function

      @impl true
      def name, do: :shout

      @impl true
      def functions do
        [
          %Function{
            name: "shout",
            signatures: [Function.signature([Function.parameter("text", [:string])], [:string])],
            call: fn _env, [text] -> {:ok, String.upcase(text) <> "!"} end
          }
        ]
      end
    end

# `data_only?`
*optional* 

```elixir
@callback data_only?() :: boolean()
```

Whether the extension adds data only: what it returns is a value that is not a function (and has none inside), and a
diagnostic it makes has no `:origin` (`Feel.Diagnostic`), so it never brings a text of another expression into a run.
A host that copies a run into a worker (`Dmn.Execution`) then need not copy the sources of the elements the run does not
use. An extension that does not say so, or says `false`, is taken to be able to (a function that returns a function
written elsewhere, with its origin, is one). Wrong `true` loses the element in the diagnostics of such a function in a
worker; it does not change a value. It is called once, when the set of extensions is prepared (`Feel.Extensions.new/1`),
inside the protected preparation, and its answer is recorded; keep it a constant. A callback that raises counts as `false`.

# `functions`
*optional* 

```elixir
@callback functions() :: [Feel.Builtin.Function.t()]
```

The functions that the extension adds. Their names are not among those of DMN 1.6 (a function of DMN 1.6
gets more signatures with `c:overloads/0`), and no other extension that is on defines them.

# `name`

```elixir
@callback name() :: atom()
```

The name of the extension, for the messages about it.

# `overloads`
*optional* 

```elixir
@callback overloads() :: [Feel.Builtin.Function.t()]
```

More signatures for functions of DMN 1.6, each as a `Feel.Builtin.Function` of the name of the function.
The `call` of an overload gets the arguments of a call that one of its signatures accepts, and returns an
outcome or `:next`.

# `temporal_text`
*optional* 

```elixir
@callback temporal_text(String.t()) :: [String.t()]
```

Other spellings of `text`, which a function or a literal could not read, as DMN 1.6 writes them, best first
(`Feel.Value.Temporal.Spellings`): none if the extension does not know the text. The library reads the first that
the function or the literal reads, and reports the spelling as an `:info` with the code `:temporal_spelling`;
if there is none that it reads, the error is the one it gave.

# `registry`

```elixir
@spec registry() :: %{optional(atom()) =&gt; [module()]}
```

The extensions that `extensions:` knows by name, each with the modules it stands for.

Any module that implements the behaviour can be given as well, so a name is only a convenience.

---

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