Commits

tibbe committed 037f444

Add peekWord8/peekChar

  • Participants
  • Parent commits 061d833

Comments (0)

Files changed (7)

File Data/Attoparsec/ByteString.hs

     , I.word8
     , I.anyWord8
     , I.notWord8
+    , I.peekWord8
     , I.satisfy
     , I.satisfyWith
     , I.skip

File Data/Attoparsec/ByteString/Char8.hs

     , char8
     , anyChar
     , notChar
+    , peekChar
     , satisfy
 
     -- ** Special character parsers
 anyChar = satisfy $ const True
 {-# INLINE anyChar #-}
 
+-- | Match any character. 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 parsers loop until a
+-- failure occurs.  Careless use will thus result in an infinite loop.
+peekChar :: Parser (Maybe Char)
+peekChar = (fmap w2c) `fmap` I.peekWord8
+{-# INLINE peekChar #-}
+
 -- | Fast predicate for matching ASCII space characters.
 --
 -- /Note/: This predicate only gives correct answers for the ASCII

File Data/Attoparsec/ByteString/Internal.hs

     , skip
     , word8
     , notWord8
+    , peekWord8
 
     -- ** Byte classes
     , inClass
 notWord8 c = satisfy (/= c) <?> "not " ++ show c
 {-# INLINE notWord8 #-}
 
+-- | Match any byte. 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 parsers loop until a
+-- failure occurs.  Careless use will thus result in an infinite loop.
+peekWord8 :: Parser (Maybe Word8)
+peekWord8 = T.Parser $ \i0 a0 m0 _kf ks ->
+            let ks' i a m = let w = B.unsafeHead (unI i)
+                            in w `seq` ks i a m (Just w)
+                kf' i a m = ks i a m Nothing
+            in if B.null (unI i0)
+               then prompt i0 a0 m0 kf' ks'
+               else ks' i0 a0 m0
+{-# INLINE peekWord8 #-}
+
 -- | Match only if all input has been consumed.
 endOfInput :: Parser ()
 endOfInput = T.Parser $ \i0 a0 m0 kf ks ->

File Data/Attoparsec/Text.hs

     , I.satisfy
     , I.satisfyWith
     , I.skip
+    , I.peekChar
 
     -- ** Special character parsers
     , digit

File Data/Attoparsec/Text/Internal.hs

     , skip
     , char
     , notChar
+    , peekChar
 
     -- ** Character classes
     , inClass
 notChar c = satisfy (/= c) <?> "not " ++ show c
 {-# INLINE notChar #-}
 
+-- | Match any character. 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 parsers loop until a
+-- failure occurs.  Careless use will thus result in an infinite loop.
+peekChar :: Parser (Maybe Char)
+peekChar = T.Parser $ \i0 a0 m0 _kf ks ->
+       let ks' i a m = let w = unsafeHead (unI i)
+                       in w `seq` ks i a m (Just w)
+           kf' i a m = ks i a m Nothing
+       in if T.null (unI i0)
+          then prompt i0 a0 m0 kf' ks'
+          else ks' i0 a0 m0
+{-# INLINE peekChar #-}
+
 -- | Match only if all input has been consumed.
 endOfInput :: Parser ()
 endOfInput = T.Parser $ \i0 a0 m0 kf ks ->

File tests/QC/ByteString.hs

 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module QC.ByteString (tests) where
 
-import Control.Applicative ((<$>))
+import Control.Applicative ((<$>), (<*>))
 import Prelude hiding (takeWhile)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 import Test.QuickCheck
     where v = L.head bs
           bs = L.pack s
 
+peekWord8 s
+    | L.null s  = p == Just (Nothing, s)
+    | otherwise = p == Just (Just (L.head s), s)
+  where p = maybeP ((,) <$> P.peekWord8 <*> P.takeLazyByteString) s
+
 string s t = maybeP (P.string s') (s `L.append` t) == Just s'
   where s' = toStrict s
 
     testProperty "word8" word8,
     testProperty "notWord8" notWord8,
     testProperty "anyWord8" anyWord8,
+    testProperty "peekWord8" peekWord8,
     testProperty "string" string,
     testProperty "skipWhile" skipWhile,
     testProperty "takeCount" takeCount,

File tests/QC/Text.hs

 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module QC.Text (tests) where
 
-import Control.Applicative ((<$>))
+import Control.Applicative ((<$>), (<*>))
 import Prelude hiding (takeWhile)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 import Test.QuickCheck
     where v = L.head bs
           bs = L.pack s
 
+peekChar s
+    | L.null s  = p == Just (Nothing, s)
+    | otherwise = p == Just (Just (L.head s), s)
+  where p = maybeP ((,) <$> P.peekChar <*> P.takeLazyText) s
+
 string s t = maybeP (P.string s') (s `L.append` t) == Just s'
   where s' = toStrict s
 
     testProperty "char" char,
     testProperty "notChar" notChar,
     testProperty "anyChar" anyChar,
+    testProperty "peekChar" peekChar,
     testProperty "string" string,
     testProperty "stringCI" stringCI,
     testProperty "skipWhile" skipWhile,