# `mix ichor.gen`
[🔗](https://github.com/joetjen/ichor/blob/v0.3.0/lib/mix/tasks/ichor.gen.ex#L1)

Runs the exact same parse -> analyze -> native-codegen pipeline as
`use Ichor, grammar: ..., actions: ...` (`Ichor.generate/3`), but once,
from the command line, writing the result to disk as an ordinary
module instead of splicing it into a macro expansion. **This is the
recommended way to use Ichor for anything shipping to production** --
see below for why.

    $ mix ichor.gen calculator.aether \
        --module Calculator \
        --actions Calculator.Actions \
        --out lib/calculator.ex

The point is moving the expensive part -- parsing the grammar, running
`Grammar.Analysis`, building an LR/GLR table if `@engine` calls for
one, and generating Elixir functions from it -- out of the consuming
app's own `mix compile` (where `use Ichor` would otherwise redo all of
that on every compile) and into a one-time step whose output gets
checked in like any other source file.

The generated module still calls a handful of small support modules by
name (`Ichor.Actions`, `Ichor.Error`, `Grammar.Native.Runtime.Parser`,
`Grammar.Native.Runtime.Tokenizer`, `Grammar.VM.Token`, and -- for an
`@engine lr`/`glr` grammar -- the LR/GLR shift-reduce and GSS runtime)
for capture dispatch, error formatting, and token matching, exactly as
`use Ichor`-generated code does -- but as ordinary function calls, not
a macro expansion, so nothing about the generated module needs `Ichor`
(or `ichor` the package at all) present once it's been written. That
handful of modules is exactly what `ichor_runtime` is: a consuming app
can depend on `ichor_runtime` as an ordinary runtime dependency and
mark `ichor` itself `only: :dev, runtime: false` -- the Aether
front-end, the format importers, `Grammar.Analysis`, the LR/GLR table
builder, and the codegen backends themselves (the bulk of the
library) genuinely never ship, including in a `mix release` build.
Contrast with `use Ichor`: because that macro needs the real `Ichor`
module loaded to expand, `ichor` has to be a real dependency in
whatever environment compiles it, and Mix simply won't load a
`only: :dev` dependency under `MIX_ENV=prod` -- so a `mix release`
build (which compiles under `:prod` by default) fails outright if any
module still says `use Ichor` and `ichor` was marked dev-only. This
task exists precisely to avoid that tradeoff.

Every private helper function the codegen backend generates
(tokenizer/rule sub-functions, LR/GLR dispatch clauses, ...) is
emitted as `def`, not `defp`: through `use Ichor`, these come from
macro expansion, which Elixir's compiler doesn't flag for being
unused even when a particular grammar's shape leaves some unreferenced
(e.g. a predefined token like `HEX` no rule actually uses); written
out as ordinary source, the same functions would trip
`--warnings-as-errors` on an unrelated grammar-shape detail.

Regenerate by rerunning the same command whenever the grammar changes
-- there's no automatic staleness check between the checked-in file
and its source grammar.

## Grammar styles: Aether, ABNF, BNF, ISO EBNF, PEG

`PATH_TO_GRAMMAR` doesn't have to be `.aether` source -- ABNF, BNF,
ISO EBNF, and PEG grammars work too, via `Ichor.GrammarImport`. The
style is picked automatically from the file extension:

| Extension | Style |
|---|---|
| `.aether` (or anything unrecognized) | Aether (default) |
| `.abnf` | ABNF (RFC 5234 + RFC 7405) |
| `.bnf` | Classical BNF |
| `.ebnf` | ISO EBNF (ISO/IEC 14977) |
| `.peg` | PEG (Ford/pest/PEG.js convention) |

Override the detected style with an `@style` line anywhere in the
source (`@style abnf`, `@style bnf`, `@style ebnf`, `@style peg`, or
`@style aether`) -- it's stripped before the source reaches whichever
parser actually runs, so it doesn't need to be valid syntax in the
target format at all.

None of ABNF, BNF, ISO EBNF, or PEG have Aether's own `@root`
pragma, named-capture syntax (`name:expr`), or `@skip` auto-splicing
convenience. For a non-Aether style:

  * The **root** is the source's own first-declared rule, unless
    overridden with `--root NAME`.
  * The grammar is always `@noskip` -- whitespace tolerance has to
    already be written explicitly into the source, matching how real
    ABNF/BNF/EBNF/PEG grammars are actually written.
  * An `Ichor.Actions` module written against the generated parser
    only ever sees the default fallback shape (`Ichor.Node`/single-
    capture passthrough) -- never a named capture, since the source
    format has no syntax for one.
  * For ABNF specifically, RFC 5234 Appendix B's own "core rules"
    (`ALPHA`, `DIGIT`, `CRLF`, ...) are filled in automatically for
    whichever of them the source references but never defines itself
    -- extremely common in real ABNF, which generally assumes those
    are always available. See `Ichor.GrammarImport`'s own moduledoc
    for the one sharp edge this can't fully paper over (two
    genuinely-overlapping core rules both referenced by the same
    source).

## Options

  * `--module` (required) -- the generated module's name, e.g.
    `MyApp.Calculator`.
  * `--actions` (required) -- the `Ichor.Actions` module the generated
    `run/1,2` dispatches to, e.g. `MyApp.Calculator.Actions`. Not
    required to exist yet -- it's baked in as a literal module
    reference, resolved when the generated file's own callers run, not
    when it's generated.
  * `--out` (required) -- path to write the generated module to.
  * `--root` (optional, non-Aether styles only) -- the entry rule's
    name, overriding the source's own first-declared rule.

---

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