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

The linear LR stack's shift/reduce mechanics -- shared by the
interpreted `Grammar.LR` and `Grammar.Native.LR`'s per-state
generated code, since a stack push/pop is exactly the same operation
regardless of whether the state driving it came from a `Map.get` or a
compiled `case`.

A stack entry is `{state, start_pos, end_pos, value}`: `state` is
needed after a reduce to know which `GOTO` to consult -- the state a
pop exposes isn't knowable until then, even when *which* production
reduced is already compile-time-known (the same production can be
reduced from more than one calling context, exposing a different
state each time). `start_pos`/`end_pos` are token-stream indices,
needed for a `:text`-kind capture's span regardless of which RHS
position it sits at (`Grammar.LRTable.Captures`). `value` is the
shifted `%Grammar.VM.Token{}` itself, or a reduced nonterminal's own
already-built raw-captures list.

# `entry`

```elixir
@type entry() :: {state :: term(), non_neg_integer(), non_neg_integer(), term()}
```

# `push_reduced`

```elixir
@spec push_reduced(
  [entry()],
  term(),
  non_neg_integer(),
  non_neg_integer(),
  Ichor.Capture.raw_captures()
) :: [entry()]
```

Pushes a reduced nonterminal's captures onto `rest_stack` (as returned by `reduce/4`), landing in `target_state`.

# `push_token`

```elixir
@spec push_token(
  [entry()],
  term(),
  Grammar.VM.Token.t(),
  non_neg_integer(),
  non_neg_integer()
) :: [
  entry()
]
```

Pushes a freshly-shifted token onto `stack`, landing in `state`.

# `reduce`

```elixir
@spec reduce([entry()], Grammar.LRTable.Production.t(), tuple(), non_neg_integer()) ::
  {term(), [entry()], non_neg_integer(), non_neg_integer(),
   Ichor.Capture.raw_captures()}
```

Pops `production`'s own RHS length off `stack`, builds its captures
via `Grammar.LRTable.Captures.build/3`, and returns `{exposed_state,
rest_stack, start_pos, end_pos, captures}` -- `exposed_state` is
whatever's now on top (the caller's own job to look up `GOTO` for),
`start_pos`/`end_pos` the span the whole reduced production covers
(both `pos`, for a zero-width/epsilon production).

---

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