# `Dmn.Compiler`
[🔗](https://github.com/FeeJai/BDM/blob/dmn-v0.1.0/apps/dmn/lib/dmn/compiler.ex#L1)

Compiles a `Dmn.Model` to a `Dmn.Compiled`: a prepared FEEL expression for each element of the decision requirements graph, and the
plan that says what each reads.

Everything that does not depend on the data is done here, once:

  1. **The models.** The models that the first one imports are read through the resolver of the caller (`Dmn.Imports`,
     `Dmn.Resolver`); their elements are elements of the same graph. An element of an imported model is called `Import.Name` by the
     model that imports it, and its types are `Import.tName`.
  2. **The types.** The item definitions of a model, and those of the models it imports under the names of the imports, become a
     `Feel.ItemDefinitions` (`Dmn.Compiler.Types`). The declared type of a variable is FEEL's type, with its allowed values and its
     type constraints. By default recursive item references are errors. With `features: [:recursion]`,
     guarded data cycles retain finite graphs: every cycle must cross a context member or list element,
     and none may cross a function signature. Runtime validation checks complete finite values;
     analysis uses conservative upper bounds (DD-22).
  3. **The graph.** The elements are indexed by their `id` (and the namespace of their model, for those of an import), the
     requirements are resolved to the elements they name, and a cycle is an error (DMN 1.6, 6.3: the requirements are acyclic): the
     elements on it have no logic. Unless the caller asks for `recursion: true` (DD-22): then business knowledge models and decision
     services that read themselves or each other are **recursion groups**, which are compiled as any unit is and run with links to
     one another (`Feel.Recursion`); a cycle that has a decision on it is still an error.
  4. **The units.** Each decision, business knowledge model and decision service has a **scope** (`Feel.Scope`): the input data and
     decisions it requires, each of its declared type and allowed values, and the functions it invokes, each as the function type
     it has. Its boxed expression is mapped to the syntax tree of FEEL (`Dmn.Compiler.Expression`, and `Dmn.Compiler.Table` for
     a decision table), and `Feel.prepare_ast/3` analyzes it, types it with that scope, and compiles it for the backend (the interpreter unless `backend:` says otherwise). The
     declared type of a decision's variable, and its allowed values, are how its result is converted and verified.

A decision is never run here, and nothing is evaluated: a text that cannot be read, a name that is not in scope and a table
with an entry that cannot be satisfied are diagnostics of the element (`Dmn.Diagnostic`), and the model is compiled all the same,
as DMN has an expression that cannot be evaluated give `null` (7.3.8). `Dmn.Compiled.diagnostics` has all of them.

# `compile`

```elixir
@spec compile(Dmn.Model.t(), keyword()) ::
  {:ok, Dmn.Compiled.t()} | {:error, Dmn.Error.t()}
```

Compiles a model.

Options:

  * `:resolver`: how the models that it imports are found (`Dmn.Resolver`). None by default, and then an import is a diagnostic.
  * `:limits`: the `Dmn.Limits` that the imported models are read within.
  * `:feel_limits`: the `Feel.Limits` that the expressions are prepared and run within (`Feel.Limits.default/0` by default). The
    compiled model keeps them (`Dmn.Compiled.feel_limits`), and a run keeps to them unless it is given `:limits` of its own, which
    replace them (`Dmn.Run`).
  * `:check_tables`: whether the decision tables are asked what their types say of them (`Dmn.Compiler.Checks`); `true` by default.
  * `:backend`: what the prepared expressions run on (`Feel.Backend`): `:interpreter` (the default), which generates no code and loads
    nothing into the VM, or `:beam`, which compiles each expression to a module and is faster. The BEAM backend loads modules and
    mints atoms that are never freed, so it is for models that are trusted (DD-41). Both give the same results. With
    `recursion: true` the business knowledge models that have logic, and the decision services, stay on the interpreter, whatever is
    asked, since they can invoke themselves.
  * `:features`: what the caller switches on (`Dmn.Features`, DD-29): `:recursion`, and the extensions (`Dmn.Extension`) by name or
    module. None by default. The two options below are the spellings that came first, and add to it.
  * `:recursion`: whether a business knowledge model or a decision service may invoke itself, and may be invoked by what it
    invokes (DD-22). `false` by default, and then a requirement that goes round in a circle is an error and an element that
    invokes itself by name has a `:recursion_not_enabled` error as well as the unknown-name diagnostic.
    It also enables guarded recursive item definitions, validating complete finite data and constraints.
    Alias-only cycles and cycles through function signatures remain errors. Only the caller can say
    `true`: nothing in a model switches it on. A decision on a requirements cycle is an error either way.
  * `:extensions`: the additions to DMN 1.6 to compile with (`Dmn.Extension`), names or modules. None by default. An extension that
    gives type names (`:dmn_1_1_types`) adds them as item definitions of the model, after its own and those of the models it imports,
    so a type that the model defines has the name.
    An extension that runs external functions (`c:Dmn.Extension.external_functions/0`) has the `functionDefinition` of that kind compiled to
    the external function of FEEL, and the expressions of the model are prepared with the extensions of FEEL it brings.

Returns `{:error, error}` when the graph exceeds `Dmn.Limits.max_units`. Otherwise
`{:ok, compiled}`: what is wrong with the model is in the diagnostics (`Dmn.Compiled.errors/1`), and an error of an element
is also an error of its unit, which a run says and which ends a strict run. `Dmn.validate/1` is the question whether there is any.

---

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