Skip to content

Repository files navigation

Tokora

Deterministic parser combinators, with on-demand lexing, LALR-style dispatch, explicit backtracking, and configurable diagnostics.

github LoC Build codecov

docs.rs book crates.io crates.io

Discord license

Introduction

Tokora is a Rust parser-combinator library with on-demand lexing, explicit lookahead and backtracking, configurable diagnostics, and optional Logos and Rowan integrations. Parsers work over a Lexer and Token model, so the same grammar can use a fail-fast runtime emitter or a collecting diagnostic emitter.

Install

Most applications use the maintained Logos adapter:

[dependencies]
tokora = { version = "0.9", features = ["logos"] }

logos is the alias for the logos_0_16 integration, the only Logos major tokora supports. The default std feature remains enabled unless you set default-features = false.

Which version this describes. Every [dependencies] snippet in this README resolves against the latest release, 0.9.1. A feature that main has grown since is named with the version it will arrive in, rather than put in a copyable block you cannot resolve.

Capabilities

  • On-demand token flow through InputRef, with explicit cache-backed lookahead and transactions.
  • Plain parser functions plus composable sequencing, repetition, delimiters, and deterministic choice.
  • Token-level and AST-level Pratt parsing.
  • Configurable Fatal, Verbose, Silent, and Ignored diagnostics.
  • Recovery, partial-input support, lexer conformance checks, tracing, and a public fuzz harness.
  • Optional lossless CST building over the parser's own backtracking (feature rowan): a rewindable event-stream sink where a parser rollback rewinds the half-built tree, and node combinators bracket sub-parses into syntax nodes.
  • Optional adapters for Logos, Rowan CSTs, source types, and container types.

How Tokora parses

A Tokora grammar is ordinary Rust: parser functions and combinators read through InputRef, which pulls tokens from a Lexer on demand and stages tokens in its cache when lookahead or backtracking needs them. peek_then_choice makes a decision from a fixed lookahead window; dispatch_on_kind and fused_dispatch_on_kind route the next token's Token::Kind to exactly one selected branch.

That token-kind dispatch is local to a hand-written combinator grammar. Tokora does not accept an LALR grammar, generate LALR parse tables, or act as an LALR parser generator.

When a grammar needs speculation, it is explicit. attempt and try_attempt commit successful work and roll back a decline or error; Transaction exposes commit and rollback directly. A rollback restores the input position, span, lexer state, token cache, and diagnostics emitted since the checkpoint. Application-owned side effects need their own transaction boundary.

Diagnostics and recovery

Parsers are generic over their parse context, including the emitter. Parser::new() uses the fail-fast Fatal emitter; Verbose records diagnostics and can continue when the grammar recovers. The same parser functions can therefore serve a runtime parser, compiler front end, or editor integration without a second grammar implementation.

Structured lexer, token, separator, container, and Pratt errors convert into the application's error type through From implementations.

Recovery is explicit: recover restores the failed parse's starting point before running a recovery parser, while inplace_recover continues from the failure position. sync_balanced and skip_then_retry provide nesting-aware synchronization; Verbose records each successful non-empty skipped region once alongside other diagnostics. Incomplete errors are re-raised instead of recovered so unfinished partial input is not discarded.

Guide and examples

The Tokora Guide has three parts: ten Calc fundamentals, one anatomy chapter plus four maintained-example walkthroughs (five applied-parser chapters), and an optional Rowan/lossless-CST chapter. The examples below are canonical complete programs; the guide links back to them instead of copying whole files into prose.

Program Focus Canonical source Run
calculator Token-level Pratt evaluator calculator.rs cargo run -p tokora --example calculator --features logos
s_expression Recursive descent and evaluation s_expression.rs cargo run -p tokora --example s_expression --features logos
json Borrowed values, delimiters, and tentative choice json.rs cargo run -p tokora --example json --features logos
c_expression AST-level Pratt parsing with postfix forms c_expression.rs cargo run -p tokora --example c_expression --features logos

The book source lives under tokora/src/guide, and the examples also compile together with cargo test -p tokora --no-default-features --features std,logos,combinators --examples.

Features

The combinator-family gates — combinators and the thirteen families it covers, any through validate — are new in 0.9.0. On 0.8.0 and earlier there are no per-family gates, default is std alone, and every combinator is compiled unconditionally.

Feature Effect
default Enables std and combinators.
std Enables standard-library support and default features of applicable dependencies.
alloc Enables allocation-backed facilities in no_std builds.
combinators Umbrella for every combinator family below. On by default.
any Any — accept one token of any kind.
fail fail / fail_with.
filter filter, filter_with, filter_map, filter_map_with.
fold The fold drivers (fold_while, try_fold*, rfold*); implies many.
ident Ident::parse / try_parse and their _except twins.
keyword Keyword::parse / try_parse and their _exact / _sliced twins.
many The repetition family: repeated*, separated*, delim*, the delimiter handlers, the cardinality bounds, list and separated1.
map map / map_with.
peek peek_then*, peek_then_choice, peek_kind, dispatch_on_kind and its fused twin.
pratt Pratt expressions: the typed pratt driver, the token-level InputRef::pratt*, PrattToken, and the PrattEmitter channel.
punct The punctuator parsers (Comma::parse, …) and the parens/braces/brackets/angles delimited shapes built on them.
then then, then_ignore, ignore_then, then_value, and_then, and_then_with.
validate validate / validate_with.
logos Alias for logos_0_16, the only supported Logos integration.
logos_0_16 Enables the optional [email protected] adapter used by logos.
stacker Runs each Pratt frame prologue on a fresh heap stack segment when the native stack is nearly exhausted; implies std and pratt. It segments those two prologues and nothing else — a consumer's own descend/descending frames are ordinary native frames and are untouched — so it does not move RecursionLimiter::PARSE_DEFAULT_DEPTH, the budget they share. RecursionLimiter::SEGMENTED_PRATT_DEPTH is the larger figure it does justify, for a caller whose whole descent is Pratt frames to opt into. It is not a substitute for the recursion budget: a segment is an mmap, so a deep enough input still ends the process with nothing on any Result channel.
trace Enables parser tracing; implies std.
unstable-raw Exposes the unstable raw checkpoint API.
conformance Enables the custom-lexer conformance test kit; implies std.
fuzz Enables the deterministic public input/backtracking fuzz harness; implies std.
rowan Enables the rewindable event-stream Rowan CST — emitter, recording sink, and node combinators; implies std. A lossless sink requires a trivia-surfacing lexer (Lexer::SURFACES_TRIVIA). Add rowan = "0.17" directly when implementing rowan::Language.
bytes Alias for bytes_1.
bytes_1 Enables bytes@1 source support.
bstr Alias for bstr_1.
bstr_1 Enables bstr@1 source support.
hipstr Alias for hipstr_0_8.
hipstr_0_8 Enables [email protected] source support.
smol_bytes Alias for smol_bytes_0_1.
smol_bytes_0_1 Enables [email protected] source support (smol-bytes ≥ 0.1.2).
smallvec Alias for smallvec_1.
smallvec_1 Enables smallvec@1 containers and implies alloc.
heapless Alias for heapless_0_9.
heapless_0_9 Enables [email protected] containers.
tinyvec Alias for tinyvec_1.
tinyvec_1 Enables tinyvec@1 containers.

Every combinator family is independently gateable so an embedded or no-alloc build compiles only the combinators it calls. What the families sit on stays unconditional: Parser/Parse/parse*, the ParseInput / TryParseInput / ParseChoice traits, and the substrate combinators (expect, delimited, recover, select, opt, padded, node, labelled, …). combinators is a default feature, so a plain dependency line sees the whole surface; a default-features = false build names the families it uses.

Feature aliases select their versioned counterpart; versioned features make the corresponding optional dependency available. tokora::logos and the unversioned tokora::lexer::LogosLexer are available with logos_0_16 and re-export/adapt that version — the only Logos major tokora supports. rowan does not enable logos, and smallvec_1 is the versioned feature that adds alloc.

Platform support

Tokora's MSRV is Rust 1.95. Tokora's core supports both allocator-free no_std (no_std without alloc) and allocation-enabled no_std (no_std with alloc). Disable default features for allocator-free core use. Enable alloc when a parser, cache, or selected optional facility requires allocation; other optional facilities may require std.

Allocator-free no_std:

[dependencies]
tokora = { version = "0.9", default-features = false }

no_std with alloc:

[dependencies]
tokora = { version = "0.9", default-features = false, features = ["alloc"] }

Neither line enables a combinator family: combinators is a default feature, and both turn the defaults off. Add features = ["combinators"] for the umbrella, or list the families the grammar actually calls, as in features = ["alloc", "many", "map"].

Design philosophy and inspirations

Core Priorities

  1. Performance - Pull tokens from the lexer on demand and offer fused dispatch where avoiding a peek/cache round trip matters.
  2. Predictability - Prefer deterministic lookahead and token-kind dispatch; make speculation explicit and transactional.
  3. Composability - Combine small parser functions and combinators; compose focused emitter traits into custom diagnostic strategies.
  4. Versatility - Reuse parser functions with fail-fast, collecting, silent, or custom emitters.
  5. Flexibility - Work through generic Lexer and Token traits, with optional Logos input and Rowan CST integrations.
  6. Correctness - Track spans and structured errors, rewind emitted diagnostics with parser rollbacks, and provide conformance and fuzz test kits.

Inspirations

Tokora takes inspiration from:

  • winnow - For ergonomic parser API design
  • chumsky - For composable parser combinator patterns
  • logos - For high-performance lexing
  • rowan - For lossless syntax tree representation

Development

Useful repository checks:

cargo fmt --all --check
cargo test -p tokora --all-features
cargo test -p tokora --no-default-features --features std,logos,combinators --examples
RUSTDOCFLAGS="-D warnings" cargo test -p tokora --all-features --doc
(cd tokora && mdbook build)

The guide is validated both as rustdoc and as an mdBook so API links, local links, chapter order, and Pages output stay aligned.

License

tokora is under the terms of both the MIT license and the Apache License (Version 2.0).

See the Apache License, Version 2.0 and the MIT license text for details.

Copyright (c) 2026 Al Liu.

About

Blazing fast parser combinators with parse-while-lexing architecture (zero-copy), deterministic LALR-style parsing, and no hidden backtracking.

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

Generated from al8n/template-rs