1 -- | Parsing utilities for texts, in the style of @pipes-parse@ and @Pipes.ByteString.Parse@
3 module Pipes.Text.Parse (
14 import Control.Monad.Trans.State.Strict (StateT, modify)
15 import qualified Data.Text as T
16 import Data.Text (Text)
19 import qualified Pipes.Parse as PP
21 import Prelude hiding (take, takeWhile)
23 {-| Consume the first character from a 'Text' stream
25 'next' either fails with a 'Left' if the 'Producer' has no more characters or
26 succeeds with a 'Right' providing the next character and the remainder of the
32 -> m (Either r (Char, Producer Text m r))
38 Left r -> return (Left r)
39 Right (txt, p') -> case (T.uncons txt) of
41 Just (c, txt') -> return (Right (c, yield txt' >> p'))
42 {-# INLINABLE nextChar #-}
44 {-| Draw one 'Char' from the underlying 'Producer', returning 'Nothing' if the
47 drawChar :: (Monad m) => StateT (Producer Text m r) m (Maybe Char)
51 Nothing -> return Nothing
52 Just txt -> case (T.uncons txt) of
57 {-# INLINABLE drawChar #-}
59 -- | Push back a 'Char' onto the underlying 'Producer'
60 unDrawChar :: (Monad m) => Char -> StateT (Producer Text m r) m ()
61 unDrawChar c = modify (yield (T.singleton c) >>)
62 {-# INLINABLE unDrawChar #-}
64 {-| 'peekChar' checks the first 'Char' in the stream, but uses 'unDrawChar' to
71 > Right c -> unDrawChar c
74 peekChar :: (Monad m) => StateT (Producer Text m r) m (Maybe Char)
79 Just c -> unDrawChar c
81 {-# INLINABLE peekChar #-}
83 {-| Check if the underlying 'Producer' has no more characters
85 Note that this will skip over empty 'Text' chunks, unlike
86 'PP.isEndOfInput' from @pipes-parse@.
88 > isEndOfChars = liftM isLeft peekChar
90 isEndOfChars :: (Monad m) => StateT (Producer Text m r) m Bool
96 {-# INLINABLE isEndOfChars #-}
98 {-| @(take n)@ only allows @n@ characters to pass
100 Unlike 'take', this 'PP.unDraw's unused characters
102 take :: (Monad m, Integral a) => a -> Pipe Text Text (StateT (Producer Text m r) m) ()
103 take n0 = go n0 where
108 let len = fromIntegral (T.length txt)
111 let n' = fromIntegral n
112 lift . PP.unDraw $ T.drop n' txt
113 yield $ T.take n' txt
117 {-# INLINABLE take #-}
119 {-| Take characters until they fail the predicate
121 Unlike 'takeWhile', this 'PP.unDraw's unused characters
126 -> Pipe Text Text (StateT (Producer Text m r) m) ()
127 takeWhile predicate = go
131 let (prefix, suffix) = T.span predicate txt
137 lift $ PP.unDraw suffix
139 {-# INLINABLE takeWhile #-}