bytesmith 0.3.1.0 → 0.3.2.0
raw patch · 3 files changed
+113/−3 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Bytes.Parser: parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a
+ Data.Bytes.Parser: parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a
+ Data.Bytes.Parser: peek :: Parser e s (Maybe Word8)
+ Data.Bytes.Parser: peek' :: e -> Parser e s Word8
+ Data.Bytes.Parser: satisfy :: e -> (Word8 -> Bool) -> Parser e s Word8
+ Data.Bytes.Parser: satisfyWith :: e -> (Word8 -> a) -> (a -> Bool) -> Parser e s a
+ Data.Bytes.Parser: scan :: state -> (state -> Word8 -> Maybe state) -> Parser e s state
Files
- CHANGELOG.md +6/−0
- bytesmith.cabal +2/−2
- src/Data/Bytes/Parser.hs +105/−1
CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for bytesmith +## 0.3.2.0 -- 2019-??-??++* Add `parseBytesEither` and `parseBytesMaybe`.+* Add common idioms from other parser libaries. This includes: `satisfy`,+ `satisfyWith`, `scan`, `peek`, and `peek'`.+ ## 0.3.1.0 -- 2019-11-12 * Add big-endian and little-endian parsers for `Word128`.
bytesmith.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: bytesmith-version: 0.3.1.0+version: 0.3.2.0 synopsis: Nonresumable byte parser description: Parse bytes as fast as possible. This is a nonresumable parser@@ -31,7 +31,7 @@ build-depends: , base >=4.12 && <5 , bytestring >=0.10.8 && <0.11- , byteslice >=0.1.3 && <0.2+ , byteslice >=0.1.3 && <0.3 , contiguous >= 0.4 && < 0.6 , primitive >=0.7 && <0.8 , text-short >=0.1.3 && <0.2
src/Data/Bytes/Parser.hs view
@@ -26,9 +26,12 @@ , Result(..) , Slice(..) -- * Run Parsers+ -- ** Result , parseByteArray , parseBytes , parseBytesEffectfully+ , parseBytesEither+ , parseBytesMaybe -- * One Byte , any -- * Many Bytes@@ -41,10 +44,17 @@ -- * Match , byteArray , bytes+ , satisfy+ , satisfyWith -- * End of Input , endOfInput , isEndOfInput , remaining+ -- * Scanning+ , scan+ -- * Lookahead+ , peek+ , peek' -- * Control Flow , fail , orElse@@ -99,7 +109,7 @@ import qualified Data.Primitive as PM import qualified Data.Primitive.Contiguous as C --- | Parse a slice of a byte array. This can succeed even if the+-- | Parse a byte sequence. This can succeed even if the -- entire slice was not consumed by the parser. parseBytes :: forall e a. (forall s. Parser e s a) -> Bytes -> Result e a parseBytes p !b = runResultST action@@ -108,6 +118,38 @@ action s0 = case p @s of Parser f -> f (unboxBytes b) s0 +-- | Variant of 'parseBytesEither' that discards the error message on failure.+-- Just like 'parseBytesEither', this does not impose any checks on the length+-- of the remaining input.+parseBytesMaybe :: forall e a. (forall s. Parser e s a) -> Bytes -> Maybe a+parseBytesMaybe p !b = runMaybeST action+ where+ action :: forall s. ST# s (Result# e a)+ action s0 = case p @s of+ Parser f -> f (unboxBytes b) s0++-- | Variant of 'parseBytes' that discards the new offset and the+-- remaining length. This does not, however, require the remaining+-- length to be zero. Use 'endOfInput' to accomplish that.+parseBytesEither :: forall e a. (forall s. Parser e s a) -> Bytes -> Either e a+parseBytesEither p !b = runEitherST action+ where+ action :: forall s. ST# s (Result# e a)+ action s0 = case p @s of+ Parser f -> f (unboxBytes b) s0++-- Similar to runResultST+runMaybeST :: (forall s. ST# s (Result# e x)) -> Maybe x+runMaybeST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of+ (# _ | #) -> Nothing+ (# | (# x, _, _ #) #) -> Just x++-- Similar to runResultST+runEitherST :: (forall s. ST# s (Result# e x)) -> Either e x+runEitherST f = case (runRW# (\s0 -> case f s0 of { (# _, r #) -> r })) of+ (# e | #) -> Left e+ (# | (# x, _, _ #) #) -> Right x+ -- This is used internally to help reduce boxing when a parser -- gets run. Due to the late inlining of runRW#, this variant -- of runST still cause the result value to be boxed. However,@@ -172,6 +214,49 @@ in InternalSuccess w (offset chunk + 1) (length chunk - 1) else InternalFailure e +-- | Match any byte, to perform lookahead. Returns 'Nothing' if+-- end of input has been reached. Does not consume any input.+--+-- /Note/: Because this parser does not fail, do not use it+-- with combinators such as 'many', because such as 'many',+-- because such parsers loop until a failure occurs. Careless+-- use will thus result in an infinite loop.+peek :: Parser e s (Maybe Word8)+peek = uneffectful $ \chunk ->+ let v = if length chunk > 0+ then Just (B.unsafeIndex chunk 1)+ else Nothing+ in InternalSuccess v (offset chunk) (length chunk)++-- | Match any byte, to perform lookahead. Does not consume any+-- input, but will fail if end of input has been reached.+peek' :: e -> Parser e s Word8+peek' e = uneffectful $ \chunk -> if length chunk > 0+ then InternalSuccess (B.unsafeIndex chunk 1) (offset chunk) (length chunk)+ else InternalFailure e++-- | A stateful scanner. The predicate consumes and transforms a+-- state argument, and each transformed state is passed to+-- successive invocations of the predicate on each byte of the input+-- until one returns 'Nothing' or the input ends.+--+-- This parser does not fail. It will return the initial state+-- if the predicate returns 'Nothing' on the first byte of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such a 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+scan :: state -> (state -> Word8 -> Maybe state) -> Parser e s state+scan s0 t = do+ let go s = do+ mw <- peek+ case mw of+ Nothing -> pure s+ Just w -> case t s w of+ Just s' -> go s'+ Nothing -> pure s+ go s0+ -- Interpret the next byte as an ASCII-encoded character. -- Does not check to see if any characters are left. This -- is not exported.@@ -246,6 +331,25 @@ then go else unconsume 1 +-- | The parser @satisfy p@ succeeds for any byte for which the+-- predicate @p@ returns 'True'. Returns the byte that is+-- actually parsed.+satisfy :: e -> (Word8 -> Bool) -> Parser e s Word8+satisfy e p = satisfyWith e id p+{-# inline satisfy #-}++-- | The parser @satisfyWith f p@ transforms a byte, and succeeds+-- if the predicate @p@ returns 'True' on the transformed value.+-- The parser returns the transformed byte that was parsed.+satisfyWith :: e -> (Word8 -> a) -> (a -> Bool) -> Parser e s a+satisfyWith e f p = uneffectful $ \chunk -> if length chunk > 1+ then case B.unsafeIndex chunk 1 of+ w ->+ let v = f w+ in if p v+ then InternalSuccess v (offset chunk + 1) (length chunk - 1)+ else InternalFailure e+ else InternalFailure e -- | Fails if there is still more input remaining. endOfInput :: e -> Parser e s ()