# `Grammar.LR.Lossless`
[🔗](https://github.com/joetjen/ichor_runtime/blob/v0.6.0/lib/grammar/lr/lossless.ex#L1)

The LR shift-reduce loop for a lossless parse: the same moves as
`Grammar.LR`'s and `Grammar.Native.LR`'s, building captures with
`Ichor.Syntax.Record.reduced/3`, so the rules' records travel with them.

**Table-driven on purpose, for both backends.** The generated LR parser
compiles every state into its own function, which calls the ordinary
`Grammar.LR.Stack.reduce/4` inline. A lossless variant of those would
be a second copy of every state function. Instead, a parser generated
with `lossless: true` embeds its table as data and hands it to this
loop through `action_fn`/`goto_fn` -- the shape `Grammar.GLR.Runtime`
already takes -- so the fast path's functions stay exactly as they
are, and the lossless path pays for lookups rather than for code.

# `run`

```elixir
@spec run(
  (Grammar.LRTable.state_id(), atom() -&gt; [Grammar.LRTable.action()]),
  (Grammar.LRTable.state_id(), atom() -&gt; Grammar.LRTable.state_id() | nil),
  %{required(non_neg_integer()) =&gt; Grammar.LRTable.Production.t()},
  Grammar.LRTable.state_id(),
  atom(),
  tuple()
) ::
  {:ok, non_neg_integer(), Ichor.Capture.raw_captures()}
  | {:error, Ichor.Error.t()}
```

Runs the loop over `stream` from `start_state`. `action_fn` answers a
state and a lookahead with the table's list of actions -- one, since an
LR table has no conflicts -- and `goto_fn` a state and a nonterminal
with the state to go to.

---

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