Turns a parsed PEG grammar_file (Ford's paper, pest/PEG.js-style
convention) into a real %{ident_atom => Grammar.IR.expr()} map --
one Grammar.IR tree per rule, the same target category every other
importer this project builds uses.
PEG's own operators (&, !, ?, *, +, /, ., [...]) are
close to identical in spelling and meaning to Aether's own, so most of
this module is a thin wrapper. primary's (IDENT !ARROW) is real
disambiguation, not a formality: without the negative lookahead, a
bare identifier reference inside one rule's expression would be
ambiguous with the start of the next rule's own definition. It works
because !ARROW is a parser-level predicate checked at every
candidate identifier, unlike the lexer-level maximal munch that
causes the equivalent ambiguity in Ichor.BNF/Ichor.EBNF.W3C (both
need an explicit newline between rules for exactly this reason; PEG
doesn't).
Rule names are kept exactly as written, case-sensitively, matching ordinary identifier conventions (no RFC 5234-style case-insensitivity rule applies here).
[^...] negates a character class the same way regex's own does:
Seq([NotPred(class), Any]).