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

Which of some names an expression reads, found in its syntax tree.

The entries of a context literal can refer to each other, in any order, and an entry has to be
evaluated after the ones it refers to (DMN 1.6, section 10.3.2.6; D-58). So the analyzer has to know what
each entry reads before it analyzes any of them, and it cannot learn that by analyzing them, for an
entry's type needs the types of the entries it reads. This module reads it off the tree, in one walk
that is linear in the size of the entry (`to/2`), or for all the context literals of an expression
in one walk of it (`of_contexts/1`).

A read is a name node whose canonical form (`Feel.Name`) is one of the names asked about, unless the
expression binds the name itself where it is read:

  * the keys of a context literal inside the expression are bound in all of its entries,
  * the variables of a `for` (and `partial`), `some` and `every` are bound in the part they scope: in the body, and in the
    domains after them (D-86),
  * the parameters of a function are bound in its body, and
  * `item` is bound in a filter's predicate.

A name that is a key of the inner context is not a read of an outer entry of the same key, as
in `{x: {x: 1, y: x}.y}`. Where the walk cannot be sure it counts a read: a name in a filter's
predicate may be a key of the elements and not a name in scope (A4-08). Missing a read would evaluate an
entry before one it needs, while counting one that is not only makes the order more careful.

    iex> {:ok, ast} = Feel.parse("{a: 1, b: a + 1, c: {a: 2, d: a}.d + b}")
    iex> {:context, _meta, entries} = ast
    iex> names = MapSet.new(["a", "b", "c"])
    iex> for {key, value} <- entries, do: {Feel.Analysis.References.key(key), Feel.Analysis.References.to(value, names) |> Enum.sort()}
    [{"a", []}, {"b", ["a"]}, {"c", ["b"]}]

# `literal_reads`

```elixir
@type literal_reads() ::
  {[{Feel.AST.key(), Feel.AST.t()}],
   %{required(non_neg_integer()) =&gt; MapSet.t(Feel.Name.t())}}
```

What the entries of one context literal read of its keys: the entries of the literal, and for each entry that reads any
the keys, by the position of the entry.

# `key`

```elixir
@spec key(Feel.AST.key()) :: String.t()
```

Returns the key of a context entry.

A key that is a name is its canonical form. A key that is a string is the string, in the canonical form
of a name when it is one (D-05): `"first  name"` and `first name` are the same key. Any other string is the key
as it is written (D-213), and it is decided by `Feel.Syntax.Lexer.name_tokens/1`, as the parser decides which
names an entry binds.

    iex> Feel.Analysis.References.key({:name, ["first", "name"]})
    "first name"
    iex> Feel.Analysis.References.key({:string, "first   name"})
    "first name"
    iex> Feel.Analysis.References.key({:string, "first   name!"})
    "first   name!"
    iex> Feel.Analysis.References.key({:string, ""})
    ""

# `of_contexts`

```elixir
@spec of_contexts(Feel.AST.t()) :: %{
  required(Feel.Diagnostic.span()) =&gt; literal_reads()
}
```

Returns, for every context literal in the expression, by its span, what `to/2` gives for each of its entries and the
keys of the literal: the keys that the entry reads.

The analyzer asks it for the literals one inside another, and `to/2` for each walks everything below the literal, so
the nodes of the innermost one are walked once for each level around them. This is one walk of the tree: a name read
is for the innermost construct that binds it, and it counts if that is a context literal, for the entry that it is in.

    iex> {:ok, ast} = Feel.parse("{a: 1, b: {a: 2, c: a + b}, d: a}")
    iex> {:context, %{span: span}, _entries} = ast
    iex> {_entries, reads} = Feel.Analysis.References.of_contexts(ast)[span]
    iex> reads |> Enum.map(fn {index, names} -> {index, Enum.sort(names)} end) |> Enum.sort()
    [{1, ["b"]}, {2, ["a"]}]

# `to`

```elixir
@spec to(Feel.AST.t(), MapSet.t(Feel.Name.t())) :: MapSet.t(Feel.Name.t())
```

Returns the names, of those given, that the expression reads.

---

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