aboutsummaryrefslogtreecommitdiffhomepage
path: root/Pipes/Text/Parse.hs
diff options
context:
space:
mode:
authormichaelt <what_is_it_to_do_anything@yahoo.com>2013-10-22 18:40:23 -0400
committermichaelt <what_is_it_to_do_anything@yahoo.com>2013-10-22 18:40:23 -0400
commit7faef8bceff2440056da59920fb932b5b76f6541 (patch)
tree935ae450dad672aca4b0fda84f9993eb93ba547c /Pipes/Text/Parse.hs
parent31f41a5d197ca9f1a613f2dc684a9fa0467a0f2e (diff)
downloadtext-pipes-7faef8bceff2440056da59920fb932b5b76f6541.tar.gz
text-pipes-7faef8bceff2440056da59920fb932b5b76f6541.tar.zst
text-pipes-7faef8bceff2440056da59920fb932b5b76f6541.zip
new module names
Diffstat (limited to 'Pipes/Text/Parse.hs')
-rw-r--r--Pipes/Text/Parse.hs139
1 files changed, 139 insertions, 0 deletions
diff --git a/Pipes/Text/Parse.hs b/Pipes/Text/Parse.hs
new file mode 100644
index 0000000..8c3a13e
--- /dev/null
+++ b/Pipes/Text/Parse.hs
@@ -0,0 +1,139 @@
1-- | Parsing utilities for characterstrings, in the style of @pipes-parse@
2
3module Pipes.Text.Parse (
4 -- * Parsers
5 nextChar,
6 drawChar,
7 unDrawChar,
8 peekChar,
9 isEndOfChars,
10 take,
11 takeWhile
12 ) where
13
14import Control.Monad.Trans.State.Strict (StateT, modify)
15import qualified Data.Text as T
16import Data.Text (Text)
17
18import Pipes
19import qualified Pipes.Parse as PP
20
21import Prelude hiding (take, takeWhile)
22
23{-| Consume the first character from a 'Text' stream
24
25 'next' either fails with a 'Left' if the 'Producer' has no more characters or
26 succeeds with a 'Right' providing the next byte and the remainder of the
27 'Producer'.
28-}
29nextChar
30 :: (Monad m)
31 => Producer Text m r
32 -> m (Either r (Char, Producer Text m r))
33nextChar = go
34 where
35 go p = do
36 x <- next p
37 case x of
38 Left r -> return (Left r)
39 Right (txt, p') -> case (T.uncons txt) of
40 Nothing -> go p'
41 Just (c, txt') -> return (Right (c, yield txt' >> p'))
42{-# INLINABLE nextChar #-}
43
44{-| Draw one 'Char' from the underlying 'Producer', returning 'Left' if the
45 'Producer' is empty
46-}
47drawChar :: (Monad m) => StateT (Producer Text m r) m (Either r Char)
48drawChar = do
49 x <- PP.draw
50 case x of
51 Left r -> return (Left r)
52 Right txt -> case (T.uncons txt) of
53 Nothing -> drawChar
54 Just (c, txt') -> do
55 PP.unDraw txt'
56 return (Right c)
57{-# INLINABLE drawChar #-}
58
59-- | Push back a 'Char' onto the underlying 'Producer'
60unDrawChar :: (Monad m) => Char -> StateT (Producer Text m r) m ()
61unDrawChar c = modify (yield (T.singleton c) >>)
62{-# INLINABLE unDrawChar #-}
63
64{-| 'peekChar' checks the first 'Char' in the stream, but uses 'unDrawChar' to
65 push the 'Char' back
66
67> peekChar = do
68> x <- drawChar
69> case x of
70> Left _ -> return ()
71> Right c -> unDrawChar c
72> return x
73-}
74peekChar :: (Monad m) => StateT (Producer Text m r) m (Either r Char)
75peekChar = do
76 x <- drawChar
77 case x of
78 Left _ -> return ()
79 Right c -> unDrawChar c
80 return x
81{-# INLINABLE peekChar #-}
82
83{-| Check if the underlying 'Producer' has no more characters
84
85 Note that this will skip over empty 'Text' chunks, unlike
86 'PP.isEndOfInput' from @pipes-parse@.
87
88> isEndOfChars = liftM isLeft peekChar
89-}
90isEndOfChars :: (Monad m) => StateT (Producer Text m r) m Bool
91isEndOfChars = do
92 x <- peekChar
93 return (case x of
94 Left _ -> True
95 Right _ -> False )
96{-# INLINABLE isEndOfChars #-}
97
98{-| @(take n)@ only allows @n@ characters to pass
99
100 Unlike 'take', this 'PP.unDraw's unused characters
101-}
102take :: (Monad m, Integral a) => a -> Pipe Text Text (StateT (Producer Text m r) m) ()
103take n0 = go n0 where
104 go n
105 | n <= 0 = return ()
106 | otherwise = do
107 txt <- await
108 let len = fromIntegral (T.length txt)
109 if (len > n)
110 then do
111 let n' = fromIntegral n
112 lift . PP.unDraw $ T.drop n' txt
113 yield $ T.take n' txt
114 else do
115 yield txt
116 go (n - len)
117{-# INLINABLE take #-}
118
119{-| Take characters until they fail the predicate
120
121 Unlike 'takeWhile', this 'PP.unDraw's unused characters
122-}
123takeWhile
124 :: (Monad m)
125 => (Char -> Bool)
126 -> Pipe Text Text (StateT (Producer Text m r) m) ()
127takeWhile predicate = go
128 where
129 go = do
130 txt <- await
131 let (prefix, suffix) = T.span predicate txt
132 if (T.null suffix)
133 then do
134 yield txt
135 go
136 else do
137 lift $ PP.unDraw suffix
138 yield prefix
139{-# INLINABLE takeWhile #-}