Megaparsec Documentation
repository·master·Indexed 21 days ago
https://github.com/mrkkrp/megaparsecAn industrial-strength monadic parser combinator library for Haskell designed for speed, flexibility, and high-quality error reporting. It features MonadParsec, ParsecT, and specialized high-performance combinators like tokens, takeWhileP, and takeP. It supports String, ByteString, and Text input streams, and provides sophisticated error handling via ParseErrorBundle and typed errors. The library includes specialized lexer modules for character-based and binary data streams.
What's inside Megaparsec
- Megaparsec is an industrial-strength monadic parser combinator library for Haskell. It is designed to strike a balance between speed, flexibility, and high-quality parse error messages. It is particularly well-suited for parsing human-readable text and source code.
Use megaparsec-tests for external test suites
masterThemegaparsec-testspackage provides Megaparsec's test suite as a standalone library. It is designed to be used by other test suites (such asparser-combinators-tests) to access auxiliary testing functions exported by the package. This separation avoids circular dependencies and allows for a cleaner test environment.Explore related Megaparsec packages
masterMegaparsec has a ecosystem of specialized packages designed to extend its functionality:
- Testing:
hspec-megaparsecprovides utilities for testing parsers with Hspec. - Stream Editing:
replace-megaparsecenables stream editing and find-and-replace operations. - CSV Parsing:
cassava-megaparsecallows parsing CSV files while maintaining compatibility with the Cassava library. - HTML/TagSoup:
tagsoup-megaparseclets you use TagSoup as a token type within Megaparsec. - Combinators:
parser-combinatorsprovides permutation and expression parsers (previously bundled with Megaparsec). - Performance:
faster-megaparsecoptimizes parsing speed by attempting a simpleMonadParsecinstance before falling back toParsecTfor error reporting.
- Testing:
How MonadParsec and ParsecT work
masterMegaparsec is built around
MonadParsec, an MTL-style type class. Most features work with any instance ofMonadParsec.To achieve various effects, you can build a monadic stack using monad transformers. Because common transformers like
WriterT,StateT, andReaderTare instances ofMonadParsec, you can wrapParsecTinside these monads to achieve features like backtracking state.ParsecTitself implements several useful type classes:MonadApplicativeAlternativeMonadParsec
Error handling and ParseErrorBundle
masterMegaparsec provides sophisticated error reporting features:
- Typed Errors: Supports typed error messages and custom parse errors tailored to specific domains.
- Independent Error Locations: Since version 8, the location of a parse error can be independent of the current offset, allowing you to point to specific positions after performing checks.
- ParseErrorBundle: Instead of a single error, Megaparsec produces a
ParseErrorBundlewhich manages and pretty-prints multiple parse errors simultaneously.
Set up a development environment with Nix and ghcid
masterMegaparsec uses
nixfor development. To enter the development shell, runnix develop.Once inside the shell, you can use the following commands:
- Build packages: Use
cabal build allto build bothmegaparsecandmegaparsec-tests. - Run tests: Use
cabal test allto run tests from themegaparsec-testspackage. - Interactive feedback: Use
ghcidfor real-time feedback while editing.- For
megaparsec:ghcid --command="cabal repl megaparsec" - For
megaparsec-tests:ghcid --command="cabal repl megaparsec-tests --enable-tests"
- For
$ nix develop $ cabal build all $ cabal test all $ ghcid --command="cabal repl megaparsec"- Build packages: Use
Run Megaparsec benchmarks
masterBenchmarks are located in the
benchsub-directory. Note: You mustcdinto thebenchdirectory before running them, as they rely on relative paths for data files.- Build all benchmarks:
nix build .#all_benches(creates symlinks inresult). - Build specific package benchmarks: To build only
megaparsecmicrobenchmarks, runnix build .#benches/megaparsec.
$ nix build .#all_benches $ nix build .#benches/megaparsec- Build all benchmarks:
Release a new version of Megaparsec
masterFollow these steps to release a new version:
- Bump versions: Update the version in
megaparsec.cabal. Also updatemegaparsec-tests.cabalto match, including its dependency onmegaparsec. - Tagging: Create a git tag and push it to the repository.
- Generate tarballs: Run
nix build .#all_dist. This creates aresultdirectory containingmegaparsec-source-*andmegaparsec-tests-source-*tarballs. - Upload to Hackage: Use
cabal upload --publishfor both the source and test tarballs:
$ cabal upload --publish result/megaparsec-source-*/megaparsec-*.tar.gz $ cabal upload --publish result/megaparsec-tests-source-*/megaparsec-tests-*.tar.gz$ nix build .#all_dist $ cabal upload --publish result/megaparsec-source-*/megaparsec-*.tar.gz $ cabal upload --publish result/megaparsec-tests-source-*/megaparsec-tests-*.tar.gz- Bump versions: Update the version in
Run unit tests and check dependent packages
masterTo gain higher confidence in non-trivial changes, you should run tests beyond the standard
megaparsec-testssuite.Build the base test group
Use the
basegroup to build and testmegaparsec,hspec-megaparsec,megaparsec-tests, andparser-combinators-tests:$ nix build .#all_base --no-linkTo build a specific derivation from the base group (e.g.,
parser-combinators-tests):$ nix build .#base/parser-combinators-tests --no-linkCheck impact on dependent packages
To see how changes affect a selected set of high-quality dependent packages, run:
$ nix build .#all_deps --no-linkTo test a specific package (e.g.,
mmark):$ nix build .#deps/mmark --no-link$ nix build .#all_base --no-link $ nix build .#all_deps --no-link $ nix build .#deps/mmark --no-linkBenchmark Megaparsec performance
masterYou can run the built-in benchmarks using
nix-build.$ nix-build -A benches.parsers-bench $ cd result/bench $ ./bench-memory $ ./bench-speedCreate patches for breaking changes in dependent packages
masterIf a breaking change in Megaparsec causes a dependent package to fail compilation, you can create a patch to maintain compatibility:
- Clone the failing package's repository.
- Checkout the commit corresponding to the version used in the current
nixpkgs. - Attempt to compile the package using the current development version of Megaparsec (e.g., by adding the Megaparsec path to
extra-depsin Stack). - Apply necessary changes to fix the build.
- Generate a patch file:
- For unstaged changes:
git diff > my-package.patch - For staged changes:
git diff --cached > my-package.patch
- For unstaged changes:
- Apply the patch in
default.nixby editing thedepsattribute set:
# Example of applying a patch in default.nix deps = { # ... idris = patch haskellPackages.idris ./nix/patches/idris.patch; };deps = { # ... idris = patch haskellPackages.idris ./nix/patches/idris.patch; };High-performance combinators in Megaparsec
masterMegaparsec provides specialized high-performance combinators that are significantly faster than standard approaches:
tokens: Parses several tokens in a row. It is approximately 100x faster than matching a string token by token. It returns a "chunk" of the original input (e.g., if parsingText, it returnsTextwithout repacking).takeWhilePandtakeWhile1P: Approximately 150x faster than usingmany,manyTill, or similar combinators.takeP: Grabsntokens from the stream and returns them as a "chunk" of the stream.