packages feed

replace-megaparsec 1.4.3.0 → 1.4.4.0

raw patch · 7 files changed

+114/−33 lines, 7 files

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for replace-megaparsec +## 1.4.4.0 -- 2020-12-04++Add `splitCapT` and `breakCapT`.+ ## 1.4.3.0 -- 2020-09-28  Bugfix sepCap backtracking when sep fails
README.md view
@@ -263,10 +263,9 @@ let editThree :: Char -> MTL.State Int String     editThree x = do         i <- get-        let i' = i+1-        if i'<=3+        if i<3             then do-                put i'+                put $ i+1                 pure [toUpper x]             else pure [x] @@ -288,7 +287,7 @@ #!/usr/bin/env stack {- stack   script-  --resolver lts-15+  --resolver lts-16   --package megaparsec   --package replace-megaparsec -}
replace-megaparsec.cabal view
@@ -1,5 +1,5 @@ name:                replace-megaparsec-version:             1.4.3.0+version:             1.4.4.0 cabal-version:       1.18 synopsis:            Find, replace, and split string patterns with Megaparsec parsers (instead of regex) homepage:            https://github.com/jamesdbrock/replace-megaparsec
src/Replace/Megaparsec.hs view
@@ -36,13 +36,10 @@ -- -- See the __replace-megaparsec__ package README for usage examples. ----- == Special accelerated inputs------ There are specialization re-write rules to speed up all functions in this--- module when the input stream type @s@ is "Data.Text" or "Data.ByteString".--- -- == Type constraints --+-- === output stream type @Tokens s@ = input stream type @s@+-- -- All functions in the __Running Parser__ section require the type of the -- stream of text that is input to be -- @'Text.Megaparsec.Stream.Stream' s@@@ -58,12 +55,32 @@ -- * "Data.ByteString" -- * "Data.ByteString.Lazy" ----- Megaparsec parsers have an error type parameter @e@. When writing parsers--- to be used by this module, the error type parameter @e@ should usually+-- === Custom error type @e@ should be 'Data.Void'+--+-- Megaparsec parsers have a custom error data component @e@. When writing parsers+-- to be used by this module, the custom error type @e@ should usually -- be 'Data.Void', because every function in this module expects a parser -- failure to occur on every token in a non-matching section of the input--- stream, so parser failure error descriptions are not returned.+-- stream, so parser failure error descriptions are not returned, and you'll+-- never see the custom error information.+--+-- == Special fast input types+--+-- Functions in this module will be “fast” when the input stream+-- type @s@ is:+--+-- * "Data.Text"+-- * "Data.ByteString"+--+-- We mean “fast” in the same sense as 'Text.Megaparsec.MonadParsec':+-- when returning subsections of the input stream,+-- we return slices of the input stream data, rather than constructing a list+-- of tokens and then building a new stream subsection from that list.+-- This relies on implementation details of the stream representation,+-- so there are specialization re-write rules in this module to make+-- that possible without adding new typeclasses. + {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-}@@ -77,16 +94,19 @@   (     -- * Running parser     ---    -- | Functions in this section are ways to run parsers. They take+    -- | Functions in this section are /ways to run parsers/+    -- (like 'Text.Megaparsec.runParser'). They take     -- as arguments a @sep@ parser and some input, run the parser on the input,     -- and return a result.     breakCap+  , breakCapT   , splitCap+  , splitCapT   , streamEdit   , streamEditT     -- * Parser combinator     ---    -- | Functions in this section are parser combinators. They take+    -- | Functions in this section are /parser combinators/. They take     -- a @sep@ parser for an argument, combine @sep@ with another parser,     -- and return a new parser.   , anyTill@@ -157,17 +177,37 @@         -- ^ The input stream of text     -> Maybe (s, a, s)         -- ^ Maybe (prefix, parse_result, suffix)-breakCap sep input =-    case runParser pser "" input of-        (Left _) -> Nothing-        (Right x) -> Just x+breakCap sep input = runIdentity $ breakCapT sep input+{-# INLINABLE breakCap #-}++-- |+-- === Break on and capture one pattern+--+-- Monad transformer version of 'breakCap'.+--+-- The parser @sep@ will run in the underlying monad context.+breakCapT+    :: forall m e s a. (Ord e, Stream s, Tokens s ~ s, Monad m)+    => ParsecT e s m a+        -- ^ The pattern matching parser @sep@+    -> s+        -- ^ The input stream of text+    -> m (Maybe (s, a, s))+        -- ^ Maybe (prefix, parse_result, suffix)+breakCapT sep input =+    runParserT pser "" input >>= \case+        (Left _) -> pure Nothing+        (Right x) -> pure $ Just x   where     pser = do       (prefix, cap) <- anyTill sep       suffix <- getInput       pure (prefix, cap, suffix)-{-# INLINABLE breakCap #-}+{-# INLINABLE breakCapT #-} +++ -- | -- === Split on and capture all patterns --@@ -199,20 +239,39 @@ -- input == 'Data.Monoid.mconcat' ('Data.Bifunctor.second' 'Data.Tuple.fst' '<$>' output) -- @ splitCap-    :: forall e s a. (Ord e, Show e, Show (Token s), Stream s, Tokens s ~ s)+    :: forall e s a. (Ord e, Stream s, Tokens s ~ s)     => Parsec e s a         -- ^ The pattern matching parser @sep@     -> s         -- ^ The input stream of text     -> [Either s a]         -- ^ List of matching and non-matching input sections.-splitCap sep input = do-    case runParser (sepCap sep) "" input of-        (Left (ParseErrorBundle errs _)) -> error (show errs) -- undefined -- sepCap can never fail-        (Right r) -> r+splitCap sep input = runIdentity $ splitCapT sep input {-# INLINABLE splitCap #-} + -- |+-- === Split on and capture all patterns+--+-- Monad transformer version of 'splitCap'.+--+-- The parser @sep@ will run in the underlying monad context.+splitCapT+    :: forall e s m a. (Ord e, Stream s, Tokens s ~ s, Monad m)+    => ParsecT e s m a+        -- ^ The pattern matching parser @sep@+    -> s+        -- ^ The input stream of text+    -> m [Either s a]+        -- ^ List of matching and non-matching input sections.+splitCapT sep input =+    runParserT (sepCap sep) "" input >>= \case+        (Left _) -> undefined -- sepCap can never fail+        (Right r) -> pure r+{-# INLINABLE splitCapT #-}+++-- | -- === Stream editor -- -- Also known as “find-and-replace”, or “match-and-substitute”. Finds all@@ -251,11 +310,11 @@ {-# INLINABLE streamEdit #-}  -- |--- === Stream editor transformer+-- === Stream editor -- -- Monad transformer version of 'streamEdit'. ----- Both the parser @sep@ and the @editor@ function run in the underlying+-- Both the parser @sep@ and the @editor@ function will run in the underlying -- monad context. -- -- If you want to do 'IO' operations in the @editor@ function or the@@ -277,7 +336,7 @@ streamEditT sep editor input = do     runParserT (sepCap sep) "" input >>= \case         (Left _) -> undefined -- sepCap can never fail-        (Right r) -> fmap mconcat $ traverse (either return editor) r+        (Right r) -> mconcat <$> traverse (either return editor) r {-# INLINABLE streamEditT #-}  -- |@@ -430,6 +489,7 @@     -> m [Either (Tokens s) (Tokens s, a)] -- ^ parser findAllCap sep = sepCap (match sep) {-# INLINABLE findAllCap #-}+{-# DEPRECATED findAllCap "replace with `findAllCap sep = sepCap (match sep)`" #-}   -- |@@ -452,3 +512,4 @@     -> m [Either (Tokens s) (Tokens s)] -- ^ parser findAll sep = (fmap.fmap) (second fst) $ sepCap (match sep) {-# INLINABLE findAll #-}+{-# DEPRECATED findAll "replace with `findAll sep = (fmap.fmap) (second fst) $ sepCap (match sep)`" #-}
tests/TestByteString.hs view
@@ -17,10 +17,13 @@  type Parser = Parsec Void B.ByteString +findAllCap' :: MonadParsec e s m => m a -> m [Either (Tokens s) (Tokens s, a)]+findAllCap' sep = sepCap (match sep)+ tests :: IO [Test] tests = return     [ Test $ runParserTest "findAll upperChar"-        (findAllCap (upperChar :: Parser Word8))+        (findAllCap' (upperChar :: Parser Word8))         ("aBcD" :: B.ByteString)         [Left "a", Right ("B", c2w 'B'), Left "c", Right ("D", c2w 'D')]     -- check that sepCap can progress even when parser consumes nothing
tests/TestString.hs view
@@ -10,13 +10,20 @@ import Text.Megaparsec import Text.Megaparsec.Char import Data.Void+import Data.Bifunctor (second)  type Parser = Parsec Void String +findAllCap' :: MonadParsec e s m => m a -> m [Either (Tokens s) (Tokens s, a)]+findAllCap' sep = sepCap (match sep)++findAll' :: MonadParsec e s f => f b -> f [Either (Tokens s) (Tokens s)]+findAll' sep = (fmap.fmap) (second fst) $ sepCap (match sep)+ tests :: IO [Test] tests = return     [ Test $ runParserTest "findAll upperChar"-        (findAllCap (upperChar :: Parser Char))+        (findAllCap' (upperChar :: Parser Char))         ("aBcD" :: String)         [Left "a", Right ("B", 'B'), Left "c", Right ("D", 'D')]     -- check that sepCap can progress even when parser consumes nothing@@ -44,7 +51,7 @@         ([Left "a"]) #endif     , Test $ runParserTest "findAll astral"-        (findAll ((takeWhileP Nothing (=='𝅘𝅥𝅯') :: Parser String)))+        (findAll' ((takeWhileP Nothing (=='𝅘𝅥𝅯') :: Parser String)))         ("𝄞𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥")         [Left "𝄞𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥", Right "𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯", Left "𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥"]     , Test $ runParserTest "empty input" (sepCap (fail "" :: Parser ())) "" []
tests/TestText.hs view
@@ -12,13 +12,20 @@ import Text.Megaparsec.Char import Data.Void import qualified Data.Text as T+import Data.Bifunctor (second)  type Parser = Parsec Void T.Text +findAllCap' :: MonadParsec e s m => m a -> m [Either (Tokens s) (Tokens s, a)]+findAllCap' sep = sepCap (match sep)++findAll' :: MonadParsec e s f => f b -> f [Either (Tokens s) (Tokens s)]+findAll' sep = (fmap.fmap) (second fst) $ sepCap (match sep)+ tests :: IO [Test] tests = return     [ Test $ runParserTest "findAll upperChar"-        (findAllCap (upperChar :: Parser Char))+        (findAllCap' (upperChar :: Parser Char))         ("aBcD" :: T.Text)         [Left "a", Right ("B", 'B'), Left "c", Right ("D", 'D')]     -- check that sepCap can progress even when parser consumes nothing@@ -46,7 +53,7 @@         ([Left "a"]) #endif     , Test $ runParserTest "findAll astral"-        (findAll ((takeWhileP Nothing (=='𝅘𝅥𝅯') :: Parser T.Text)))+        (findAll' ((takeWhileP Nothing (=='𝅘𝅥𝅯') :: Parser T.Text)))         ("𝄞𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥" :: T.Text)         [Left "𝄞𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥", Right "𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯𝅘𝅥𝅯", Left "𝅘𝅥𝅘𝅥𝅘𝅥𝅘𝅥"]     , Test $ runParserTest "empty input" (sepCap (fail "" :: Parser ())) "" []