Grammar.LR (Ichor v0.2.0)

Copy Markdown View Source

The deterministic bottom-up backend: builds an SLR(1) table via Grammar.LRTable and requires it be conflict-free -- a real conflict is a compile-time error here (compile/1), never something forked through (that's what Grammar.GLR is for). No graph-structured-stack bookkeeping at all: an ordinary shift-reduce loop over a single stack.

Only ever runs @engine lr grammars -- same reasoning Grammar.VM/ Grammar.Native reject anything but @engine peg: the tag is a grammar author's own declared choice of backend, and running a grammar through the wrong one is a bug worth catching immediately rather than silently doing something unintended.

Builds the exact same raw-capture shape Ichor.Actions expects ({:token,...}/{:rule,...}/{:text,...}) at every reduce, using Grammar.LRTable.Production.t()'s own captures plan -- see its moduledoc for what each capture kind means. Reuses Grammar.VM.RuleCompiler.capture_shapes/1 unchanged (a pure static pass over grammar.rules' IR, unaffected by how a table-driven engine parses it) so Ichor.Actions.evaluate/5 needs no changes at all to work with this backend.

Summary

Functions

Builds grammar's SLR(1) table and requires it be conflict-free, or reports every conflict found.

Matches input against grammar's root, requiring the entire (tokenized) input to be consumed. A bare recognizer -- no Ichor.Actions involved.

Like parse/3, but runs the match through actions_module starting from initial_context, returning the grammar's actual evaluated result.

Types

t()

@type t() :: %Grammar.LR{
  capture_shapes: Ichor.Actions.capture_shapes(),
  table: Grammar.LRTable.t()
}

Functions

compile(grammar)

@spec compile(Aether.Grammar.t()) :: {:ok, t()} | {:error, [Ichor.Error.t()]}

Builds grammar's SLR(1) table and requires it be conflict-free, or reports every conflict found.

parse(grammar, input, context \\ nil)

@spec parse(Aether.Grammar.t(), String.t(), term()) ::
  {:ok, non_neg_integer()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}

Matches input against grammar's root, requiring the entire (tokenized) input to be consumed. A bare recognizer -- no Ichor.Actions involved.

run(grammar, input, actions_module, initial_context \\ nil)

@spec run(Aether.Grammar.t(), String.t(), module(), Ichor.Actions.context()) ::
  {:ok, term()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}

Like parse/3, but runs the match through actions_module starting from initial_context, returning the grammar's actual evaluated result.