# `ExDatalog.IR`
[🔗](https://github.com/thanos/ex_datalog/blob/v0.5.0/lib/ex_datalog/ir.ex#L1)

Intermediate representation (IR) types for compiled Datalog programs.

The IR is the engine-neutral output of `ExDatalog.Compiler.compile/1`. It
contains the same information as a validated `ExDatalog.Program` but in a
canonical, deterministic form optimized for evaluation:

- Rules are sorted by `(stratum, relation_name, rule_id)`.
- Facts are sorted by `(relation_name, values)`.
- Relations are sorted by name.
- Each rule carries its assigned `stratum` field.
- Every struct has a `serialize/1` function that produces a plain map
  suitable for logging, debugging, or future serialisation.

## IR Type Hierarchy

    IRProgram
      +-- relations:  [IRRelation]
      +-- facts:      [IRFact]
      +-- rules:      [IRRule]
      +-- strata:     [IRStratum]
      +-- metadata:   map()

    IRRelation   — name, arity, types
    IRFact       — relation, values
    IRRule       — id, head (IRAtom), body ([IRLiteral]), stratum, metadata
    IRLiteral    — {:positive, IRAtom} | {:negative, IRAtom} | {:constraint, IRConstraint}
    IRAtom       — relation, terms ([IRTerm])
    IRTerm       — {:var, name} | {:const, IRValue} | :wildcard
    IRConstraint — op, left, right, result
    IRStratum    — index, rule_ids, relations
    IRValue      — {:int, integer} | {:str, String.t} | {:atom, atom}
    IRType       — :integer | :string | :atom | :any

# `ir_callback`

```elixir
@type ir_callback() :: %ExDatalog.IR.Callback{
  args: [ir_term()],
  function: atom(),
  module: module(),
  result: ir_term() | nil
}
```

# `ir_constraint`

```elixir
@type ir_constraint() :: %ExDatalog.IR.Constraint{
  left: ir_term(),
  op: ExDatalog.Constraint.op(),
  result: ir_term() | nil,
  right: ir_term() | nil
}
```

# `ir_literal`

```elixir
@type ir_literal() ::
  {:positive, ExDatalog.IR.Atom.t()}
  | {:negative, ExDatalog.IR.Atom.t()}
  | {:constraint, ir_constraint()}
  | {:callback, ir_callback()}
```

# `ir_term`

```elixir
@type ir_term() :: {:var, String.t()} | {:const, ir_value()} | :wildcard
```

# `ir_type`

```elixir
@type ir_type() :: :integer | :string | :atom | :any
```

# `ir_value`

```elixir
@type ir_value() ::
  {:int, integer()}
  | {:str, String.t()}
  | {:atom, atom()}
  | {:list, [ir_value()]}
```

# `t`

```elixir
@type t() :: %ExDatalog.IR{
  facts: [ExDatalog.IR.Fact.t()],
  metadata: map(),
  relations: [ExDatalog.IR.Relation.t()],
  rules: [ExDatalog.IR.Rule.t()],
  strata: [ExDatalog.IR.Stratum.t()]
}
```

# `__struct__`
*struct* 

The top-level IR program struct.

# `from_atom`

```elixir
@spec from_atom(ExDatalog.Atom.t()) :: ExDatalog.IR.Atom.t()
```

Converts an AST atom to an IR atom.

# `from_callback`

```elixir
@spec from_callback(ExDatalog.Callback.t()) :: ExDatalog.IR.Callback.t()
```

Converts an AST callback to an IR callback.

# `from_constraint`

```elixir
@spec from_constraint(ExDatalog.Constraint.t()) :: ir_constraint()
```

Converts an AST constraint to an IR constraint.

# `from_term`

```elixir
@spec from_term(ExDatalog.Term.t()) :: ir_term()
```

Converts an AST term to an IR term.

## Examples

    iex> ExDatalog.IR.from_term({:var, "X"})
    {:var, "X"}

    iex> ExDatalog.IR.from_term({:const, 42})
    {:const, {:int, 42}}

    iex> ExDatalog.IR.from_term({:const, :alice})
    {:const, {:atom, :alice}}

    iex> ExDatalog.IR.from_term({:const, "hello"})
    {:const, {:str, "hello"}}

    iex> ExDatalog.IR.from_term(:wildcard)
    :wildcard

# `resolve_operand`

```elixir
@spec resolve_operand(ir_term(), map()) :: {:ok, term()} | :unbound
```

Resolves an IR term against a binding environment.

Returns `{:ok, native_value}` if the term is a constant or a bound variable,
or `:unbound` if the term is a variable not present in the binding.

# `serialize`

```elixir
@spec serialize(t()) :: map()
```

Serializes an IR program to a plain map.

The output is deterministic: relations, facts, rules, and strata are
sorted by their canonical order.

# `value_to_native`

```elixir
@spec value_to_native(ir_value()) :: term()
```

Converts a tagged IR value to its native Elixir representation.

- `{:int, n}` → `n`
- `{:str, s}` → `s`
- `{:atom, a}` → `a`
- `{:list, elements}` → `elements` (each element is recursively converted)

---

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