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

The context functions of FEEL (DMN 1.6, section 10.3.4.10, Table 82): `get value`, `get entries`,
`context`, `context put` and `context merge`.

## What is written (D-79)

| Call | Result |
| ---- | ------ |
| `get value(m, key)` | the value of the entry `key` of the context `m`; `null` if there is none |
| `get entries(m)` | a list of contexts `{key: ..., value: ...}`, one for each entry |
| `context(entries)` | the context of a list of such contexts |
| `context put(context, key, value)` | the context with the entry `key` set to `value`, added or replaced |
| `context put(context, keys, value)` | the same at the end of a path of keys, through the contexts in between |
| `context merge(contexts)` | the entries of all the contexts of the list; a later one wins for a key |

The result of a function is a new context: the one that was given is not changed.

**An entry that is not there** is `null` for `get value`, as the second example of the table has it,
and it is no error. A path (`m.key`) with a key the context does not have is an error (TCK, 0057 #009), and
`get value` is the one that is not: its example says `null`, and the TCK has no case for it.

**`context(entries)`** takes a list of contexts that have a `key`, a string, and a `value`, which can be
`null`; other entries of an item are left out. An item without a `key` or without a `value`, a `key` that is
`null` or not a string, an item that is no context, and two items with one key, make the whole result `null`
with an error: the first three are what the table says, and the last is what the TCK has (1145 #003)
where the notes (A16) thought of the later item winning. A context in place of the list is the list of
it (section 10.3.2.9.4), so `context({key: "a", value: 1})` is `{a: 1}`.

**`context put` with keys** puts the value at the end of the path, `context put({x: 1, y: {a: 0}}, ["y", "a"], 2)`
being `{x: 1, y: {a: 2}}`. Every key but the last has to be an entry that is a context: where it is not
there, or is a value of another kind, the result is `null` with an error (TCK 1146, #nested009; the
table is silent, A18), and it makes no contexts of its own. A path with no key, or with a key that is
`null` or not a string, is out of the domain as well.

**`context merge`** does not look into the contexts: the entry of the later context is the entry, so
`context merge([{a: {b: 1}}, {a: {c: 2}}])` is `{a: {c: 2}}` (TCK 1147 #004).

## The order of the entries (D-135)

A context keeps the order of its entries (`Feel.Value.Context`), and these are the functions that show it:

  * `get entries` has the entries in the order they have;
  * `context(entries)` has the order of the list;
  * `context put` puts a new entry last, and an entry that is put again stays where it was (`context put({x: 1, y: 2}, "x", 3)`
    is `{x: 3, y: 2}`);
  * `context merge` keeps the entries of the first context where they are and adds the new ones of the next after them, in
    their order: `context merge([{x: 1, y: 0}, {z: 3, y: 2}])` is `{x: 1, y: 2, z: 3}`.

The specification's examples are all in this order, and the TCK has no case that tells it from the order of the keys
(D-135), so what it says is kept either way. A context that a host binds as a plain map has the
order of its keys.

## What a call by name cannot tell

`context put(context, key, value)` and `context put(context, keys, value)` are two signatures that differ in
the type of the second parameter, and the function is given the values and not the signature that a call by
name chose. So a call with a list for `key:` would be a call with `keys:`, where the TCK has `null` for it
(1146 #nested008). It is not, since D-56: the analyzer has the signature that the names chose and the type of
the argument, and a list of two for a string is a mismatch that makes the call `null` with its error
(`Feel.Analysis.Calls.mismatch/3`); and a call by name carries that signature to the run, which checks the
values against it (`Feel.Builtin.call/4`), so a list that is bound to a name when the run begins is the same.

A null argument, and one of another kind, is out of the domain: the result is `null` with an
`:argument_out_of_domain` error. A list of one context is that context, for a context parameter.

# `functions`

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

The functions of this module that are written, as `Feel.Builtin.Function`s: all five.

    iex> length(Feel.Builtin.Context.functions())
    5

# `names`

```elixir
@spec names() :: [Feel.Name.t()]
```

Returns the canonical names of the functions of this module, sorted.

    iex> "get value" in Feel.Builtin.Context.names()
    true

---

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