Grammar.LRTable.Desugar (Ichor v0.2.0)

Copy Markdown View Source

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

end_symbol()

@spec end_symbol() :: atom()

The synthetic end-of-input terminal appended by Grammar.LRTable's automaton construction.

run(grammar)

@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.

start_symbol()

@spec start_symbol() :: atom()

The augmented start nonterminal every desugared grammar's automaton is built from.