Skip to content

v0.7.0.0 — `<?>` and `commit` error-reporting combinators

Choose a tag to compare

@zollij zollij released this 03 May 22:13
· 1 commit to main since this release

New features

Two additive combinators for controlling error reporting at choice boundaries. Existing parsers compile unchanged.

  • (<?>) :: Parser a -> String -> Parser a — replaces a parser's failure with a single Labeled lbl pos carrying the label and the position where the labeled parser started. Use to surface "expected an X here" diagnostics instead of whatever character-level mismatch the deepest internal parser happened to produce.
  • commit :: Parser a -> Parser a — marks a parse path as committed: if it fails, surrounding <|> propagates the failure rather than backtracking to the next alternative. Built on a new internal Committed [Error] marker that the Alternative instance recognises and strips. parse unwraps any top-level Committed, so external callers never observe the marker.
  • Error gains two constructors: Labeled !String !Pos and Committed ![Error]. Pattern-matching code that explicitly listed every Error constructor will get a non-exhaustive-match warning and need to add the new cases.

The <|> instance gains one extra pattern match on its failure path — a head-of-list check for the Committed marker — which is constant-time and only runs when an alternative has already failed. The success path is byte-identical.

Performance

  • INLINABLE pragmas on numeric parsers. dec, hex, oct, bin, digs, and signed all became Num a => … in 0.5.x but lacked unfoldings, so cross-module callers paid dictionary-passing overhead on every digit. Adding {-# INLINABLE #-} recovers ~27% on the Log workload (188 μs → 137 μs), putting MiniParser back in the same league as Megaparsec on that benchmark. CSV and JSON also see modest improvements.

Bench fixes

  • perf-compare build fixed. The benchmark project's .cabal was missing a scientific build-dep added to MiniParser.Base in 0.5.x, and BenchLog.hs / BenchJSON.hs still referenced MP.nat (renamed to MP.dec in 0.5.x). Both fixed; cabal bench bench-csv bench-log bench-json now runs cleanly.

Documentation

  • New Error Labeling and Cut section in README.md with worked examples for both combinators, a "scope of commit" note, and an explicit rule-of-thumb that commit goes on the outside, <?> on the inside — putting <?> outside commit silently discards the Committed marker.
  • Performance Benchmarks section refreshed with new numbers and a softened analysis (MiniParser is "competitive with Megaparsec" rather than "consistently faster" — Log is now within ~3% of Megaparsec instead of ahead).

Tests

  • 13 adversarial cases added to test/Test.hs covering nested-label override, <?> over empty / pFailStr / eof, triple-nested commit, scope-after-success, commit empty, nested-<|> commit propagation, and two documented footguns (the <?>-outside-commit order trap, and commit inside many being stripped at the inner <|>). Suite count is now 338 (was 313 in 0.6.0.0).