# `Grammar.Furthest`
[🔗](https://github.com/joetjen/ichor_runtime/blob/v0.6.2/lib/grammar/furthest.ex#L1)

Where a PEG parse went wrong: the furthest token any alternative
reached, and every token that would have been accepted there.

**A failed PEG parse says only that the root did not match** -- an
ordered choice backtracks out of every alternative, and by the time
the root gives up, where each one failed is gone. The usual answer,
and this one, is to remember while matching: each token match that
fails reports its position and the token it wanted (`failed/2`), and
the furthest position wins. That is where the input went wrong, and
what was wanted there is what to tell the user.

**Per process, in the process dictionary.** A generated parser's
matchers are pure functions of the stream and a position, and
threading a record through every one of them would change every
generated file; a parse runs in one process from start to finish. A
parse brackets itself with `start/0` and `finish/1`, which save and
restore whatever was there, so a parse nested inside another -- a
custom lexeme re-lexing a suffix -- leaves the outer record as it was.

**Not inside a lookahead.** `!X` failing to match `X` is what lets a
parse go on, and `&X` is a question, not a consumption: a matcher
brackets a predicate with `enter_predicate/0` and `exit_predicate/0`,
and failures between them are not expectations.

# `record`

```elixir
@type record() :: {integer(), MapSet.t(atom())}
```

The furthest token index a match failed at (-1 for none yet), and the tokens wanted there.

# `enter_predicate`

```elixir
@spec enter_predicate() :: :ok
```

A lookahead begins: failures until `exit_predicate/0` are not expectations.

# `error`

```elixir
@spec error(
  record(),
  tuple(),
  String.t(),
  non_neg_integer() | nil,
  atom() | nil,
  (atom() -&gt; String.t())
) ::
  Ichor.Error.t() | nil
```

The error a failed parse of `input` over `stream` reports, from its
`record`, or nil when the record says nothing better than the
caller's own error.

`leftover` is the token index a root that matched a prefix stopped
at, or nil when the root did not match at all: input left over after
a complete match is reported there unless some alternative reached
further. `skip` is the grammar's `@skip` token, which skip-splicing
makes optional everywhere and so is never worth naming. `describe`
names a wanted token for the user: an anonymous literal by its text,
quoted, and anything else by its name.

## Examples

    iex> stream = {%Grammar.VM.Token{name: :INT, text: "1", line: 1, column: 1}}
    iex> error = Grammar.Furthest.error({0, MapSet.new([:NAME])}, stream, "1", nil, nil, &Atom.to_string/1)
    iex> {error.message, error.line, error.column}
    {~s(unexpected "1" -- expected NAME), 1, 1}

# `exit_predicate`

```elixir
@spec exit_predicate() :: :ok
```

A lookahead ends, matched or not.

# `failed`

```elixir
@spec failed(non_neg_integer(), atom()) :: :ok
```

A token match that failed: at token index `pos`, wanting `name`.
Ignored inside a lookahead, behind the furthest position, and outside
a parse that called `start/0`.

# `finish`

```elixir
@spec finish(term()) :: record()
```

The parse's record, and whatever `start/0` found put back.

# `start`

```elixir
@spec start() :: term()
```

Starts a fresh record for a parse, answering whatever was there, for `finish/1`.

---

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