Commits

Anonymous committed d3f7e47

Unified 'satisfy' for ByteString and Text.

Comments (0)

Files changed (4)

Data/Attoparsec/ByteString/Internal.hs

 -- >digit = satisfy isDigit
 -- >    where isDigit w = w >= 48 && w <= 57
 satisfy :: (Word8 -> Bool) -> Parser Word8
-satisfy p = do
-  s <- ensure 1
-  let !w = B.unsafeHead s
-  if p w
-    then put (B.unsafeTail s) >> return w
-    else fail "satisfy"
+satisfy = satisfyElem
 {-# INLINE satisfy #-}
 
 -- | The parser @skip p@ succeeds for any byte for which the predicate

Data/Attoparsec/Combinator.hs

 --
 -- Useful parser combinators, similar to those provided by Parsec.
 module Data.Attoparsec.Combinator
-    ( try
+    (
+    -- * Combinators
+      try
     , (<?>)
     , choice
     , count
     , skipMany
     , skipMany1
     , eitherP
+    -- * Parsing individual chunk elements
+    , satisfyElem
     ) where
 
 import Control.Applicative (Alternative(..), Applicative(..), empty, liftA2,
 import Control.Applicative (many)
 #endif
 
-import Data.Attoparsec.Internal.Types (Parser(..))
+import Data.Attoparsec.Internal.Types
+import Data.Attoparsec.Internal
 #if __GLASGOW_HASKELL__ >= 700
 import qualified Data.Attoparsec.Zepto as Z
 import Data.ByteString (ByteString)
 eitherP :: (Alternative f) => f a -> f b -> f (Either a b)
 eitherP a b = (Left <$> a) <|> (Right <$> b)
 {-# INLINE eitherP #-}
+
+-- | The parser @satisfyElem p@ succeeds for any chunk element for which the
+-- predicate @p@ returns 'True'. Returns the element that is
+-- actually parsed.
+--
+-- >digit = satisfyElem isDigit
+-- >    where isDigit c = c >= '0' && c <= '9'
+satisfyElem :: Chunk t => (ChunkElem t -> Bool) -> Parser t (ChunkElem t)
+satisfyElem p = do
+  c <- ensure 1
+  let !h = unsafeChunkHead c
+  if p h
+    then put (unsafeChunkTail c) >> return h
+    else fail "satisfyElem"
+{-# INLINE satisfyElem #-}

Data/Attoparsec/Internal/Types.hs

 import Data.Word (Word8)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as BS
+import qualified Data.ByteString.Unsafe as BS
 import Data.Text (Text)
 import qualified Data.Text as T
 import qualified Data.Text.Unsafe as T
   type ChunkElem c
   -- | Test if the chunk is empty.
   nullChunk :: c -> Bool
+  -- | Get the head element of a non-empty chunk.
+  unsafeChunkHead :: c -> ChunkElem c
+  -- | Get the tail of a non-empty chunk.
+  unsafeChunkTail :: c -> c
   -- | Check if the chunk has the length of at least @n@ elements.
   chunkLengthAtLeast :: c -> Int -> Bool
 
   type ChunkElem ByteString = Word8
   nullChunk = BS.null
   {-# INLINE nullChunk #-}
+  unsafeChunkHead = BS.unsafeHead
+  {-# INLINE unsafeChunkHead #-}
+  unsafeChunkTail = BS.unsafeTail
+  {-# INLINE unsafeChunkTail #-}
   chunkLengthAtLeast bs n = BS.length bs >= n
   {-# INLINE chunkLengthAtLeast #-}
 
   type ChunkElem Text = Char
   nullChunk = T.null
   {-# INLINE nullChunk #-}
+  unsafeChunkHead = T.unsafeHead
+  {-# INLINE unsafeChunkHead #-}
+  unsafeChunkTail = T.unsafeTail
+  {-# INLINE unsafeChunkTail #-}
   chunkLengthAtLeast t n = T.lengthWord16 t `quot` 2 >= n || T.length t >= n
   {-# INLINE chunkLengthAtLeast #-}

Data/Attoparsec/Text/Internal.hs

 -- >digit = satisfy isDigit
 -- >    where isDigit c = c >= '0' && c <= '9'
 satisfy :: (Char -> Bool) -> Parser Char
-satisfy p = do
-  s <- ensure 1
-  let !w = unsafeHead s
-  if p w
-    then put (unsafeTail s) >> return w
-    else fail "satisfy"
+satisfy = satisfyElem
 {-# INLINE satisfy #-}
 
 -- | The parser @skip p@ succeeds for any character for which the