Alternatives
Each tab compares Hyperlark with the main parsing libraries in one language and says when to prefer which.
Hyperlark loads a .lark grammar when your program runs and compiles it in
memory, with no code generation. It has two parsers,
LALR and Earley: Earley accepts
grammars LALR rejects and is slower on every input here. Python,
Rust and TypeScript (through WASM) have both; C has LALR only, for now.
In Python, Hyperlark is often a drop-in replacement for
lark: the same grammar and nearly the same API,
with the parse running in native Rust.
| Parser | Approach | Pros | Cons |
|---|---|---|---|
| Hyperlark | Rust core behind a Lark-compatible API | Parse in native code; LALR and Earley; no runtime dependency on lark | In beta: fewer users and examples; close to lark, with documented gaps; wheels only, for CPython 3.10+ on Linux, macOS 13+ and Windows x64 (install); no PyPy |
| lark | Pure Python; the library Hyperlark reimplements | Mature; Earley, LALR and CYK, a reconstructor and tree templates; large community; no compiled dependency | Slower than Hyperlark and sly (chart below) |
| PLY | Python lex-yacc (LALR) | Stable; well documented | Rules in method docstrings; no tree by default |
| sly | PLY’s successor (yacc-style LALR) | Reduces straight to a value, no tree | The grammar is Python code; less active |
| pyparsing | Combinators (PEG-like), pure Python | No grammar file: the grammar is Python expressions | Pure Python; ordered choice with |, so the first alternative that matches wins |
| parsimonious | PEG with a grammar file | Short declarative grammars | Pure Python; PEG semantics (ordered choice, no left recursion) |
| ANTLR4 (Python target) | ALL(*) parser generator (codegen) | One grammar, many target languages; mature tooling | Codegen through a Java tool; heavy, verbose runtime |
PLY, pyparsing and ANTLR are not in the chart below.
Which to pick:
- Hyperlark for Lark’s grammar and API with a much faster parse.
- Lark for a feature Hyperlark lacks, such as the reconstructor or tree templates (full list), for pure Python with no compiled dependency, or on PyPy.
- sly for a yacc-style evaluator with no tree.
- ANTLR for its tooling, or for a target language Hyperlark does not have.
In Rust, Hyperlark is the one library here that loads its grammar at runtime, so the grammar can change without a rebuild.
| Parser | Approach | Pros | Cons |
|---|---|---|---|
| Hyperlark | Runtime LALR and Earley tables from a .lark grammar | No build step; LALR and Earley from one grammar; a tree, or a value computed during the parse with no tree; the same grammar runs in Python, JS and C | Source available with license (contact us); Rust 1.96 or later; slower than nom, lalrpop and pest (chart below); in beta, small ecosystem; a grammar instead of Rust, so less inline control than combinators |
| nom | Parser combinators (Rust functions) | The fastest here; few dependencies; suits binary and streaming formats; full control | The grammar is Rust code; ordered choice, so no LALR conflict checks; you build any tree yourself |
| winnow | Combinators, forked from nom | Actively developed | As nom: the grammar is Rust code |
| chumsky | Combinators with built-in error recovery | Error recovery and good error messages; suits language front ends | Slower than nom and Hyperlark’s LALR (chart below); the grammar is Rust code |
| pest | PEG from a .pest file (a derive macro generates the parser) | Declarative grammar file; good error messages | A build step; PEG semantics (ordered choice, no left recursion); untyped pairs you walk |
| lalrpop | LR(1) parser generator (codegen) | LR(1) with conflict detection; fast; typed reduce actions | A build step; its built-in lexer is slow (pair it with logos); Rust only |
| tree-sitter | Incremental GLR at runtime, from generated C tables | Incremental re-parse and error recovery; a large grammar ecosystem; many languages | The grammar is JS, generated to C (a build step); a concrete syntax tree rather than an AST; tuned for editors rather than throughput |
winnow is not in the chart below.
Which to pick:
- Hyperlark for a grammar file you load or edit at runtime and share across languages, when the speed in the chart is enough.
- nom or winnow for maximum speed and binary formats.
- chumsky for a language front end that needs error recovery and good error messages.
- lalrpop for a compiled LR(1) parser with conflict detection.
- pest for a declarative PEG grammar with a build step.
- tree-sitter for incremental editor tooling.
In JavaScript and TypeScript, Hyperlark is the npm package
@hyperlark/hyperlark, loading .lark grammars at runtime with no build
step. On structure-heavy
input (many small nodes) chevrotain is faster than Hyperlark, and peggy
sometimes is; on scan-heavy input (few nodes, long tokens) Hyperlark is
slightly ahead (benchmarks, TypeScript tab).
| Parser | Approach | Pros | Cons |
|---|---|---|---|
| Hyperlark (WASM) | Rust core compiled to WASM, with TypeScript types; .lark grammar | LALR and Earley; the same grammar as Python, Rust and C; a tree, or a value computed with no JS tree | Slower than chevrotain, and sometimes peggy, on structure-heavy input; a WASM module to ship; Node 22 or later (browsers and other runtimes use a separate entry point); in beta |
| chevrotain | Pure-JS parsing DSL at runtime, no codegen | The fastest pure-JS parser here; no build step; good errors; Langium is built on it | The grammar is JS rule methods rather than a declarative file; JS only; needs JIT warm-up |
| peggy (successor to peg.js) | PEG, generates a JS parser | Declarative PEG grammar; a standalone generated parser | PEG semantics (ordered choice, no left recursion); slower than chevrotain |
| nearley | Earley at runtime; grammar compiled by nearleyc | Any context-free grammar, ambiguity included; streaming | Slower than the LALR and PEG parsers here; a grammar build step; lightly maintained |
| ohm | PEG with a grammar file and separate semantics | Declarative grammar and semantic actions; good for DSLs and teaching | Smaller ecosystem |
| tree-sitter (WASM) | Incremental GLR | Incremental parsing and error recovery for editors; many grammars | Grammar generated JS→C→WASM (a build step); a concrete syntax tree rather than an AST |
ohm, tree-sitter and nearley are not in the chart below; the chart note compares nearley with Hyperlark’s Earley on calc.
Which to pick:
- Hyperlark when you already have a
.larkgrammar or want one grammar shared with other languages. - chevrotain for the fastest pure-JS parsing on structure-heavy input, with no build step.
- peggy for a declarative PEG grammar.
- nearley for general or ambiguous grammars in pure JS.
- tree-sitter for incremental editor tooling.
In C, Hyperlark loads a .lark grammar at runtime, behind a C ABI.
| Parser | Approach | Pros | Cons |
|---|---|---|---|
| Hyperlark (C ABI) | Rust core behind a C ABI; .lark grammar | Grammars load at runtime, no code generation; a tree with a value computed over it (lark_fold_apply), or a value computed during the parse with no tree (lark_parse_fold) | Source available with license (contact us); builds with Rust 1.96 or later (build); no postlex (Indenter), custom lexer or %import of your own files (feature matrix); in beta |
| bison + flex | yacc/lex (LALR, codegen) | Fast LALR; decades of use; available everywhere | A build step; C actions interleaved in the grammar; global state and reentrancy quirks; you build the tree in actions |
| lemon | LALR generator (codegen), from SQLite | Reentrant, no global state; very fast | A build step; C actions; less common; you build the tree yourself |
| tree-sitter (C API) | Incremental GLR at runtime | Incremental parsing and error recovery for editors; a large grammar library | Grammar generated JS→C (a build step); a concrete syntax tree rather than an AST |
| re2c | Lexer generator | A very fast DFA lexer | Lexer only; pair it with a parser |
| hand-written recursive descent | Manual C | Full control; fast; no dependencies | All manual; no grammar file; error-prone as grammars grow |
re2c and hand-written parsers are not in the chart below.
Which to pick:
- Hyperlark for a grammar loaded at runtime, with a tree or a value computed during the parse (
lark_parse_fold). - bison + flex or lemon for a compiled LALR parser with no runtime dependency; lemon if you want reentrancy and no global state.
- tree-sitter for incremental editor tooling.