Bryan O'Sullivan avatar Bryan O'Sullivan committed 991ca29 Merge

Merge pull request #29 from tibbe/strict-combinators

Strict versions of list-producing combinators

Comments (0)

Files changed (1)

Data/Attoparsec/Combinator.hs

       choice
     , count
     , option
+    , many'
     , many1
+    , many1'
     , manyTill
+    , manyTill'
     , sepBy
+    , sepBy'
     , sepBy1
+    , sepBy1'
     , skipMany
     , skipMany1
     , eitherP
 {-# SPECIALIZE option :: a -> Z.Parser a -> Z.Parser a #-}
 #endif
 
+-- | @many' p@ applies the action @p@ /zero/ or more times. Returns a
+-- list of the returned values of @p@. The value returned by @p@ is
+-- forced to WHNF.
+--
+-- >  word  = many' letter
+many' :: (Alternative f, Monad f) => f a -> f [a]
+many' p = many_p
+  where many_p = some_p <|> pure []
+        some_p = do
+            !a <- p
+            as <- many_p
+            return (a : as)
+{-# INLINE many' #-}
+
 -- | @many1 p@ applies the action @p@ /one/ or more times. Returns a
 -- list of the returned values of @p@.
 --
 many1 p = liftA2 (:) p (many p)
 {-# INLINE many1 #-}
 
+-- | @many1' p@ applies the action @p@ /one/ or more times. Returns a
+-- list of the returned values of @p@. The value returned by @p@ is
+-- forced to WHNF.
+--
+-- >  word  = many1' letter
+many1' :: (Alternative f, Monad f) => f a -> f [a]
+many1' p = do
+    !a <- p
+    as <- many' p
+    return (a : as)
+{-# INLINE many1' #-}
+
 -- | @sepBy p sep@ applies /zero/ or more occurrences of @p@, separated
 -- by @sep@. Returns a list of the values returned by @p@.
 --
 {-# SPECIALIZE sepBy :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-}
 #endif
 
+-- | @sepBy' p sep@ applies /zero/ or more occurrences of @p@, separated
+-- by @sep@. Returns a list of the values returned by @p@. The value
+-- returned by @p@ is forced to WHNF.
+--
+-- > commaSep p  = p `sepBy'` (symbol ",")
+sepBy' :: (Alternative f, Monad f) => f a -> f s -> f [a]
+sepBy' p s = scan <|> pure []
+  where
+    scan = do
+        !a <- p
+        as <- (s *> sepBy1' p s) <|> pure []
+        return (a : as)
+#if __GLASGOW_HASKELL__ >= 700
+{-# SPECIALIZE sepBy' :: Parser ByteString a -> Parser ByteString s
+                      -> Parser ByteString [a] #-}
+{-# SPECIALIZE sepBy' :: Parser Text a -> Parser Text s -> Parser Text [a] #-}
+{-# SPECIALIZE sepBy' :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-}
+#endif
+
 -- | @sepBy1 p sep@ applies /one/ or more occurrences of @p@, separated
 -- by @sep@. Returns a list of the values returned by @p@.
 --
--- > commaSep p  = p `sepBy` (symbol ",")
+-- > commaSep p  = p `sepBy1` (symbol ",")
 sepBy1 :: Alternative f => f a -> f s -> f [a]
 sepBy1 p s = scan
     where scan = liftA2 (:) p ((s *> scan) <|> pure [])
 {-# SPECIALIZE sepBy1 :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-}
 #endif
 
+-- | @sepBy1' p sep@ applies /one/ or more occurrences of @p@, separated
+-- by @sep@. Returns a list of the values returned by @p@. The value
+-- returned by @p@ is forced to WHNF.
+--
+-- > commaSep p  = p `sepBy1'` (symbol ",")
+sepBy1' :: (Alternative f, Monad f) => f a -> f s -> f [a]
+sepBy1' p s = scan
+    where scan = do !a <- p
+                    as <- (s *> scan) <|> pure []
+                    return (a : as)
+#if __GLASGOW_HASKELL__ >= 700
+{-# SPECIALIZE sepBy1' :: Parser ByteString a -> Parser ByteString s
+                       -> Parser ByteString [a] #-}
+{-# SPECIALIZE sepBy1' :: Parser Text a -> Parser Text s -> Parser Text [a] #-}
+{-# SPECIALIZE sepBy1' :: Z.Parser a -> Z.Parser s -> Z.Parser [a] #-}
+#endif
+
 -- | @manyTill p end@ applies action @p@ /zero/ or more times until
 -- action @end@ succeeds, and returns the list of values returned by
 -- @p@.  This can be used to scan comments:
 {-# SPECIALIZE manyTill :: Z.Parser a -> Z.Parser b -> Z.Parser [a] #-}
 #endif
 
+-- | @manyTill' p end@ applies action @p@ /zero/ or more times until
+-- action @end@ succeeds, and returns the list of values returned by
+-- @p@.  This can be used to scan comments:
+--
+-- >  simpleComment   = string "<!--" *> manyTill' anyChar (try (string "-->"))
+--
+-- Note the overlapping parsers @anyChar@ and @string \"<!--\"@, and
+-- therefore the use of the 'try' combinator. The value returned by @p@
+-- is forced to WHNF.
+manyTill' :: (Alternative f, Monad f) => f a -> f b -> f [a]
+manyTill' p end = scan
+    where scan = (end *> pure []) <|> scan'
+          scan' = do
+              !a <- p
+              as <- scan
+              return (a : as)
+#if __GLASGOW_HASKELL__ >= 700
+{-# SPECIALIZE manyTill' :: Parser ByteString a -> Parser ByteString b
+                         -> Parser ByteString [a] #-}
+{-# SPECIALIZE manyTill' :: Parser Text a -> Parser Text b -> Parser Text [a] #-}
+{-# SPECIALIZE manyTill' :: Z.Parser a -> Z.Parser b -> Z.Parser [a] #-}
+#endif
+
 -- | Skip zero or more instances of an action.
 skipMany :: Alternative f => f a -> f ()
 skipMany p = scan
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.