# `Ichor.GrammarImport`
[🔗](https://github.com/joetjen/ichor/blob/v0.3.0/lib/ichor/grammar_import.ex#L1)

Turns an ABNF/BNF/ISO-EBNF/PEG ruleset (as `Ichor.ABNF`/`Ichor.BNF`/
`Ichor.EBNF.ISO`/`Ichor.PEG` produce them -- `%{rule_name_atom =>
Grammar.IR.expr()}`, explicitly documented as "not a runnable
`Aether.Grammar`") into one that actually is: picks a root (the
source's own first-declared rule, unless overridden), assembles a
full `%Aether.Grammar{}`, and (for ABNF specifically) fills in RFC
5234 Appendix B's implicit "core rules" (`ALPHA`, `DIGIT`, `CRLF`,
...) for anything the source references but never defines itself --
extremely common in real ABNF, which generally assumes those are
always available.

`Mix.Tasks.Ichor.Gen`'s own entry point for a grammar whose source
isn't `.aether` text at all; nothing here is native-Aether-specific,
so it's equally usable standalone by anything else that wants a
runnable grammar out of one of these formats.

None of ABNF, ISO EBNF, or PEG (as specified, and as this project's
own importers implement them) have Aether's own named-capture syntax
(`name:expr`) or its `@skip` auto-splicing convenience -- both are
Aether-specific authoring conveniences, not properties of the target
formats -- so every assembled grammar is `@noskip` (whitespace
tolerance has to already be written explicitly into the imported
rules, matching how real ABNF/EBNF/PEG source is actually written),
and an `Ichor.Actions` module written against one only ever sees the
default fallback shape (`Ichor.Node`/passthrough), never a named
capture.

# `style`

```elixir
@type style() :: :abnf | :bnf | :ebnf_iso | :peg
```

# `assemble`

```elixir
@spec assemble(%{required(atom()) =&gt; Grammar.IR.expr()}, atom(), [atom()]) ::
  Aether.Grammar.t()
```

Builds a grammar from `ruleset`, `root` (an atom naming the entry
rule), and `token_names` (the subset of `ruleset` keys that are
lexical/terminal -- everything else becomes a parser rule; `[]` is a
perfectly good default, since every bare `Literal`/`CharClass`/`Any`
leaf inside a designated *rule* still gets auto-promoted into its own
synthetic token below, exactly as `Aether.Parser` already does for
hand-written Aether source -- pre-declaring a name as a token only
matters if you want it to read as one *by that name* in generated
code, not for correctness). `@noskip` always -- see this module's own
moduledoc for why.

# `import_grammar`

```elixir
@spec import_grammar(style(), String.t(), keyword()) ::
  {:ok, Aether.Grammar.t()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}
```

Imports `source` (written in `style`) into a runnable `%Aether.Grammar{}`.

`opts`:

  * `:root` -- the entry rule's name (an atom; matched against the
    ruleset's own key casing -- e.g. `:foo`, never `:"Foo"`). Defaults
    to the first rule `source` itself declares.

Returns `{:error, Ichor.Error.t()}` if `source` fails to parse, if it
declares no rules at all and no `:root` override was given, or if an
explicit `:root` names a rule the ruleset doesn't actually have.

# `styles`

```elixir
@spec styles() :: [style()]
```

The style names `import_grammar/3`/`Mix.Tasks.Ichor.Gen` accept, matched against `--style`/`@style`/a file extension.

---

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