Flattens grammar.rules' PEG-shaped IR into the flat CFG production
list Grammar.LRTable.Production describes, for Grammar.LRTable's
LR(0)/SLR(1) construction to consume.
The one representational mismatch this exists to bridge: a CFG
production's right-hand side is a flat sequence of single symbols,
while PEG's IR is a tree (Seq/Choice/Star/Plus/Opt/Rep can
all nest arbitrarily). Only a RuleRef (a reference to an actual
declared token or rule) is already a single symbol; everything else
gets a fresh compiler-generated helper nonterminal ($star_1,
$opt_2, ...) standing in for it -- an artifact of the CFG
representation that doesn't exist in the original grammar at all.
:splice-kind captures (see Grammar.LRTable.Production) are what
erase that artifact again at reduce time: a helper nonterminal's own
already-built captures map gets merged directly into its parent's,
so the final raw-capture tree looks exactly like what
Grammar.VM/Grammar.Native would have built for the same grammar --
the boundary a helper nonterminal introduces is purely structural
(needed so the LR table has single symbols to work with), never
semantic.
Reuses the exact same token/rule classification and implicit-capture
exclusion rules every other backend uses (Grammar.VM.RuleCompiler's
own token_names/1/implicit_capture_exclusions/1) so a
@keywords/@refine target name, an anonymous auto-promoted literal
token, or the grammar's own spliced @skip token are all treated
identically here -- in particular, a spliced @skip token (already an
ordinary, uncaptured Star[RuleRef(skip)] node in the IR by the time
this runs -- see Aether.Eval's own splice_skip/2) needs no special
handling at all: it desugars into an ordinary :splice-kind helper
nonterminal whose own body has no capture entries, so splicing its
empty map into the parent is simply a no-op.
Summary
Functions
The synthetic end-of-input terminal appended by Grammar.LRTable's automaton construction.
Desugars grammar.rules (plus a fresh $start := root production) into
a flat production list, or every unsupported-construct error found.
The augmented start nonterminal every desugared grammar's automaton is built from.
Functions
@spec end_symbol() :: atom()
The synthetic end-of-input terminal appended by Grammar.LRTable's automaton construction.
@spec run(Aether.Grammar.t()) :: {:ok, [Grammar.LRTable.Production.t()]} | {:error, [Ichor.Error.t()]}
Desugars grammar.rules (plus a fresh $start := root production) into
a flat production list, or every unsupported-construct error found.
@spec start_symbol() :: atom()
The augmented start nonterminal every desugared grammar's automaton is built from.