@@ -18,6 +18,7 @@ module Data.Attoparsec.Internal
1818 , wantInput
1919 , endOfInput
2020 , atEnd
21+ , satisfyElem
2122 ) where
2223
2324import Control.Applicative ((<$>))
@@ -112,3 +113,43 @@ endOfInput = Parser $ \t pos more lose succ ->
112113atEnd :: Chunk t => Parser t Bool
113114atEnd = not <$> wantInput
114115{-# INLINE atEnd #-}
116+
117+satisfySuspended :: forall t r . Chunk t
118+ => (ChunkElem t -> Bool)
119+ -> State t -> Pos -> More
120+ -> Failure t (State t) r
121+ -> Success t (State t) (ChunkElem t) r
122+ -> IResult t r
123+satisfySuspended p t pos more lose succ =
124+ runParser (demandInput >> go) t pos more lose succ
125+ where go = Parser $ \t' pos' more' lose' succ' ->
126+ case bufferElemAt (undefined :: t) pos' t' of
127+ Just (e, l) | p e -> succ' t' (pos' + Pos l) more' e
128+ | otherwise -> lose' t' pos' more' [] "satisfyElem"
129+ Nothing -> runParser (demandInput >> go) t' pos' more' lose' succ'
130+#if __GLASGOW_HASKELL__ >= 700
131+{-# SPECIALIZE satisfySuspended :: (ChunkElem ByteString -> Bool)
132+ -> State ByteString -> Pos -> More
133+ -> Failure ByteString (State ByteString) r
134+ -> Success ByteString (State ByteString)
135+ (ChunkElem ByteString) r
136+ -> IResult ByteString r #-}
137+{-# SPECIALIZE satisfySuspended :: (ChunkElem Text -> Bool)
138+ -> State Text -> Pos -> More
139+ -> Failure Text (State Text) r
140+ -> Success Text (State Text)
141+ (ChunkElem Text) r
142+ -> IResult Text r #-}
143+#endif
144+
145+-- | The parser @satisfyElem p@ succeeds for any chunk element for which the
146+-- predicate @p@ returns 'True'. Returns the element that is
147+-- actually parsed.
148+satisfyElem :: forall t . Chunk t
149+ => (ChunkElem t -> Bool) -> Parser t (ChunkElem t)
150+satisfyElem p = Parser $ \t pos more lose succ ->
151+ case bufferElemAt (undefined :: t) pos t of
152+ Just (e, l) | p e -> succ t (pos + Pos l) more e
153+ | otherwise -> lose t pos more [] "satisfyElem"
154+ Nothing -> satisfySuspended p t pos more lose succ
155+{-# INLINE satisfyElem #-}