@@ -28,6 +28,8 @@ module Data.ParserCombinators.Attoparsec.Internal
2828
2929 -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
3030 , try
31+ , many
32+ , many1
3133 , manyTill
3234 , eof
3335 , skipMany
@@ -52,6 +54,7 @@ module Data.ParserCombinators.Attoparsec.Internal
5254 -- * Miscellaneous functions.
5355 , getInput
5456 , getConsumed
57+ , setInput
5558 , takeWhile
5659 , takeWhile1
5760 , takeTill
@@ -59,6 +62,7 @@ module Data.ParserCombinators.Attoparsec.Internal
5962 , skipWhile
6063 , notEmpty
6164 , match
65+ , endOfLine
6266 ) where
6367
6468import Control.Applicative (Alternative(..), Applicative(..), (<$>))
@@ -66,13 +70,20 @@ import Control.Monad (MonadPlus(..), ap, liftM2)
6670import Control.Monad.Fix (MonadFix(..))
6771import qualified Data.ByteString as SB
6872import qualified Data.ByteString.Lazy as LB
69−import qualified Data.ByteString.Lazy.Internal as I
73+import qualified Data.ByteString.Lazy.Char8 as L8
74+import qualified Data.ByteString.Unsafe as U
75+import qualified Data.ByteString.Internal as I
76+import qualified Data.ByteString.Lazy.Internal as LB
7077import Data.Int (Int64)
7178import Data.Word (Word8)
7279import Prelude hiding (takeWhile)
7380
7481type ParseError = String
7582
83+-- State invariants:
84+-- * If the strict bytestring is empty, the entire input is considered
85+-- to be empty.
86+-- * Otherwise, the strict bytestring must not be empty.
7687data S = S {-# UNPACK #-} !SB.ByteString
7788 LB.ByteString
7889 {-# UNPACK #-} !Int64
@@ -132,14 +143,14 @@ instance Alternative Parser where
132143
133144mkState :: LB.ByteString -> Int64 -> S
134145mkState s = case s of
135− I.Empty -> S SB.empty s
136− I.Chunk x xs -> S x xs
146+ LB.Empty -> S SB.empty s
147+ LB.Chunk x xs -> S x xs
137148
138149-- | Turn our chunked representation back into a normal lazy
139150-- ByteString.
140151(+:) :: SB.ByteString -> LB.ByteString -> LB.ByteString
141152sb +: lb | SB.null sb = lb
142− | otherwise = I.Chunk sb lb
153+ | otherwise = LB.Chunk sb lb
143154{-# INLINE (+:) #-}
144155
145156infix 0 <?>
@@ -156,13 +167,17 @@ p <?> msg =
156167nextChunk :: Parser ()
157168nextChunk = Parser $ \(S _ lb n) ->
158169 case lb of
159− I.Chunk sb' lb' -> Right ((), S sb' lb' n)
160− I.Empty -> Left (lb, [])
170+ LB.Chunk sb' lb' -> Right ((), S sb' lb' n)
171+ LB.Empty -> Left (lb, [])
161172
162173-- | Get remaining input.
163174getInput :: Parser LB.ByteString
164175getInput = Parser $ \s@(S sb lb _) -> Right (sb +: lb, s)
165176
177+-- | Set the remaining input.
178+setInput :: LB.ByteString -> Parser ()
179+setInput bs = Parser $ \(S _ _ n) -> Right ((), mkState bs n)
180+
166181-- | Get number of bytes consumed so far.
167182getConsumed :: Parser Int64
168183getConsumed = Parser $ \s@(S _ _ n) -> Right (n, s)
@@ -202,12 +217,24 @@ string :: LB.ByteString -> Parser LB.ByteString
202217string s = Parser $ \(S sb lb n) ->
203218 let bs = sb +: lb
204219 l = LB.length s
205− (h, t) = LB.splitAt l bs
220+ (h,t) = LB.splitAt l bs
206221 in if s == h
207222 then Right (s, mkState t (n + l))
208223 else Left (bs, [])
209224{-# INLINE string #-}
210225
226+endOfLine :: Parser ()
227+endOfLine = Parser $ \(S sb lb n) ->
228+ let bs = sb +: lb
229+ in case I.w2c (U.unsafeHead sb) of
230+ '\n' -> Right ((), mkState (LB.tail bs) (n + 1))
231+ '\r' -> let (h,t) = LB.splitAt 2 bs
232+ rn = L8.pack "\r\n"
233+ in if h == rn
234+ then Right ((), mkState t (n + 2))
235+ else Right ((), mkState (LB.tail bs) (n + 1))
236+ _ -> Left (bs, ["EOL"])
237+
211238-- | Satisfy a literal string, after applying a transformation to both
212239-- it and the matching text.
213240stringTransform :: (LB.ByteString -> LB.ByteString) -> LB.ByteString
@@ -255,7 +282,7 @@ takeWhile p =
255282takeTill :: (Word8 -> Bool) -> Parser LB.ByteString
256283takeTill p =
257284 Parser $ \(S sb lb n) ->
258− case LB.span (not . p) (sb +: lb) of
285+ case LB.break p (sb +: lb) of
259286 (h,t) | LB.null t -> Left (h, [])
260287 | otherwise -> Right (h, mkState t (n + LB.length h))
261288{-# INLINE takeTill #-}
@@ -277,6 +304,12 @@ manyTill :: Parser a -> Parser b -> Parser [a]
277304manyTill p end = scan
278305 where scan = (end >> return []) <|> liftM2 (:) p scan
279306
307+many :: Parser a -> Parser [a]
308+many p = ((:) <$> p <*> many p) <|> return []
309+
310+many1 :: Parser a -> Parser [a]
311+many1 p = (:) <$> p <*> many p
312+
280313-- |'skipMany' - skip zero or many instances of the parser
281314skipMany :: Parser a -> Parser ()
282315skipMany p = scan