# `Ichor.EBNF.ISO.Actions`
[🔗](https://github.com/joetjen/ichor/blob/v0.3.0/lib/ichor/ebnf/iso_actions.ex#L1)

Turns a parsed ISO/IEC 14977 EBNF `syntax` into a real
`%{meta_identifier_atom => Grammar.IR.expr()}` map -- one `Grammar.IR`
tree per rule, the same target category `Ichor.ABNF.Actions` and
`Ichor.BNF.Actions` both use.

Meta-identifier names are kept exactly as written (leading/trailing
whitespace trimmed off the token's own greedy trailing-space capture
-- ISO EBNF's `IDENT` allows an embedded literal space, but internal
spacing, e.g. `syntax rule`, is preserved, since ISO EBNF really does
allow multi-word identifiers). No case-insensitivity rule the way
ABNF's RFC 5234 has one.

An empty alternative (`x = 'a' | ;`) is expressed as `single_definition`
matching zero-width via a rule-level `Opt` around its own body, not a
token -- Aether's own lexer never treats a zero-length match as "the
next token" (needed so tokenization itself can't stall forever on an
always-matches-empty token), so a token-based encoding of "empty"
referenced from a rule could never actually match, at any position.

**The exception operator (`-`) is a best-effort, not a full
language-theoretic set difference.** ISO EBNF's `factor - exception`
means "every string `factor` generates that `exception` doesn't
generate" -- true set subtraction, which `Grammar.IR` has no
combinator for (`NotPred` is PEG lookahead at the *current* parse
position, not "matches `factor`'s language minus `exception`'s").
This translates it as `Seq([NotPred(exception), factor])`: reject
first if `exception` would also match here, then require `factor` --
correct when the excluded language is a lookahead-distinguishable
prefix of the included one (e.g. `digit - '0'`, a factor that's a
plain alternation of single characters and an exception that's one of
them), but not a claim of full correctness for arbitrary
`factor`/`exception` pairs in general.

`special_sequence` (`? ... ?`, ISO's own escape hatch for
implementation-defined extensions the formal grammar doesn't cover)
has no executable meaning, so it's rejected the same deliberate way
ABNF's `prose_val` and regex's backreferences/named-groups/anchors
are: `Ichor.Error`, not silently ignored.

---

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