# `Predicator.Conformance.Generator`
[🔗](https://github.com/riddler/predicator-ex/blob/v9.4.1/lib/predicator/conformance/generator.ex#L1)

The pure half of conformance corpus generation (`px-35i.4`).

`generate/1` takes decoded authored cases - already-`JSON.decode/1`-ed maps
from `conformance/cases/*.json` - and runs each through the real compiler
and evaluator, deriving everything the authored case does not spell out:
`instructions` (when a case authors `source`), `expected_result` or
`expected_error`, `tier`, and `features`.

An authored `expected` or `tier` is an **assertion**, not data: if either
disagrees with what the real pipeline computes, generation fails naming the
case and both values, so a sibling author's belief about semantics gets
checked against Elixir's behavior rather than silently overwritten.

Failures accumulate rather than halting on the first one - a contributor
fixing five broken cases should see five errors in one run, not one at a
time.

This module writes nothing to disk and knows nothing about
`conformance/cases/*.json` as files; `mix corpus.generate` (`px-35i.4`
Phase 4) is the thin I/O shell around it.

# `authored_case`

```elixir
@type authored_case() :: %{optional(String.t()) =&gt; term()}
```

An authored case, already JSON-decoded: string keys, JSON-shaped values.

# `case_error`

```elixir
@type case_error() :: %{id: String.t() | nil, problem: String.t()}
```

One per-case generation failure: the case id (`nil` if unknown) and a human-readable problem.

# `completed_case`

```elixir
@type completed_case() :: %{optional(String.t()) =&gt; term()}
```

A completed case: the authored fields plus everything the generator derived.

# `generate`

```elixir
@spec generate(
  [authored_case()],
  keyword()
) ::
  {:ok,
   %{tiers: %{required(pos_integer()) =&gt; [completed_case()]}, manifest: map()}}
  | {:error, [case_error()]}
```

Runs every authored case through the real compiler and evaluator.

Returns `{:ok, %{tiers: %{1 => [case], ...}, manifest: manifest}}` when
every case generates cleanly, or `{:error, [case_error, ...]}` with **every**
failing case's problem, not just the first.

Accepts an options keyword list. The only option is `:retired_opcodes`, a
`MapSet` of opcode names this build's reference evaluator can no longer run
(`docs/isa.md` section 4, "Retired opcodes"). It defaults to the opcodes
present in `Instructions.opcodes/0` but absent from
`Instructions.opcode_set(Instructions.isa_version())` - today that default
is empty, since no opcode carries `:removed_in` yet. A case that uses a
retired opcode is classified in `generate_case/3` and takes a frozen-
expectation path instead of running the pipeline below.

## Examples

    iex> {:ok, result} = Predicator.Conformance.Generator.generate([
    ...>   %{"id" => "core/literal-true", "source" => "true", "expected" => %{"result" => true}}
    ...> ])
    iex> result.tiers[1]
    [
      %{
        "id" => "core/literal-true",
        "source" => "true",
        "instructions" => [["lit", true]],
        "context" => %{},
        "expected_result" => true,
        "tier" => 1,
        "features" => []
      }
    ]

    iex> Predicator.Conformance.Generator.generate([%{"id" => "bad", "source" => "limit >"}])
    {:error, [%{id: "bad", problem: "source \"limit >\" failed to compile: Expected number, string, boolean, date, datetime, identifier, function call, list, object, or '(' but found end of input"}]}

---

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