# parser-lang v0.2.0 — Cursor & Pratt engine
**The core, front-loaded.** v0.2.0 turns the scaffold into a working parsing
toolkit: the [`Parser`] cursor a hand-written recursive-descent grammar threads,
and the [`Pratt`] precedence-climbing engine for expressions, with error recovery
throughout. This was the hard part of the roadmap, and the roadmap put it first.
## What is parser-lang?
The parsing layer of the `-lang` family. It owns no grammar and no AST: a grammar
is a set of functions that take `&mut Parser` and build whatever output they like,
consuming [`token-lang`] tokens and reporting [`diag-lang`] diagnostics. parser-lang
supplies the cursor, the precedence loop, and the recovery machinery they run on.
## What's new in 0.2.0
### `Parser` — the recursive-descent cursor
[`Parser`] borrows a `&[Token<K>]`, skips trivia, and stops cleanly at end of input.
Kinds are matched by predicate, so a kind that carries data needs no `PartialEq`:
```rust
use parser_lang::{Parser, Span, Token, TokenKind};
# #[derive(Clone, Copy)] enum K { Num, Plus, Eof }
# impl TokenKind for K { fn is_eof(&self) -> bool { matches!(self, K::Eof) } }
# let tokens = [Token::new(K::Num, Span::new(0,1)), Token::new(K::Eof, Span::empty(1))];
let mut p = Parser::new(&tokens);
}
```
`expect` records an `expected …` diagnostic on a mismatch and keeps going; `recover`
skips to a synchronizing token; `repeated` and `separated` cover list shapes;
`checkpoint`/`rewind` give speculative parsing that rolls back the cursor *and* any
errors recorded since. Errors are collected, not thrown — one parse reports many,
in source order.
### `Pratt` — precedence climbing
[`Pratt`] turns operator precedence and associativity into three small methods —
`prefix`, `infix_binding`, `infix` — and a provided driver does the rest. The engine
is validated against an independent shunting-yard oracle over random operator
sequences, so `1 + 2 * 3` groups as `1 + (2 * 3)` and `2 ^ 3 ^ 2` as `2 ^ (3 ^ 2)`,
every time.
### A worked grammar
`tests/calculator.rs` is a full calculator: a Pratt expression engine with
parentheses and prefix negation, a recursive-descent statement loop, and recovery
that parses the good statements around a broken one while collecting diagnostics —
the whole toolkit exercised end to end.
## Breaking changes
**None** to released API: v0.1.0 had no public surface. The reserved no-op `serde`
feature is removed rather than carried unused toward the frozen 1.0 surface.
## Verification
```bash
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo clippy --all-targets --all-features -- -D warnings
cargo clippy --no-default-features -- -D warnings
cargo test
cargo test --all-features
cargo build --no-default-features
cargo +1.85 build --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
cargo audit
cargo deny check
```
All green. Counts at this tag: 12 unit + 9 calculator + 2 property + 13 doctests.
## What's next
- **1.0.0 — API freeze.** The surface is stable and frozen until 2.0;
documentation, tests, and internal optimisation only.
## Installation
```toml
[dependencies]
parser-lang = "0.2"
```
MSRV: Rust 1.85.
---
**Changelog:** [`CHANGELOG.md`](https://github.com/jamesgober/parser-lang/blob/main/CHANGELOG.md#020---2026-06-28).