Skip to content

Benchmarks

Hyperlark’s parse time against other parsers in Python, Rust, JavaScript/TypeScript and C. Most charts use one of two inputs: JSON with many small objects and arrays (structure-heavy), or arithmetic expressions (calc). Within a chart, every library reads the same input and produces the same result: the JSON value or a digest of it (a sum over its numbers), or the calc answer (method). Both of Hyperlark’s parsers, LALR and Earley, are charted. nom, lalrpop with logos, pest, bison and lemon compile the grammar into the program at build time and are faster than Hyperlark, which builds its tables when your program runs. In JavaScript, chevrotain is faster on the structure-heavy JSON and on calc, peggy on calc, and nearley leads Hyperlark’s Earley with the dynamic_complete lexer (TypeScript tab). Alternatives says what each library is and when to prefer it.

The parse runs in native code; only your transformer callbacks run in Python. Hyperlark’s LALR is 11.1× faster than Lark’s on JSON and 10.1× on calc, and ahead of sly, the fastest pure-Python parser here.

Hyperlark’s LALR, Lark’s LALR and sly compute the result during the parse, with no tree. For Hyperlark and Lark that is Lark(grammar, parser="lalr", transformer=...) (Transformers). The Earley rows and parsimonious build a tree first. Lark’s Earley (1096 ms on JSON, 1739 ms on calc) is off the scale; see below.

JSON → digest (Python, 134 KB)
Hyperlark (LALR) 4.74 ms
sly 42.3 ms
lark (LALR) 52.6 ms
Hyperlark (Earley) 62.9 ms
parsimonious (PEG, 194 ms) is off this chart's scale.
calc → number (Python, 85 KB)
Hyperlark (LALR) 7.02 ms
sly 39.6 ms
lark (LALR) 71.3 ms
Hyperlark (Earley) 73.1 ms
parsimonious (125 ms) is off this chart's scale.

All six, both inputs (ms):

libraryJSON → digestcalc → number
Hyperlark (LALR)4.747.02
sly42.339.6
lark (LALR)52.671.3
Hyperlark (Earley)62.973.1
parsimonious (PEG)194125
lark (Earley)10961739

Opt-in switches such as fast_scan are off.

Versions: lark 1.3.1, sly 0.5, CPython 3.14.2.

These tables time building an LALR parser, Hyperlark against Lark. The builds are warm, so a fresh process’s first build costs more on both sides. Hyperlark builds its lexer’s scanners lazily, during the first parse, so the constructor alone overstates its margin on python.lark: the first parse there takes 6.47 ms, a warm one 0.73 ms. The second table adds that first parse (8 to 13 KB input) to both sides.

Constructor only:

Grammar (LALR)Hyperlarklarkratio
json.lark0.72 ms4.77 ms6.7×
calc.lark0.79 ms4.35 ms5.5×
tp_escaped_string.lark0.28 ms2.5 ms9.1×
python.lark22.5 ms269 ms12.0×

Constructor plus the first parse:

Grammar (LALR)Hyperlarklarkratio
json.lark1.18 ms11.7 ms9.9×
calc.lark1.53 ms12.3 ms8.0×
tp_escaped_string.lark0.39 ms3.81 ms9.8×
python.lark29 ms298 ms10.3×

Earley is the default parser in both libraries. Hyperlark’s is 17.4× faster than Lark’s on JSON and 23.8× on calc. If your grammar needs Earley, Hyperlark’s is slower than Lark’s LALR but close: 62.9 against 52.6 ms on JSON and 73.1 against 71.3 ms on calc.

JSON → digest · Earley and PEG (134 KB)
Hyperlark (Earley) 62.9 ms
parsimonious (PEG) 194 ms
lark (Earley) 1096 ms
calc → number · Earley and PEG (85 KB)
Hyperlark (Earley) 73.1 ms
parsimonious (PEG) 125 ms
lark (Earley) 1739 ms
Hyperlark's Earley leads parsimonious by 1.7× on calc and 3.1× on JSON.
  • One machine (cpu Apple · arch aarch64 · 13 cores · rustc 1.96.0). Compare bars within a chart; your hardware’s milliseconds will differ.
  • Warm timings: the best of many runs after warm-up. The Rust figures are criterion medians; the first-parse figures under Building the parser are single cold runs.
  • Each parser is built once, outside the timed loop, so the figures are parse time only. Building the parser, Hyperlark against Lark, is timed in the Python tab.
  • Every library reads the same bytes and must produce the same result, or its row is not published. For JSON, Rust and JavaScript produce the value itself. Python and C produce a digest of it: the sum of its numbers, each truncated to an integer. For calc, every target produces the evaluated answer.
  • Inputs:
    • JSON, 134 KB: 240 generated values nested up to three deep (structure-heavy).
    • calc, 85 KB: 720 arithmetic expressions, one per line, each parsed separately (720 small parses per run).
    • JSON, 1 MB, for the WASM scan-heavy chart: 430 strings of about 2.5 KB, so the lexer does most of the work.
  • Bars are milliseconds; shorter is faster. A library far off a chart’s scale is left off it and listed in that tab’s table.