paripari 0.3.0.0 → 0.4.0.0
raw patch · 10 files changed
+109/−65 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Text.PariPari: asciiSatisfy :: CharParser k p => (Word8 -> Bool) -> p Word8
- Text.PariPari.Internal.Acceptor: instance (Text.PariPari.Internal.Chunk.Chunk k, GHC.Base.Monoid a) => GHC.Base.Monoid (Text.PariPari.Internal.Acceptor.Acceptor k a)
- Text.PariPari.Internal.CharCombinators: scanCharsWhile :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s
- Text.PariPari.Internal.CharCombinators: scanCharsWhile1 :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s
- Text.PariPari.Internal.Class: asciiSatisfy :: CharParser k p => (Word8 -> Bool) -> p Word8
- Text.PariPari.Internal.ElementCombinators: scanElementsWhile :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s
- Text.PariPari.Internal.ElementCombinators: scanElementsWhile1 :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s
- Text.PariPari.Internal.Reporter: instance (Text.PariPari.Internal.Chunk.Chunk k, GHC.Base.Monoid a) => GHC.Base.Monoid (Text.PariPari.Internal.Reporter.Reporter k a)
+ Text.PariPari: asciiScan :: CharParser k p => (Word8 -> Maybe a) -> p a
+ Text.PariPari.Internal.Acceptor: instance (Text.PariPari.Internal.Chunk.Chunk k, GHC.Base.Semigroup a, GHC.Base.Monoid a) => GHC.Base.Monoid (Text.PariPari.Internal.Acceptor.Acceptor k a)
+ Text.PariPari.Internal.CharCombinators: asciiSatisfy :: CharParser k p => (Word8 -> Bool) -> p Word8
+ Text.PariPari.Internal.CharCombinators: scanChars :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s
+ Text.PariPari.Internal.CharCombinators: scanChars1 :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s
+ Text.PariPari.Internal.Class: asciiScan :: CharParser k p => (Word8 -> Maybe a) -> p a
+ Text.PariPari.Internal.ElementCombinators: scanElements :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s
+ Text.PariPari.Internal.ElementCombinators: scanElements1 :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s
+ Text.PariPari.Internal.Reporter: instance (Text.PariPari.Internal.Chunk.Chunk k, GHC.Base.Semigroup a, GHC.Base.Monoid a) => GHC.Base.Monoid (Text.PariPari.Internal.Reporter.Reporter k a)
Files
- paripari.cabal +8/−8
- specialise-all.hs +1/−0
- src/Text/PariPari/Internal/Acceptor.hs +11/−7
- src/Text/PariPari/Internal/CharCombinators.hs +15/−8
- src/Text/PariPari/Internal/Chunk.hs +1/−0
- src/Text/PariPari/Internal/Class.hs +5/−4
- src/Text/PariPari/Internal/ElementCombinators.hs +12/−11
- src/Text/PariPari/Internal/Reporter.hs +10/−6
- src/Text/PariPari/Internal/Tracer.hs +2/−1
- test/test.hs +44/−20
paripari.cabal view
@@ -2,12 +2,12 @@ -- -- see: https://github.com/sol/hpack ----- hash: 78092995723d296e73be8c5403a8bf6c7b46bece1826eb1e0841683e3252071d+-- hash: 9f4767161c726109fa8849cc08f350e49f03eeef59675e9c770da1f6bd959ab8 name: paripari-version: 0.3.0.0+version: 0.4.0.0 synopsis: Parser combinators with fast-path and slower fallback for error reporting-description: PariPari offers two parsing strategies. There is a fast Acceptor and a slower Reporter which are evaluated in parallel. If the Acceptor fails, the Reporter returns a report about the parsing errors. Unlike Parsec and like Attoparsec, the parser combinators backtrack by default.+description: PariPari offers two parsing strategies. There is a fast Acceptor and a slower Reporter which are evaluated in parallel. If the Acceptor fails, the Reporter returns a report about the parsing errors. Like Attoparsec, the parser combinators backtrack by default. category: Text stability: experimental homepage: https://github.com/minad/paripari#readme@@ -17,7 +17,7 @@ copyright: 2018 Daniel Mendler license: MIT license-file: LICENSE-tested-with: GHC == 8.4.3, GHC == 8.6.1+tested-with: GHC == 8.0.1, GHC == 8.2.1, GHC == 8.4.3, GHC == 8.6.1 build-type: Simple cabal-version: >= 1.10 @@ -40,7 +40,7 @@ Paths_paripari hs-source-dirs: src- ghc-options: -Wall -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances+ ghc-options: -Wall -Wcompat -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances build-depends: base >=4.8 && <5 , bytestring >=0.10 && <0.11@@ -52,7 +52,7 @@ main-is: example.hs other-modules: Paths_paripari- ghc-options: -Wall -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances+ ghc-options: -Wall -Wcompat -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances build-depends: base >=4.8 && <5 , bytestring >=0.10 && <0.11@@ -65,7 +65,7 @@ main-is: specialise-all.hs other-modules: Paths_paripari- ghc-options: -Wall -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances+ ghc-options: -Wall -Wcompat -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances build-depends: base >=4.8 && <5 , bytestring >=0.10 && <0.11@@ -81,7 +81,7 @@ Paths_paripari hs-source-dirs: test- ghc-options: -Wall -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances+ ghc-options: -Wall -Wcompat -Widentities -Wmonomorphism-restriction -Wincomplete-uni-patterns -Wincomplete-record-updates -Wtabs -fprint-potential-instances build-depends: base >=4.8 && <5 , bytestring >=0.10 && <0.11
specialise-all.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE Rank2Types #-} import System.Environment (getArgs)+import Data.Semigroup ((<>)) import Text.PariPari import qualified Data.Char as C import qualified Data.List.NonEmpty as NE
src/Text/PariPari/Internal/Acceptor.hs view
@@ -15,6 +15,7 @@ ) where import Control.Monad (void)+import Data.Semigroup as Sem import Data.String (IsString(..)) import Text.PariPari.Internal.Chunk import Text.PariPari.Internal.Class@@ -43,14 +44,17 @@ -> b } -instance (Chunk k, Semigroup a) => Semigroup (Acceptor k a) where+instance (Chunk k, Semigroup a) => Sem.Semigroup (Acceptor k a) where p1 <> p2 = (<>) <$> p1 <*> p2 {-# INLINE (<>) #-} -instance (Chunk k, Monoid a) => Monoid (Acceptor k a) where+instance (Chunk k, Semigroup a, Monoid a) => Monoid (Acceptor k a) where mempty = pure mempty {-# INLINE mempty #-} + mappend = (<>)+ {-# INLINE mappend #-}+ instance Functor (Acceptor k) where fmap f p = Acceptor $ \env st ok err -> unAcceptor p env st (ok . f) err@@ -212,19 +216,19 @@ err $ ECombinator "char" {-# INLINE char #-} - asciiSatisfy f = Acceptor $ \env st@State{_stOff, _stLine, _stCol} ok err ->+ asciiScan f = Acceptor $ \env st@State{_stOff, _stLine, _stCol} ok err -> if | b <- byteAt @k (_envBuf env) _stOff, b /= 0, b < 128,- f b ->- ok b st+ Just x <- f b ->+ ok x st { _stOff = _stOff + 1 , _stLine = if b == asc_newline then _stLine + 1 else _stLine , _stCol = if b == asc_newline then 1 else _stCol + 1 } | otherwise ->- err $ ECombinator "asciiSatisfy"- {-# INLINE asciiSatisfy #-}+ err $ ECombinator "asciiScan"+ {-# INLINE asciiScan #-} asciiByte 0 = error "Character '\\0' cannot be parsed because it is used as sentinel" asciiByte b
src/Text/PariPari/Internal/CharCombinators.hs view
@@ -27,14 +27,15 @@ , spaceChar , asciiChar , satisfy+ , asciiSatisfy , skipChars , takeChars , skipCharsWhile , takeCharsWhile , skipCharsWhile1 , takeCharsWhile1- , scanCharsWhile- , scanCharsWhile1+ , scanChars+ , scanChars1 , string ) where @@ -42,6 +43,7 @@ import Control.Monad.Combinators (option, skipCount, skipMany) import Data.Functor (void) import Data.Maybe (fromMaybe)+import Data.Semigroup ((<>)) import Data.Word (Word8) import Text.PariPari.Internal.Chunk import Text.PariPari.Internal.Class@@ -303,11 +305,16 @@ satisfy f = scan $ \c -> if f c then Just c else Nothing {-# INLINE satisfy #-} -scanCharsWhile :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s-scanCharsWhile f = go+-- | Parse a single character within the ASCII charset with the given predicate+asciiSatisfy :: CharParser k p => (Word8 -> Bool) -> p Word8+asciiSatisfy f = asciiScan $ \b -> if f b then Just b else Nothing+{-# INLINE asciiSatisfy #-}++scanChars :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s+scanChars f = go where go s = (scan (f s) >>= go) <|> pure s-{-# INLINE scanCharsWhile #-}+{-# INLINE scanChars #-} -scanCharsWhile1 :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s-scanCharsWhile1 f s = scan (f s) >>= scanCharsWhile f-{-# INLINE scanCharsWhile1 #-}+scanChars1 :: CharParser k p => (s -> Char -> Maybe s) -> s -> p s+scanChars1 f s = scan (f s) >>= scanChars f+{-# INLINE scanChars1 #-}
src/Text/PariPari/Internal/Chunk.hs view
@@ -16,6 +16,7 @@ import Data.Bits (unsafeShiftL, (.|.), (.&.)) import Data.ByteString (ByteString) import Data.Foldable (foldl')+import Data.Semigroup ((<>)) import Data.String (fromString) import Data.Text (Text) import Data.Word (Word8)
src/Text/PariPari/Internal/Class.hs view
@@ -17,6 +17,7 @@ import Control.Monad (MonadPlus(..)) import Control.Monad.Fail (MonadFail(..)) import Data.List (intercalate)+import Data.Semigroup ((<>)) import Data.String (IsString) import Data.Word (Word8) import GHC.Generics (Generic)@@ -89,7 +90,7 @@ -- | Parse a single element element :: Element k -> p (Element k) - -- | Scan a single byte+ -- | Scan a single element elementScan :: (Element k -> Maybe a) -> p a -- | Parse a chunk of elements. The chunk must not@@ -120,11 +121,11 @@ -- since it is used as decoding sentinel. Use 'element' instead. asciiByte :: Word8 -> p Word8 - -- | Parse a single character within the ASCII charset with the given predicate+ -- | Scan a single character within the ASCII charset -- -- __Note__: The character '\0' cannot be parsed using this combinator- -- since it is used as decoding sentinel. Use 'elementSatisfy' instead.- asciiSatisfy :: (Word8 -> Bool) -> p Word8+ -- since it is used as decoding sentinel. Use 'elementScan' instead.+ asciiScan :: (Word8 -> Maybe a) -> p a -- | Pretty string representation of 'Error' showError :: Error -> String
src/Text/PariPari/Internal/ElementCombinators.hs view
@@ -55,14 +55,15 @@ , takeElementsWhile , skipElementsWhile1 , takeElementsWhile1- , scanElementsWhile- , scanElementsWhile1+ , scanElements+ , scanElements1 ) where import Control.Applicative ((<|>), empty) import Control.Monad (when) import Control.Monad.Combinators (skipCount, skipMany) import Data.Functor (void)+import Data.Semigroup ((<>)) import Prelude hiding (getLine) import Text.PariPari.Internal.Chunk import Text.PariPari.Internal.Class@@ -146,12 +147,12 @@ linefold = line <|> indented {-# INLINE linefold #-} --- | Parser a single byte different from the given one+-- | Parser a single element different from the given one notElement :: forall k p. ChunkParser k p => Element k -> p (Element k) notElement e = elementSatisfy @k (/= e) <?> "not " <> showElement @k e {-# INLINE notElement #-} --- | Parse an arbitrary byte+-- | Parse an arbitrary element anyElement :: ChunkP k (Element k) anyElement = elementSatisfy (const True) {-# INLINE anyElement #-}@@ -186,16 +187,16 @@ takeElementsWhile1 f = asChunk (skipElementsWhile1 f) {-# INLINE takeElementsWhile1 #-} --- | Parse a single byte with the given predicate+-- | Parse a single element with the given predicate elementSatisfy :: ChunkParser k p => (Element k -> Bool) -> p (Element k) elementSatisfy f = elementScan $ \e -> if f e then Just e else Nothing {-# INLINE elementSatisfy #-} -scanElementsWhile :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s-scanElementsWhile f = go+scanElements :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s+scanElements f = go where go s = (elementScan (f s) >>= go) <|> pure s-{-# INLINE scanElementsWhile #-}+{-# INLINE scanElements #-} -scanElementsWhile1 :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s-scanElementsWhile1 f s = elementScan (f s) >>= scanElementsWhile f-{-# INLINE scanElementsWhile1 #-}+scanElements1 :: ChunkParser k p => (s -> Element k -> Maybe s) -> s -> p s+scanElements1 f s = elementScan (f s) >>= scanElements f+{-# INLINE scanElements1 #-}
src/Text/PariPari/Internal/Reporter.hs view
@@ -28,6 +28,7 @@ import Data.Function (on) import Data.List (intercalate, sort, group, sortOn) import Data.List.NonEmpty (NonEmpty(..))+import Data.Semigroup as Sem import Data.String (IsString(..)) import GHC.Generics (Generic) import Text.PariPari.Internal.Chunk@@ -86,14 +87,17 @@ -> b } -instance (Chunk k, Semigroup a) => Semigroup (Reporter k a) where+instance (Chunk k, Semigroup a) => Sem.Semigroup (Reporter k a) where p1 <> p2 = (<>) <$> p1 <*> p2 {-# INLINE (<>) #-} -instance (Chunk k, Monoid a) => Monoid (Reporter k a) where+instance (Chunk k, Semigroup a, Monoid a) => Monoid (Reporter k a) where mempty = pure mempty {-# INLINE mempty #-} + mappend = (<>)+ {-# INLINE mappend #-}+ instance Chunk k => Functor (Reporter k) where fmap f p = Reporter $ \env st ok err -> unReporter p env st (ok . f) err@@ -262,12 +266,12 @@ raiseError env st err $ EExpected [show c] {-# INLINE char #-} - asciiSatisfy f = Reporter $ \env st@State{_stOff, _stLine, _stCol} ok err ->+ asciiScan f = Reporter $ \env st@State{_stOff, _stLine, _stCol} ok err -> let b = byteAt @k (_envBuf env) _stOff in if | b /= 0, b < 128,- f b ->- ok b st+ Just x <- f b ->+ ok x st { _stOff = _stOff + 1 , _stLine = if b == asc_newline then _stLine + 1 else _stLine , _stCol = if b == asc_newline then 1 else _stCol + 1@@ -276,7 +280,7 @@ raiseError env st err unexpectedEnd | otherwise -> raiseError env st err $ EUnexpected $ showByte b- {-# INLINE asciiSatisfy #-}+ {-# INLINE asciiScan #-} asciiByte 0 = error "Character '\\0' cannot be parsed because it is used as sentinel" asciiByte b
src/Text/PariPari/Internal/Tracer.hs view
@@ -9,6 +9,7 @@ , runTracer ) where +import Data.Semigroup as Sem import Data.String (IsString) import Debug.Trace (trace) import Text.PariPari.Internal.Chunk@@ -18,7 +19,7 @@ -- | Parser which prints trace messages, when backtracking occurs. newtype Tracer k a = Tracer { unTracer :: Reporter k a }- deriving (Semigroup, Monoid, Functor, Applicative, MonadPlus, Monad, Fail.MonadFail)+ deriving (Sem.Semigroup, Monoid, Functor, Applicative, MonadPlus, Monad, Fail.MonadFail) deriving instance CharChunk k => ChunkParser k (Tracer k) deriving instance CharChunk k => CharParser k (Tracer k)
test/test.hs view
@@ -82,20 +82,26 @@ s <- randomString ok (traverse char s *> eof) s () - , testCase "asciiSatisfy" $ do- ok (asciiSatisfy (== asc_a)) "abc" asc_a- ok (asciiSatisfy (== asc_a) <* eof) "a" asc_a- err (asciiSatisfy (== asc_0)) "abc"- err (asciiSatisfy (== asc_0)) ""+ , testCase "scan" $ do+ ok (scan (\c -> if c == 'a' then Just c else Nothing)) "abc" 'a'+ ok (scan (\c -> if c == 'a' then Just c else Nothing) <* eof) "a" 'a'+ err (scan (\c -> if c == 'b' then Just c else Nothing)) "abc"+ err (scan (\c -> if c == 'a' then Just c else Nothing)) "" -- because of sentinel- err (asciiSatisfy (== 0)) "\0"- err (asciiSatisfy (== 0)) ""+ err (scan (\c -> if c == '\0' then Just c else Nothing)) "\0"+ err (scan (\c -> if c == '\0' then Just c else Nothing)) "" - , testCase "asciiSatisfy-random" $ replicateM_ randomTries $ do- s <- randomAsciiString- ok (traverse (asciiSatisfy . (==) . fromIntegral . C.ord) s *> eof) s ()+ , testCase "asciiScan" $ do+ ok (asciiScan (\c -> if c == asc_a then Just c else Nothing)) "abc" asc_a+ ok (asciiScan (\c -> if c == asc_a then Just c else Nothing) <* eof) "a" asc_a+ err (asciiScan (\c -> if c == asc_0 then Just c else Nothing)) "abc"+ err (asciiScan (\c -> if c == asc_0 then Just c else Nothing)) "" + -- because of sentinel+ err (asciiScan (\c -> if c == 0 then Just c else Nothing)) "\0"+ err (asciiScan (\c -> if c == 0 then Just c else Nothing)) ""+ , testCase "asciiByte" $ do ok (asciiByte asc_a) "abc" asc_a ok (asciiByte asc_a <* eof) "a" asc_a@@ -123,6 +129,20 @@ s <- randomString ok (traverse (satisfy . (==)) s *> eof) s () + , testCase "asciiSatisfy" $ do+ ok (asciiSatisfy (== asc_a)) "abc" asc_a+ ok (asciiSatisfy (== asc_a) <* eof) "a" asc_a+ err (asciiSatisfy (== asc_0)) "abc"+ err (asciiSatisfy (== asc_0)) ""++ -- because of sentinel+ err (asciiSatisfy (== 0)) "\0"+ err (asciiSatisfy (== 0)) ""++ , testCase "asciiSatisfy-random" $ replicateM_ randomTries $ do+ s <- randomAsciiString+ ok (traverse (asciiSatisfy . (==) . fromIntegral . C.ord) s *> eof) s ()+ , testCase "string" $ do ok (string "ab") "abc" (stringToChunk "ab") err (string "bc") "abc"@@ -458,6 +478,16 @@ ok (element '\0' <* eof) "\0" '\0' err (element '\0') "" + , testCase "elementScan" $ do+ ok (elementScan (\c -> if c == 'a' then Just c else Nothing)) "abc" 'a'+ ok (elementScan (\c -> if c == 'a' then Just c else Nothing) <* eof) "a" 'a'+ err (elementScan (\c -> if c == 'b' then Just c else Nothing)) "abc"+ err (elementScan Just) ""++ -- sentinel+ ok (elementScan (\c -> if c == '\0' then Just c else Nothing)) "\0" '\0'+ ok (elementScan (\c -> if c == '\0' then Just c else Nothing) <* eof) "\0" '\0'+ , testCase "chunk" $ do ok (chunk "ab") "abc" "ab" err (chunk "bc") "abc"@@ -653,17 +683,11 @@ fraction fractionHex -CharParser:-scan--ChunkParser:-elementScan- Element Combinators:-scanElementsWhile-scanElementsWhile1+scanElements+scanElements1 Char Combinators:-scanCharsWhile-scanCharsWhile1+scanChars+scanChars1 -}