cabal-version: 3.0
name: attoparsec-isotropic
version: 0.14.6
license: BSD-3-Clause
license-file: LICENSE
category: Text, Parsing
author: Daniil Iaitskov <dyaitskov@gmail.com>
maintainer: Daniil Iaitskov <dyaitskov@gmail.com>
stability: experimental
synopsis: right-to-left parser backward compatible with attoparsec
homepage: https://github.com/yaitskov/attoparsec-isotropic
bug-reports: https://github.com/yaitskov/attoparsec-isotropic/issues
build-type: Simple
description:
A fork of <https://github.com/haskell/attoparsec attoparsec> library
allows to define omnidirected parsers or parsers consuming input from
right-to-left. The library is highly backward compabitle with original
interface. Idea to do the fork is inspired by the need to parse a CSV
file in <https://github.com/yaitskov/RobinHood-pr0fit robin-hood-profit>
in one go with “constant” memory footprint and rows in reverse
chronological order.
== Example
#example#
> {-# LANGUAGE OverloadedStrings #-}
> {-# LANGUAGE TupleSections #-}
> import Data.Attoparsec.ByteString
>
> test = parseOnly ab "ab" == parseBackOnly ba "ab"
> where
> ab = (,) <$> string "a" <*> string "b"
> ba = (,) <$> string "b" <*> string "a"
>
> test2 = parseOnly ab "ab" == parseBackOnly ab "ba"
> where
> ab = string "a" >*< string "b"
== Running parser in reverse incrementally
#running-parser-in-reverse-incrementally#
Snippet from the CSV parser app:
> consumeFile :: Handle -> (RobinRow -> ProfitM ()) -> ProfitM ()
> consumeFile h handleRow = do
> input <- readBlock h
> go Nothing input
> where
> go !loopDetector input = do
> iBlock <- gets (^. #currentBlock)
> if iBlock < 0 && input == mempty
> then pure ()
> else do
> parseBackWith (readBlock h) parseRow input >>= \case
> Fail _unconsumed ctx er -> do
> erpos <- liftIO $ hTell h
> fail $ "Failed to parse CSV file around " <> show erpos <> " byte; due: "
> <> show er <> "; context: " <> show ctx
> Partial _ -> fail "CSV file is partial"
> Done (unconsumed :: ByteString) (rawRow :: [ByteString]) -> do
> iBlock' <- gets (^. #currentBlock)
> if loopDetector == Just (unconsumed, iBlock')
> then
> fail $ "Loop detected. Unconsumed input: " <> show unconsumed
> else do
> trashCodes <- asks (^. #codesToSkip)
> case parseRobinRow trashCodes rawRow of
> Left e -> fail e
> Right row -> do
> forM_ row handleRow
> go (Just (unconsumed, iBlock')) unconsumed
tested-with:
GHC == 9.10.1, GHC == 9.12.2
extra-source-files:
trace-embrace.yaml
benchmarks/*.txt
benchmarks/json-data/*.json
benchmarks/Makefile
benchmarks/med.txt.bz2
examples/*.c
examples/*.hs
examples/Makefile
extra-doc-files:
README.md
changelog.md
Flag developer
Description: Whether to build the library in development mode
Default: False
Manual: True
common base
default-language: GHC2024
ghc-options: -Wall
default-extensions:
CPP
DefaultSignatures
OverloadedStrings
TemplateHaskell
TypeFamilies
build-depends:
array < 1
, base < 5
, bytestring < 1
, containers < 1
, deepseq < 2
, fail < 5
, haddock-use-refs < 2
, scientific < 1
, semigroups < 0.21
, tagged < 1
, text < 3
, trace-embrace >= 1.2 && < 3
, transformers < 1
-- We need to test and benchmark these modules,
-- but do not want to expose them to end users
library attoparsec-isotropic-internal
import: base
hs-source-dirs: internal
exposed-modules: Data.Attoparsec.ByteString.Buffer
Data.Attoparsec.ByteString.FastSet
Data.Attoparsec.Internal.Compat
Data.Attoparsec.Internal.Fhthagn
Data.Attoparsec.Text.Buffer
Data.Attoparsec.Text.FastSet
ghc-options: -O2 -Wall
library
import: base
build-depends:
attoparsec-isotropic-internal
, ghc-prim < 0.14
exposed-modules: Data.Attoparsec
Data.Attoparsec.ByteString
Data.Attoparsec.ByteString.Char8
Data.Attoparsec.ByteString.Lazy
Data.Attoparsec.Char8
Data.Attoparsec.Combinator
Data.Attoparsec.Internal
Data.Attoparsec.Internal.Types
Data.Attoparsec.Lazy
Data.Attoparsec.Number
Data.Attoparsec.Text
Data.Attoparsec.Text.Lazy
Data.Attoparsec.Types
Data.Attoparsec.Zepto
other-modules: Data.Attoparsec.ByteString.Internal
Data.Attoparsec.Text.Internal
ghc-options: -O2 -Wall
if flag(developer)
ghc-prof-options: -auto-all
ghc-options: -Werror
test-suite attoparsec-isotropic-tests
import: base
type: exitcode-stdio-1.0
hs-source-dirs: tests
main-is: QC.hs
other-modules: QC.Buffer
QC.ByteString
QC.ByteStringRightToLeft
QC.Combinator
QC.CombinatorRight
QC.Common
QC.IPv6.Internal
QC.IPv6.Types
QC.MonoidalScientific
QC.Rechunked
QC.Simple
QC.Text
QC.Text.FastSet
QC.Text.Regressions
ghc-options:
-Wall -threaded -rtsopts
if flag(developer)
ghc-options: -Werror
build-depends:
QuickCheck >= 2.13.2 && < 2.16
, attoparsec-isotropic
, attoparsec-isotropic-internal
, quickcheck-unicode
, tasty >= 1 && < 2
, tasty-bench >= 0.3 && < 1
, tasty-quickcheck >= 0.8 && < 1
, vector
-- benchmark dependencies
-- cabal2nix skips dependencies from benchmark
, http-types
benchmark attoparsec-isotropic-benchmarks
import: base
type: exitcode-stdio-1.0
hs-source-dirs: benchmarks benchmarks/warp-3.0.1.1
ghc-options: -O2 -Wall -rtsopts
main-is: Benchmarks.hs
other-modules:
Aeson
Common
Genome
HeadersByteString
HeadersByteString.Atto
HeadersText
Links
Network.Wai.Handler.Warp.ReadInt
Network.Wai.Handler.Warp.RequestHeader
Numbers
Sets
TextFastSet
Warp
ghc-options: -O2 -Wall
if flag(developer)
ghc-options: -Werror
build-depends:
attoparsec-isotropic
, attoparsec-isotropic-internal
, case-insensitive
, directory
, filepath
, ghc-prim
, http-types
, parsec >= 3.1.2
, tasty-bench >= 0.3 && < 1
, unordered-containers
, vector
source-repository head
type: git
location: https://github.com/yaitskov/attoparsec-isotropic.git