@@ -65,14 +65,14 @@ module Data.Attoparsec.Text.Internal
68−import Control.Applicative ((<|>), (<$>))
68+import Control.Applicative ((<|>), (<$>), pure, (*>))
69import Control.Monad (when)
69import Control.Monad (when)
70import Data.Attoparsec.Combinator ((<?>))
70import Data.Attoparsec.Combinator ((<?>))
71import Data.Attoparsec.Internal
71import Data.Attoparsec.Internal
72import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success)
72import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success)
73import qualified Data.Attoparsec.Text.Buffer as Buf
73import qualified Data.Attoparsec.Text.Buffer as Buf
74import Data.Attoparsec.Text.Buffer (Buffer, buffer)
74import Data.Attoparsec.Text.Buffer (Buffer, buffer)
75−import Data.Char (chr, ord)
75+import Data.Char (isAsciiUpper, isAsciiLower, toUpper, toLower)
76import Data.List (intercalate)
76import Data.List (intercalate)
77import Data.String (IsString(..))
77import Data.String (IsString(..))
78import Data.Text.Internal (Text(..))
78import Data.Text.Internal (Text(..))
@@ -222,15 +222,16 @@ stringCI s = go 0
223-- | Satisfy a literal string, ignoring case for characters in the ASCII range.
223-- | Satisfy a literal string, ignoring case for characters in the ASCII range.
224asciiCI :: Text -> Parser Text
224asciiCI :: Text -> Parser Text
225−asciiCI s = string_ (stringSuspended asciiToLower) asciiToLower s
225+asciiCI s = fmap fst $ match $ T.foldr ((*>) . asciiCharCI) (pure ()) s
227− asciiToLower = T.map f
229− offset = ord 'a' - ord 'A'
230− f c | 'A' <= c && c <= 'Z' = chr (ord c + offset)
232{-# INLINE asciiCI #-}
226{-# INLINE asciiCI #-}
228+asciiCharCI :: Char -> Parser Char
230+ | isAsciiUpper c = char c <|> char (toLower c)
231+ | isAsciiLower c = char c <|> char (toUpper c)
232+ | otherwise = char c
233+{-# INLINE asciiCharCI #-}
234-- | Skip past input for as long as the predicate returns 'True'.
235-- | Skip past input for as long as the predicate returns 'True'.
235skipWhile :: (Char -> Bool) -> Parser ()
236skipWhile :: (Char -> Bool) -> Parser ()
236skipWhile p = go
237skipWhile p = go
@@ -266,14 +267,25 @@ takeTill p = takeWhile (not . p)
266-- parsers loop until a failure occurs. Careless use will thus result
267-- parsers loop until a failure occurs. Careless use will thus result
267-- in an infinite loop.
268-- in an infinite loop.
268takeWhile :: (Char -> Bool) -> Parser Text
269takeWhile :: (Char -> Bool) -> Parser Text
269−takeWhile p = (T.concat . reverse) `fmap` go []
270+takeWhile p = do
271+ h <- T.takeWhile p <$> get
272+ continue <- inputSpansChunks (size h)
273+ -- only use slow concat path if necessary
275+ then takeWhileAcc p [h]
277+{-# INLINE takeWhile #-}
279+takeWhileAcc :: (Char -> Bool) -> [Text] -> Parser Text
271 go acc = do
282 go acc = do
272 h <- T.takeWhile p <$> get
283 h <- T.takeWhile p <$> get
273 continue <- inputSpansChunks (size h)
284 continue <- inputSpansChunks (size h)
274 if continue
285 if continue
275 then go (h:acc)
286 then go (h:acc)
276− else return (h:acc)
287+ else return $ concatReverse (h:acc)
288+{-# INLINE takeWhileAcc #-}
278takeRest :: Parser [Text]
290takeRest :: Parser [Text]
279takeRest = go []
291takeRest = go []
@@ -296,7 +308,7 @@ takeLazyText :: Parser L.Text
296takeLazyText = L.fromChunks `fmap` takeRest
308takeLazyText = L.fromChunks `fmap` takeRest
298data Scan s = Continue s
310data Scan s = Continue s
299− | Finished {-# UNPACK #-} !Int Text
311+ | Finished s {-# UNPACK #-} !Int Text
301scan_ :: (s -> [Text] -> Parser r) -> s -> (s -> Char -> Maybe s) -> Parser r
313scan_ :: (s -> [Text] -> Parser r) -> s -> (s -> Char -> Maybe s) -> Parser r
302scan_ f s0 p = go [] s0
314scan_ f s0 p = go [] s0
@@ -305,7 +317,7 @@ scan_ f s0 p = go [] s0
305 case T.uncons t of
317 case T.uncons t of
306 Just (c,t') -> case p s c of
318 Just (c,t') -> case p s c of
307 Just s' -> scanner s' (n+1) t'
319 Just s' -> scanner s' (n+1) t'
308− Nothing -> Finished n t
320+ Nothing -> Finished s n t
309 Nothing -> Continue s
321 Nothing -> Continue s
310 go acc s = do
322 go acc s = do
311 input <- get
323 input <- get
@@ -314,8 +326,8 @@ scan_ f s0 p = go [] s0
314 if continue
326 if continue
315 then go (input : acc) s'
327 then go (input : acc) s'
316 else f s' (input : acc)
328 else f s' (input : acc)
317− Finished n t -> do advance (size input - size t)
329+ Finished s' n t -> do advance (size input - size t)
318− f s (T.take n input : acc)
330+ f s' (T.take n input : acc)
319{-# INLINE scan_ #-}
331{-# INLINE scan_ #-}
321-- | A stateful scanner. The predicate consumes and transforms a
333-- | A stateful scanner. The predicate consumes and transforms a
@@ -331,16 +343,13 @@ scan_ f s0 p = go [] s0
331-- parsers loop until a failure occurs. Careless use will thus result
343-- parsers loop until a failure occurs. Careless use will thus result
332-- in an infinite loop.
344-- in an infinite loop.
333scan :: s -> (s -> Char -> Maybe s) -> Parser Text
345scan :: s -> (s -> Char -> Maybe s) -> Parser Text
334−scan = scan_ $ \_ chunks ->
346+scan = scan_ $ \_ chunks -> return $! concatReverse chunks
337− xs -> return . T.concat . reverse $ xs
338{-# INLINE scan #-}
347{-# INLINE scan #-}
340-- | Like 'scan', but generalized to return the final state of the
349-- | Like 'scan', but generalized to return the final state of the
341-- scanner.
350-- scanner.
342runScanner :: s -> (s -> Char -> Maybe s) -> Parser (Text, s)
351runScanner :: s -> (s -> Char -> Maybe s) -> Parser (Text, s)
343−runScanner = scan_ $ \s xs -> return (T.concat (reverse xs), s)
352+runScanner = scan_ $ \s xs -> let !sx = concatReverse xs in return (sx, s)
344{-# INLINE runScanner #-}
353{-# INLINE runScanner #-}
346-- | Consume input as long as the predicate returns 'True', and return
355-- | Consume input as long as the predicate returns 'True', and return
@@ -358,8 +367,9 @@ takeWhile1 p = do
358 advance size'
367 advance size'
359 eoc <- endOfChunk
368 eoc <- endOfChunk
361− then (h<>) `fmap` takeWhile p
370+ then takeWhileAcc p [h]
362 else return h
371 else return h
372+{-# INLINE takeWhile1 #-}
364-- | Match any character in a set.
374-- | Match any character in a set.