parser-regex 0.2.0.2 → 0.3.0.0
raw patch · 10 files changed
+359/−295 lines, 10 filesdep ~ghc-bignumPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: ghc-bignum
API changes (from Hackage documentation)
- Regex.Base: type Foldr f a = forall b. (a -> b -> b) -> b -> f -> b
- Regex.Internal.Parser: type Foldr f a = forall b. (a -> b -> b) -> b -> f -> b
- Regex.Internal.Regex: Greedy :: Greediness
- Regex.Internal.Regex: Minimal :: Greediness
- Regex.Internal.Regex: NonStrict :: Strictness
- Regex.Internal.Regex: Strict :: Strictness
- Regex.Internal.Regex: [RFold] :: !Strictness -> !Greediness -> !a -> a1 -> a -> a -> !RE c a1 -> RE c a
- Regex.Internal.Regex: data Greediness
- Regex.Internal.Regex: data Strictness
- Regex.Internal.Text: instance GHC.Base.Applicative Regex.Internal.Text.WithMatch
- Regex.Internal.Text: instance GHC.Base.Functor Regex.Internal.Text.WithMatch
+ Regex.Base: type Foldr f a = forall b. () => a -> b -> b -> b -> f -> b
+ Regex.Internal.Parser: type Foldr f a = forall b. () => a -> b -> b -> b -> f -> b
+ Regex.Internal.Regex: [RFoldGr] :: forall a a1 c. !a -> a1 -> Solo a -> a -> !RE c a1 -> RE c a
+ Regex.Internal.Regex: [RFoldMn] :: forall a a1 c. !a -> a1 -> Solo a -> a -> !RE c a1 -> RE c a
+ Regex.Internal.Solo: data Solo a :: TYPE 'TupleRep '[LiftedRep]
+ Regex.Internal.Solo: matchSolo :: Solo a -> (a -> b) -> b
+ Regex.Internal.Solo: mkSolo :: a -> Solo a
- Regex.Internal.Debug: parserToDot :: forall c a. Maybe ([c], [c] -> String) -> Parser c a -> String
+ Regex.Internal.Debug: parserToDot :: Maybe ([c], [c] -> String) -> Parser c a -> String
- Regex.Internal.Debug: reToDot :: forall c a. Maybe ([c], [c] -> String) -> RE c a -> String
+ Regex.Internal.Debug: reToDot :: Maybe ([c], [c] -> String) -> RE c a -> String
- Regex.Internal.Parser: [NAccept] :: a -> Node c a
+ Regex.Internal.Parser: [NAccept] :: forall a c. a -> Node c a
- Regex.Internal.Parser: [NAlt] :: !Node c a -> !Node c a -> {-# UNPACK #-} !SmallArray (Node c a) -> Node c a
+ Regex.Internal.Parser: [NAlt] :: forall c a. !Node c a -> !Node c a -> {-# UNPACK #-} !SmallArray (Node c a) -> Node c a
- Regex.Internal.Parser: [NEmpty] :: Node c a
+ Regex.Internal.Parser: [NEmpty] :: forall c a. Node c a
- Regex.Internal.Parser: [NGuard] :: {-# UNPACK #-} !Unique -> Node c a -> Node c a
+ Regex.Internal.Parser: [NGuard] :: forall c a. {-# UNPACK #-} !Unique -> Node c a -> Node c a
- Regex.Internal.Parser: [NToken] :: !c -> Maybe a1 -> !Node c a -> Node c a
+ Regex.Internal.Parser: [NToken] :: forall c a1 a. !c -> Maybe a1 -> !Node c a -> Node c a
- Regex.Internal.Parser: [PAlt] :: {-# UNPACK #-} !Unique -> !Parser c a -> !Parser c a -> {-# UNPACK #-} !SmallArray (Parser c a) -> Parser c a
+ Regex.Internal.Parser: [PAlt] :: forall c a. {-# UNPACK #-} !Unique -> !Parser c a -> !Parser c a -> {-# UNPACK #-} !SmallArray (Parser c a) -> Parser c a
- Regex.Internal.Parser: [PEmpty] :: Parser c a
+ Regex.Internal.Parser: [PEmpty] :: forall c a. Parser c a
- Regex.Internal.Parser: [PFmap] :: !Strictness -> !a1 -> a -> !Parser c a1 -> Parser c a
+ Regex.Internal.Parser: [PFmap] :: forall a1 a c. !a1 -> Solo a -> !Parser c a1 -> Parser c a
- Regex.Internal.Parser: [PFmap_] :: !Node c a -> Parser c a
+ Regex.Internal.Parser: [PFmap_] :: forall c a. !Node c a -> Parser c a
- Regex.Internal.Parser: [PFoldGr] :: {-# UNPACK #-} !Unique -> !Strictness -> !a -> a1 -> a -> a -> !Parser c a1 -> Parser c a
+ Regex.Internal.Parser: [PFoldGr] :: forall a a1 c. {-# UNPACK #-} !Unique -> !a -> a1 -> Solo a -> a -> !Parser c a1 -> Parser c a
- Regex.Internal.Parser: [PFoldMn] :: {-# UNPACK #-} !Unique -> !Strictness -> !a -> a1 -> a -> a -> !Parser c a1 -> Parser c a
+ Regex.Internal.Parser: [PFoldMn] :: forall a a1 c. {-# UNPACK #-} !Unique -> !a -> a1 -> Solo a -> a -> !Parser c a1 -> Parser c a
- Regex.Internal.Parser: [PLiftA2] :: !Strictness -> !a1 -> a2 -> a -> !Parser c a1 -> !Parser c a2 -> Parser c a
+ Regex.Internal.Parser: [PLiftA2] :: forall a1 a2 a c. !a1 -> a2 -> Solo a -> !Parser c a1 -> !Parser c a2 -> Parser c a
- Regex.Internal.Parser: [PMany] :: {-# UNPACK #-} !Unique -> !a1 -> a -> !a2 -> a -> !a2 -> a1 -> a2 -> !a2 -> !Parser c a1 -> Parser c a
+ Regex.Internal.Parser: [PMany] :: forall a1 a a2 c. {-# UNPACK #-} !Unique -> !a1 -> Solo a -> !a2 -> Solo a -> !a2 -> a1 -> Solo a2 -> !a2 -> !Parser c a1 -> Parser c a
- Regex.Internal.Parser: [PPure] :: a -> Parser c a
+ Regex.Internal.Parser: [PPure] :: forall a c. a -> Parser c a
- Regex.Internal.Parser: [PToken] :: !c -> Maybe a -> Parser c a
+ Regex.Internal.Parser: [PToken] :: forall c a. !c -> Maybe a -> Parser c a
- Regex.Internal.Regex: [RAlt] :: !RE c a -> !RE c a -> RE c a
+ Regex.Internal.Regex: [RAlt] :: forall c a. !RE c a -> !RE c a -> RE c a
- Regex.Internal.Regex: [REmpty] :: RE c a
+ Regex.Internal.Regex: [REmpty] :: forall c a. RE c a
- Regex.Internal.Regex: [RFmap] :: !Strictness -> !a1 -> a -> !RE c a1 -> RE c a
+ Regex.Internal.Regex: [RFmap] :: forall a1 a c. !a1 -> Solo a -> !RE c a1 -> RE c a
- Regex.Internal.Regex: [RFmap_] :: a -> !RE c a1 -> RE c a
+ Regex.Internal.Regex: [RFmap_] :: forall a c a1. a -> !RE c a1 -> RE c a
- Regex.Internal.Regex: [RLiftA2] :: !Strictness -> !a1 -> a2 -> a -> !RE c a1 -> !RE c a2 -> RE c a
+ Regex.Internal.Regex: [RLiftA2] :: forall a1 a2 a c. !a1 -> a2 -> Solo a -> !RE c a1 -> !RE c a2 -> RE c a
- Regex.Internal.Regex: [RMany] :: !a1 -> a -> !a2 -> a -> !a2 -> a1 -> a2 -> !a2 -> !RE c a1 -> RE c a
+ Regex.Internal.Regex: [RMany] :: forall a1 a a2 c. !a1 -> Solo a -> !a2 -> Solo a -> !a2 -> a1 -> Solo a2 -> !a2 -> !RE c a1 -> RE c a
- Regex.Internal.Regex: [RPure] :: a -> RE c a
+ Regex.Internal.Regex: [RPure] :: forall a c. a -> RE c a
- Regex.Internal.Regex: [RToken] :: !c -> Maybe a -> RE c a
+ Regex.Internal.Regex: [RToken] :: forall c a. !c -> Maybe a -> RE c a
Files
- CHANGELOG.md +10/−1
- README.md +29/−12
- parser-regex.cabal +2/−1
- src/Regex/Internal/Debug.hs +18/−25
- src/Regex/Internal/List.hs +33/−40
- src/Regex/Internal/Parser.hs +142/−154
- src/Regex/Internal/Regex.hs +67/−20
- src/Regex/Internal/Solo.hs +27/−0
- src/Regex/Internal/Text.hs +31/−40
- src/Regex/Internal/Unique.hs +0/−2
CHANGELOG.md view
@@ -1,7 +1,16 @@-### 0.2.0.2 -- 2024-03-15+### 0.3.0.0 -- 2025-04-19 +* Breaking changes—`Internal` modules only+ * Changes to internal representations+* Performance improvements+ * Fix a pessimization due to boxity analysis on GHC >= 9.4. Improves parsing+ time by up to 23%.++### 0.2.0.2 -- 2025-03-15+ * Compatibility with [MicroHs](https://github.com/augustss/MicroHs) * Performance improvements+ * Avoid some closure allocations, improving parsing time by up to 10%. * Fix `compileBounded`'s behavior on negative bounds ### 0.2.0.1 -- 2024-12-25
README.md view
@@ -66,7 +66,7 @@ , fragment = Just "parser-regex" }) ``` -### More parsing+### Parsing Parsing is straightforward, even for tasks which may be impractical with submatch extraction typically offered by regex libraries.@@ -121,27 +121,44 @@ ### Parse any sequence -Regexes are not restricted to parsing text. For example, one may parse vectors-from the [vector](https://hackage.haskell.org/package/vector) library, because-why not.+Parsing is not restricted to text. One can parse a+[`vector`](https://hackage.haskell.org/package/vector), a+[`conduit`](https://hackage.haskell.org/package/conduit), or any other sequence+one might have. ```hs-import Regex.Base (Parser) import qualified Regex.Base as R-import qualified Data.Vector.Generic as VG+import qualified Data.Vector.Generic as VG -- from vector+import qualified Conduit as C -- from conduit -parseVector :: VG.Vector v c => Parser c a -> v c -> Maybe a+parseVector :: VG.Vector v c => R.Parser c a -> v c -> Maybe a parseVector = R.parseFoldr VG.foldr++parseConduit :: Monad m => R.Parser c a -> C.ConduitT c x m (Maybe a)+parseConduit p = R.parseNext p C.await <* C.sinkNull ``` ```hs >>> import Control.Applicative (many)->>> import qualified Data.Vector as V >>> import qualified Regex.Base as R+>>> :{+let evenOddP :: R.Parser Int [(Int, Int)]+ evenOddP = R.compile $ many ((,) <$> R.satisfy even <*> R.satisfy odd)+:} >>>->>> let p = R.compile $ many ((,) <$> R.satisfy even <*> R.satisfy odd)->>> let v = V.fromList [0..5] :: V.Vector Int->>> parseVector p v-Just [(0,1),(2,3),(4,5)]+>>> import qualified Data.Vector as V+>>> parseVector evenOddP (V.fromList [6,1,2,5,4,3])+Just [(6,1),(2,5),(4,3)]+>>> parseVector evenOddP (V.fromList [4,3,1,2])+Nothing+>>>+>>> import Conduit ((.|))+>>> import qualified Conduit as C+>>> C.runConduit $ C.yieldMany [0..3] .| C.iterMC print .| parseConduit evenOddP+0+1+2+3+Just [(0,1),(2,3)] ``` ## Documentation
parser-regex.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: parser-regex-version: 0.2.0.2+version: 0.3.0.0 synopsis: Regex based parsers homepage: https://github.com/meooow25/parser-regex bug-reports: https://github.com/meooow25/parser-regex/issues@@ -52,6 +52,7 @@ Regex.Internal.Debug Regex.Internal.Parser Regex.Internal.Regex+ Regex.Internal.Solo Regex.Internal.Text Regex.Internal.Unique
src/Regex/Internal/Debug.hs view
@@ -22,7 +22,7 @@ import Data.IntMap.Strict (IntMap) import qualified Data.IntMap.Strict as IM -import Regex.Internal.Regex (RE(..), Strictness(..), Greediness(..))+import Regex.Internal.Regex (RE(..)) import Regex.Internal.Parser (Node(..), Parser(..)) import Regex.Internal.Unique (Unique(..)) import qualified Regex.Internal.CharSet as CS@@ -44,15 +44,15 @@ go :: forall b. RE c b -> M Id go re = case re of RToken t -> new $ labelToken "RToken" t ma- RFmap st _ re1 ->- withNew (str "RFmap" <+> dispsSt st) $ \i ->+ RFmap _ re1 ->+ withNew (str "RFmap") $ \i -> go re1 >>= writeEdge i RFmap_ _ re1 -> withNew (str "RFmap_") $ \i -> go re1 >>= writeEdge i RPure _ -> new (str "RPure")- RLiftA2 st _ re1 re2 ->- withNew (str "RLiftA2" <+> dispsSt st) $ \i -> do+ RLiftA2 _ re1 re2 ->+ withNew (str "RLiftA2") $ \i -> do go re1 >>= writeEdge i go re2 >>= writeEdge i REmpty -> new (str "REmpty")@@ -60,9 +60,12 @@ withNew (str "RAlt") $ \i -> do go re1 >>= writeEdge i go re2 >>= writeEdge i- RFold st gr _ _ re1 ->- withNew (str "RFold" <+> dispsSt st <+> dispsGr gr) $ \i ->+ RFoldGr _ _ re1 ->+ withNew (str "RFoldGr") $ \i -> go re1 >>= writeEdge i+ RFoldMn _ _ re1 ->+ withNew (str "RFoldMn") $ \i ->+ go re1 >>= writeEdge i RMany _ _ _ _ re1 -> withNew (str "RMany") $ \i -> go re1 >>= writeEdge i@@ -84,8 +87,8 @@ go :: forall b. Parser c b -> M Id go p = case p of PToken t -> new $ labelToken "PToken" t ma- PFmap st _ re1 ->- withNew (str "PFmap" <+> dispsSt st) $ \i ->+ PFmap _ re1 ->+ withNew (str "PFmap") $ \i -> go re1 >>= writeEdge i PFmap_ node -> withNew (str "PFmap_") $ \i -> do@@ -94,8 +97,8 @@ writeLn (str "}") writeEdge i j PPure _ -> new (str "PPure")- PLiftA2 st _ re1 re2 ->- withNew (str "PLiftA2" <+> dispsSt st) $ \i -> do+ PLiftA2 _ re1 re2 ->+ withNew (str "PLiftA2") $ \i -> do go re1 >>= writeEdge i go re2 >>= writeEdge i PEmpty -> new (str "PEmpty")@@ -107,11 +110,11 @@ PMany _ _ _ _ _ re1 -> withNew (str "PMany") $ \i -> go re1 >>= writeEdge i- PFoldGr _ st _ _ re1 ->- withNew (str "PFoldGr" <+> dispsSt st) $ \i ->+ PFoldGr _ _ _ re1 ->+ withNew (str "PFoldGr") $ \i -> go re1 >>= writeEdge i- PFoldMn _ st _ _ re1 ->- withNew (str "PFoldMn" <+> dispsSt st) $ \i ->+ PFoldMn _ _ _ re1 ->+ withNew (str "PFoldMn") $ \i -> go re1 >>= writeEdge i goNode :: forall b. Node c b -> StateT (IntMap Id) M Id@@ -157,16 +160,6 @@ instance Monoid Str where mempty = Str id--dispsSt :: Strictness -> Str-dispsSt st = case st of- Strict -> str "S"- NonStrict -> str "NS"--dispsGr :: Greediness -> Str-dispsGr gr = case gr of- Greedy -> str "G"- Minimal -> str "M" labelToken :: String -> (c -> Maybe a) -> Maybe ([c], [c] -> String) -> Str labelToken node t = maybe
src/Regex/Internal/List.hs view
@@ -50,10 +50,11 @@ import qualified Data.CharSet as CS import Regex.Internal.Parser (Parser) import qualified Regex.Internal.Parser as P-import Regex.Internal.Regex (RE(..), Greediness(..), Strictness(..))+import Regex.Internal.Regex (RE(..)) import qualified Regex.Internal.Regex as R import qualified Regex.Internal.Num as RNum import qualified Regex.Internal.Generated.CaseFold as CF+import Regex.Internal.Solo (Solo, mkSolo, matchSolo) ------------------------ -- REs and combinators@@ -231,30 +232,28 @@ toMatch_ :: RE c b -> RE c (DList c) toMatch_ re = case re of- RToken t -> RToken (\c -> singletonD c <$ t c)- RFmap _ _ re1 -> toMatch_ re1+ RToken t -> R.token (\c -> singletonD c <$ t c)+ RFmap _ re1 -> toMatch_ re1 RFmap_ _ re1 -> toMatch_ re1- RPure _ -> RPure mempty- RLiftA2 _ _ re1 re2 -> RLiftA2 Strict (<>) (toMatch_ re1) (toMatch_ re2)- REmpty -> REmpty- RAlt re1 re2 -> RAlt (toMatch_ re1) (toMatch_ re2)- RMany _ _ _ _ re1 -> RFold Strict Greedy (<>) mempty (toMatch_ re1)- RFold _ gr _ _ re1 -> RFold Strict gr (<>) mempty (toMatch_ re1)+ RPure _ -> pure mempty+ RLiftA2 _ re1 re2 -> R.liftA2' (<>) (toMatch_ re1) (toMatch_ re2)+ REmpty -> Ap.empty+ RAlt re1 re2 -> toMatch_ re1 <|> toMatch_ re2+ RFoldGr _ _ re1 -> R.foldlMany' (<>) mempty (toMatch_ re1)+ RFoldMn _ _ re1 -> R.foldlManyMin' (<>) mempty (toMatch_ re1)+ RMany _ _ _ _ re1 -> R.foldlMany' (<>) mempty (toMatch_ re1) data WithMatch c a = WM !(DList c) a -instance Functor (WithMatch c) where- fmap f (WM t x) = WM t (f x)--fmapWM' :: (a -> b) -> WithMatch c a -> WithMatch c b-fmapWM' f (WM t x) = WM t $! f x+fmapWM :: (a -> Solo b) -> WithMatch c a -> WithMatch c b+fmapWM f (WM t x) = matchSolo (f x) (WM t) -instance Applicative (WithMatch c) where- pure = WM mempty- liftA2 f (WM t1 x) (WM t2 y) = WM (t1 <> t2) (f x y)+pureWM :: a -> WithMatch c a+pureWM = WM mempty -liftA2WM' :: (a1 -> a2 -> b) -> WithMatch c a1 -> WithMatch c a2 -> WithMatch c b-liftA2WM' f (WM t1 x) (WM t2 y) = WM (t1 <> t2) $! f x y+liftA2WM+ :: (a1 -> a2 -> Solo b) -> WithMatch c a1 -> WithMatch c a2 -> WithMatch c b+liftA2WM f (WM t1 x) (WM t2 y) = matchSolo (f x y) (WM (t1 <> t2)) -- | Rebuild the @RE@ to include the matched section of the list alongside the -- result.@@ -263,28 +262,22 @@ where go :: RE c b -> RE c (WithMatch c b) go re = case re of- RToken t -> RToken (\c -> WM (singletonD c) <$> t c)- RFmap st f re1 ->- let g = case st of- Strict -> fmapWM' f- NonStrict -> fmap f- in RFmap Strict g (go re1)- RFmap_ b re1 -> RFmap Strict (flip WM b) (toMatch_ re1)- RPure b -> RPure (pure b)- RLiftA2 st f re1 re2 ->- let g = case st of- Strict -> liftA2WM' f- NonStrict -> Ap.liftA2 f- in RLiftA2 Strict g (go re1) (go re2)- REmpty -> REmpty- RAlt re1 re2 -> RAlt (go re1) (go re2)+ RToken t -> R.token (\c -> WM (singletonD c) <$> t c)+ RFmap f re1 -> R.fmap' (fmapWM f) (go re1)+ RFmap_ b re1 -> R.fmap' (flip WM b) (toMatch_ re1)+ RPure b -> pure (pureWM b)+ RLiftA2 f re1 re2 -> R.liftA2' (liftA2WM f) (go re1) (go re2)+ REmpty -> Ap.empty+ RAlt re1 re2 -> go re1 <|> go re2+ RFoldGr f z re1 -> R.foldlMany' (liftA2WM f) (pureWM z) (go re1)+ RFoldMn f z re1 -> R.foldlManyMin' (liftA2WM f) (pureWM z) (go re1) RMany f1 f2 f z re1 ->- RMany (fmapWM' f1) (fmapWM' f2) (liftA2WM' f) (pure z) (go re1)- RFold st gr f z re1 ->- let g = case st of- Strict -> liftA2WM' f- NonStrict -> Ap.liftA2 f- in RFold Strict gr g (pure z) (go re1)+ RMany+ (\x -> mkSolo $! fmapWM f1 x)+ (\x -> mkSolo $! fmapWM f2 x)+ (\x y -> mkSolo $! liftA2WM f x y)+ (pureWM z)+ (go re1) ---------- -- Parse
src/Regex/Internal/Parser.hs view
@@ -4,6 +4,10 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_HADDOCK not-home #-}+#if __GLASGOW_HASKELL__ >= 904+-- See Note [-fdmd-unbox-width]+{-# OPTIONS_GHC -fdmd-unbox-width=4 #-}+#endif -- | This is an internal module. You probably don't need to import this. --@@ -30,7 +34,7 @@ import Control.Applicative ((<|>), empty) import qualified Control.Applicative as Ap import Control.Monad.Trans.State.Strict- ( State, StateT, evalState, evalStateT, execState, gets, modify', state)+ ( State, StateT, evalState, evalStateT, gets, modify', state) import Control.Monad.Fix (mfix) import Data.Maybe (isJust) import qualified Data.Foldable as F@@ -41,7 +45,8 @@ import qualified GHC.Exts as X #endif -import Regex.Internal.Regex (RE(..), Strictness(..), Greediness(..))+import Regex.Internal.Regex (RE(..))+import Regex.Internal.Solo (Solo, matchSolo) import Regex.Internal.Unique (Unique(..), UniqueSet) import qualified Regex.Internal.Unique as U @@ -52,15 +57,15 @@ -- | A parser compiled from a @'RE' c a@. data Parser c a where PToken :: !(c -> Maybe a) -> Parser c a- PFmap :: !Strictness -> !(a1 -> a) -> !(Parser c a1) -> Parser c a+ PFmap :: !(a1 -> Solo a) -> !(Parser c a1) -> Parser c a PFmap_ :: !(Node c a) -> Parser c a PPure :: a -> Parser c a- PLiftA2 :: !Strictness -> !(a1 -> a2 -> a) -> !(Parser c a1) -> !(Parser c a2) -> Parser c a+ PLiftA2 :: !(a1 -> a2 -> Solo a) -> !(Parser c a1) -> !(Parser c a2) -> Parser c a PEmpty :: Parser c a PAlt :: {-# UNPACK #-} !Unique -> !(Parser c a) -> !(Parser c a) -> {-# UNPACK #-} !(SmallArray (Parser c a)) -> Parser c a- PFoldGr :: {-# UNPACK #-} !Unique -> !Strictness -> !(a -> a1 -> a) -> a -> !(Parser c a1) -> Parser c a- PFoldMn :: {-# UNPACK #-} !Unique -> !Strictness -> !(a -> a1 -> a) -> a -> !(Parser c a1) -> Parser c a- PMany :: {-# UNPACK #-} !Unique -> !(a1 -> a) -> !(a2 -> a) -> !(a2 -> a1 -> a2) -> !a2 -> !(Parser c a1) -> Parser c a+ PFoldGr :: {-# UNPACK #-} !Unique -> !(a -> a1 -> Solo a) -> a -> !(Parser c a1) -> Parser c a+ PFoldMn :: {-# UNPACK #-} !Unique -> !(a -> a1 -> Solo a) -> a -> !(Parser c a1) -> Parser c a+ PMany :: {-# UNPACK #-} !Unique -> !(a1 -> Solo a) -> !(a2 -> Solo a) -> !(a2 -> a1 -> Solo a2) -> !a2 -> !(Parser c a1) -> Parser c a -- | A node in the NFA. Used for recognition. data Node c a where@@ -91,11 +96,11 @@ compileToParser :: RE c a -> State Unique (Parser c a) compileToParser re = case re of RToken t -> pure $ PToken t- RFmap st f re1 -> PFmap st f <$> compileToParser re1+ RFmap f re1 -> PFmap f <$> compileToParser re1 RFmap_ a re1 -> PFmap_ <$> compileToNode a re1 RPure a -> pure $ PPure a- RLiftA2 st f re1 re2 ->- Ap.liftA2 (PLiftA2 st f) (compileToParser re1) (compileToParser re2)+ RLiftA2 f re1 re2 ->+ Ap.liftA2 (PLiftA2 f) (compileToParser re1) (compileToParser re2) REmpty -> pure PEmpty RAlt re01 re02 -> do u <- nxtU@@ -104,12 +109,14 @@ p2 <- compileToParser re2 ps <- T.traverse compileToParser res pure $ PAlt u p1 p2 (smallArrayFromList ps)- RFold st gr f z re1 -> do+ RFoldGr f z re1 -> do u <- nxtU _localU <- nxtU- case gr of- Greedy -> PFoldGr u st f z <$> compileToParser re1- Minimal -> PFoldMn u st f z <$> compileToParser re1+ PFoldGr u f z <$> compileToParser re1+ RFoldMn f z re1 -> do+ u <- nxtU+ _localU <- nxtU+ PFoldMn u f z <$> compileToParser re1 RMany f1 f2 f z re1 -> do u <- nxtU _localU <- nxtU@@ -121,10 +128,10 @@ go :: forall a2. RE c a2 -> Node c a -> State Unique (Node c a) go re nxt = case re of RToken t -> pure $ NToken t nxt- RFmap _ _ re1 -> go re1 nxt+ RFmap _ re1 -> go re1 nxt RFmap_ _ re1 -> go re1 nxt RPure _ -> pure nxt- RLiftA2 _ _ re1 re2 -> go re2 nxt >>= go re1+ RLiftA2 _ re1 re2 -> go re2 nxt >>= go re1 REmpty -> pure NEmpty RAlt re01 re02 -> do u <- nxtU@@ -134,17 +141,17 @@ n2 <- go re2 nxt1 ns <- T.traverse (flip go nxt1) res pure $ NAlt n1 n2 (smallArrayFromList ns)- RFold _ gr _ _ re1 -> goMany gr re1 nxt- RMany _ _ _ _ re1 -> goMany Greedy re1 nxt- goMany :: forall a2.- Greediness -> RE c a2 -> Node c a -> State Unique (Node c a)- goMany gr re1 nxt = do+ RFoldGr _ _ re1 -> goMany True re1 nxt+ RFoldMn _ _ re1 -> goMany False re1 nxt+ RMany _ _ _ _ re1 -> goMany True re1 nxt+ goMany :: forall a2. Bool -> RE c a2 -> Node c a -> State Unique (Node c a)+ goMany greedy re1 nxt = do u <- nxtU mfix $ \n -> do ndown <- go re1 n- case gr of- Greedy -> pure $ NGuard u (NAlt ndown nxt emptySmallArray)- Minimal -> pure $ NGuard u (NAlt nxt ndown emptySmallArray)+ if greedy+ then pure $ NGuard u (NAlt ndown nxt emptySmallArray)+ else pure $ NGuard u (NAlt nxt ndown emptySmallArray) gatherAlts :: RE c a -> RE c a -> (RE c a, RE c a, [RE c a]) gatherAlts re01 re02 = case go re01 (go re02 []) of@@ -180,14 +187,15 @@ go :: RE c a1 -> StateT Int Maybe () go re = case re of RToken _ -> inc- RFmap _ _ re1 -> inc *> go re1+ RFmap _ re1 -> inc *> go re1 RFmap_ _ re1 -> inc *> go re1 RPure _ -> inc- RLiftA2 _ _ re1 re2 -> inc *> go re1 *> go re2+ RLiftA2 _ re1 re2 -> inc *> go re1 *> go re2 REmpty -> inc RAlt re1 re2 -> inc *> go re1 *> go re2+ RFoldGr _ _ re1 -> inc *> go re1+ RFoldMn _ _ re1 -> inc *> go re1 RMany _ _ _ _ re1 -> inc *> go re1- RFold _ _ _ _ re1 -> inc *> go re1 inc = do ok <- gets (< lim) if ok@@ -200,14 +208,14 @@ data Cont c b a where CTop :: Cont c a a- CFmap :: !Strictness -> !(b -> a1) -> !(Cont c a1 a) -> Cont c b a+ CFmap :: !(b -> Solo a1) -> !(Cont c a1 a) -> Cont c b a CFmap_ :: !(Node c a1) -> !(Cont c a1 a) -> Cont c b a- CLiftA2A :: !Strictness -> !(b -> a2 -> a3) -> !(Parser c a2) -> !(Cont c a3 a) -> Cont c b a- CLiftA2B :: !Strictness -> !(a1 -> b -> a3) -> a1 -> !(Cont c a3 a) -> Cont c b a+ CLiftA2A :: !(b -> a2 -> Solo a3) -> !(Parser c a2) -> !(Cont c a3 a) -> Cont c b a+ CLiftA2B :: !(a1 -> b -> Solo a3) -> a1 -> !(Cont c a3 a) -> Cont c b a CAlt :: {-# UNPACK #-} !Unique -> !(Cont c b a) -> Cont c b a- CFoldGr :: {-# UNPACK #-} !Unique -> !Strictness -> !(Parser c b) -> !(a1 -> b -> a1) -> a1 -> !(Cont c a1 a) -> Cont c b a- CFoldMn :: {-# UNPACK #-} !Unique -> !Strictness -> !(Parser c b) -> !(a1 -> b -> a1) -> a1 -> !(Cont c a1 a) -> Cont c b a- CMany :: {-# UNPACK #-} !Unique -> !(Parser c b) -> !(b -> a2) -> !(a1 -> a2) -> !(a1 -> b -> a1) -> !a1 -> !(Cont c a2 a) -> Cont c b a+ CFoldGr :: {-# UNPACK #-} !Unique -> !(Parser c b) -> !(a1 -> b -> Solo a1) -> a1 -> !(Cont c a1 a) -> Cont c b a+ CFoldMn :: {-# UNPACK #-} !Unique -> !(Parser c b) -> !(a1 -> b -> Solo a1) -> a1 -> !(Cont c a1 a) -> Cont c b a+ CMany :: {-# UNPACK #-} !Unique -> !(Parser c b) -> !(b -> Solo a2) -> !(a1 -> Solo a2) -> !(a1 -> b -> Solo a1) -> !a1 -> !(Cont c a2 a) -> Cont c b a data NeedCList c a where NeedCCons :: !(c -> Maybe b) -> !(Cont c b a) -> !(NeedCList c a) -> NeedCList c a@@ -222,59 +230,72 @@ stepStateZero :: StepState c a stepStateZero = StepState U.empty NeedCNil Nothing --- Note: Ideally we would have--- down :: Parser c b -> Cont c b a -> State (StepState c a) ()--- and similar downNode and up, but GHC is unable to optimize it to be--- equivalent to the current code.------ Using State is pretty convenient though, so it is used in branches. This--- seems to get optimized well enough.+sMember :: Unique -> StepState c a -> Bool+sMember u pt = U.member u (sSet pt) -sMember :: Unique -> State (StepState c a) Bool-sMember u = gets $ \pt -> U.member u (sSet pt)+sInsert :: Unique -> StepState c a -> StepState c a+sInsert u pt = pt { sSet = U.insert u (sSet pt) } -sInsert :: Unique -> State (StepState c a) ()-sInsert u = modify' $ \pt -> pt { sSet = U.insert u (sSet pt) }+-- Note [-fdmd-unbox-width]+-- ~~~~~~~~~~~~~~~~~~~~~~~~+-- GHC's worker/wrapper transformation is able to eliminate the StepState and+-- generate a worker for `down` with signature+--+-- $wdown+-- :: Parser c b -> Cont c b a+-- -> Int# -> IntSet -> NeedCList c a -> Maybe a+-- -> (# Int#, IntSet, NeedCList c a, Maybe a #)+--+-- and likewise for `downNode` and `up`.+--+-- This is great, but unfortunately boxity analysis gets in the way. Boxity+-- analysis prevents unboxing of types with more than -fdmd-unbox-width fields,+-- default 3 as of today. So we set it to the number of fields in StepState,+-- i.e. 4, with an OPTIONS_GHC pragma. down :: Parser c b -> Cont c b a -> StepState c a -> StepState c a down p !ct !pt = case p of PToken t -> pt { sNeed = NeedCCons t ct (sNeed pt) }- PFmap st f p1 -> down p1 (CFmap st f ct) pt+ PFmap f p1 -> down p1 (CFmap f ct) pt PFmap_ n -> downNode n ct pt PPure b -> up b ct pt- PLiftA2 st f p1 p2 -> down p1 (CLiftA2A st f p2 ct) pt+ PLiftA2 f p1 p2 -> down p1 (CLiftA2A f p2 ct) pt PEmpty -> pt PAlt u p1 p2 ps -> let ct1 = CAlt u ct in F.foldl' (\pt' p' -> down p' ct1 pt') (down p2 ct1 (down p1 ct1 pt)) ps- PFoldGr u st f z p1 -> flip execState pt $- unlessM (sMember u) $ do- sInsert (localU u)- modify' $ down p1 (CFoldGr u st p1 f z ct)- unlessM (sMember u) $ do- sInsert u- modify' $ up z ct- PFoldMn u st f z p1 -> flip execState pt $- unlessM (sMember u) $ do- unlessM (sMember (localU u)) $ do- modify' $ up z ct- sInsert u- modify' $ down p1 (CFoldMn u st p1 f z ct)- PMany u f1 f2 f z p1 -> flip execState pt $- unlessM (sMember u) $ do- sInsert (localU u)- modify' $ down p1 (CMany u p1 f1 f2 f z ct)- unlessM (sMember u) $ do- sInsert u- let !x = f2 z- modify' $ up x ct+ PFoldGr u f z p1 ->+ if sMember u pt+ then pt+ else+ let pt1 = down p1 (CFoldGr u p1 f z ct) (sInsert (localU u) pt)+ in if sMember u pt1+ then pt1+ else up z ct (sInsert u pt1)+ PFoldMn u f z p1 ->+ if sMember u pt+ then pt+ else+ let pt1 = if sMember (localU u) pt+ then pt+ else up z ct pt+ in down p1 (CFoldMn u p1 f z ct) (sInsert u pt1)+ PMany u f1 f2 f z p1 ->+ if sMember u pt+ then pt+ else+ let pt1 = down p1 (CMany u p1 f1 f2 f z ct) (sInsert (localU u) pt)+ in if sMember u pt1+ then pt1+ else matchSolo (f2 z) $ \x -> up x ct (sInsert u pt1) downNode :: Node c b -> Cont c b a -> StepState c a -> StepState c a downNode n !ct !pt = case n of NAccept b -> up b ct pt- NGuard u n1- | U.member u (sSet pt) -> pt- | otherwise -> downNode n1 ct (pt { sSet = U.insert u (sSet pt) })+ NGuard u n1 ->+ if sMember u pt+ then pt+ else downNode n1 ct (sInsert u pt) NToken t nxt -> pt { sNeed = NeedCCons t (CFmap_ nxt ct) (sNeed pt) } NEmpty -> pt@@ -287,58 +308,42 @@ up :: b -> Cont c b a -> StepState c a -> StepState c a up b ct !pt = case ct of CTop -> pt { sResult = sResult pt <|> Just b }- CFmap st f ct1 -> case st of- Strict -> let !x = f b in up x ct1 pt- NonStrict -> up (f b) ct1 pt+ CFmap f ct1 -> matchSolo (f b) $ \x -> up x ct1 pt CFmap_ n ct1 -> downNode n ct1 pt- CLiftA2A st f p1 ct1 -> down p1 (CLiftA2B st f b ct1) pt- CLiftA2B st f a ct1 -> case st of- Strict -> let !x = f a b in up x ct1 pt- NonStrict -> up (f a b) ct1 pt- CAlt u ct1 -> flip execState pt $- unlessM (sMember u) $ do- sInsert u- modify' $ up b ct1- CFoldGr u st p1 f z ct1 -> flip execState pt $- unlessM (sMember u) $ do- lc <- sMember (localU u)- if lc then do- sInsert u- modify' $ up z ct1- else do- let go z1 = do- modify' $ down p1 (CFoldGr u st p1 f z1 ct1)- sInsert u- modify' $ up z1 ct1- {-# INLINE go #-}- case st of- Strict -> let !z1 = f z b in go z1- NonStrict -> go (f z b)- CFoldMn u st p1 f z ct1 -> flip execState pt $- unlessM (sMember u) $ do- let go z1 = do- sInsert (localU u)- modify' $ up z1 ct1- unlessM (sMember u) $ do- sInsert u- modify' $ down p1 (CFoldMn u st p1 f z1 ct1)- {-# INLINE go #-}- case st of- Strict -> let !z1 = f z b in go z1- NonStrict -> go (f z b)- CMany u p1 f1 f2 f z ct1 -> flip execState pt $- unlessM (sMember u) $ do- lc <- sMember (localU u)- if lc then do- sInsert u- let !x = f1 b- modify' $ up x ct1- else do- let !z1 = f z b- modify' $ down p1 (CMany u p1 f1 f2 f z1 ct1)- sInsert u- let !x = f2 z1- modify' $ up x ct1+ CLiftA2A f p1 ct1 -> down p1 (CLiftA2B f b ct1) pt+ CLiftA2B f a ct1 -> matchSolo (f a b) $ \x -> up x ct1 pt+ CAlt u ct1 ->+ if sMember u pt+ then pt+ else up b ct1 (sInsert u pt)+ CFoldGr u p1 f z ct1 ->+ if sMember u pt+ then pt+ else+ if sMember (localU u) pt+ then up z ct1 (sInsert u pt)+ else matchSolo (f z b) $ \z1 ->+ let pt1 = down p1 (CFoldGr u p1 f z1 ct1) pt+ in up z1 ct1 (sInsert u pt1)+ CFoldMn u p1 f z ct1 ->+ if sMember u pt+ then pt+ else matchSolo (f z b) $ \z1 ->+ let pt1 = up z1 ct1 (sInsert (localU u) pt)+ in if sMember u pt1+ then pt1+ else down p1 (CFoldMn u p1 f z1 ct1) (sInsert u pt1)+ CMany u p1 f1 f2 f z ct1 ->+ if sMember u pt+ then pt+ else+ if sMember (localU u) pt+ then matchSolo (f1 b) $ \x -> up x ct1 (sInsert u pt)+ else+ matchSolo (f z b) $ \z1 ->+ matchSolo (f2 z1) $ \x ->+ let pt1 = down p1 (CMany u p1 f1 f2 f z1 ct1) pt+ in up x ct1 (sInsert u pt1) localU :: Unique -> Unique localU = Unique . (+1) . unUnique@@ -395,24 +400,21 @@ -- ==== __Examples__ -- -- @--- import qualified Data.Vector.Generic as VG -- from vector------ import Regex.Base (Parser) -- import qualified Regex.Base as R+-- import qualified Data.Vector.Generic as VG -- from vector ----- parseVector :: VG.Vector v c => Parser c a -> v c -> Maybe a+-- parseVector :: VG.Vector v c => R.Parser c a -> v c -> Maybe a -- parseVector p v = R.'parseFoldr' VG.foldr p v -- @ -- -- >>> import Control.Applicative (many)--- >>> import qualified Data.Vector as V--- >>> import Regex.Base (Parser) -- >>> import qualified Regex.Base as R+-- >>> import qualified Data.Vector as V -- >>> -- >>> let p = R.compile $ many ((,) <$> R.satisfy even <*> R.satisfy odd) :: Parser Int [(Int, Int)]--- >>> parseVector p (V.fromList [0..5])--- Just [(0,1),(2,3),(4,5)]--- >>> parseVector p (V.fromList [0,2..6])+-- >>> parseVector p (V.fromList [6,1,2,5,4,3])+-- Just [(6,1),(2,5),(4,3)]+-- >>> parseVector p (V.fromList [4,3,1,2]) -- Nothing -- parseFoldr :: Foldr f c -> Parser c a -> f -> Maybe a@@ -436,35 +438,30 @@ -- ==== __Examples__ -- -- @--- import Conduit (ConduitT, await, sinkNull) -- from conduit------ import Regex.Base (Parser) -- import qualified Regex.Base as R+-- import qualified Conduit as C -- from conduit ----- parseConduit :: Monad m => Parser c a -> ConduitT c x m (Maybe a)--- parseConduit p = R.'parseNext' p await <* sinkNull+-- parseConduit :: Monad m => R.Parser c a -> C.ConduitT c x m (Maybe a)+-- parseConduit p = R.'parseNext' p C.await <* C.sinkNull -- @ -- -- >>> import Control.Applicative (many)--- >>> import Conduit ((.|), iterMC, runConduit, yieldMany)--- >>> import Regex.Base (Parser) -- >>> import qualified Regex.Base as R+-- >>> import Conduit ((.|))+-- >>> import qualified Conduit as C -- >>> -- >>> let p = R.compile $ many ((,) <$> R.satisfy even <*> R.satisfy odd) :: Parser Int [(Int, Int)]--- >>> let printYieldMany xs = yieldMany xs .| iterMC print--- >>> runConduit $ printYieldMany [0..5] .| parseConduit p+-- >>> runConduit $ C.yieldMany [0..3] .| C.iterMC print .| parseConduit p -- 0 -- 1 -- 2 -- 3+-- Just [(0,1),(2,3)]+-- >>> runConduit $ C.yieldMany [4,3,1,2] .| C.iterMC print .| parseConduit p -- 4--- 5--- Just [(0,1),(2,3),(4,5)]--- >>> runConduit $ printYieldMany [0,2..6] .| parseConduit p--- 0+-- 3+-- 1 -- 2--- 4--- 6 -- Nothing -- -- @since 0.2.0.0@@ -479,15 +476,6 @@ Nothing -> pure Nothing Just ps' -> loop ps' {-# INLINE parseNext #-}-------------- Util------------unlessM :: Monad m => m Bool -> m () -> m ()-unlessM mb mx = do- b <- mb- if b then pure () else mx ----------------- -- Array compat
src/Regex/Internal/Regex.hs view
@@ -6,8 +6,6 @@ -- module Regex.Internal.Regex ( RE(..)- , Strictness(..)- , Greediness(..) , Many(..) , token@@ -53,6 +51,8 @@ import qualified Data.Foldable as F import qualified Data.Traversable as T +import Regex.Internal.Solo (Solo, mkSolo)+ --------------------------------- -- RE and constructor functions ---------------------------------@@ -90,35 +90,43 @@ -- /Performance tip/: Prefer the smaller of equivalent regexes, i.e. prefer -- @(a \<|> b) \<*> c@ over @(a \<*> c) \<|> (b \<*> c)@. --++-- See Note [Functions returning Solo] data RE c a where RToken :: !(c -> Maybe a) -> RE c a- RFmap :: !Strictness -> !(a1 -> a) -> !(RE c a1) -> RE c a+ RFmap :: !(a1 -> Solo a) -> !(RE c a1) -> RE c a RFmap_ :: a -> !(RE c a1) -> RE c a RPure :: a -> RE c a- RLiftA2 :: !Strictness -> !(a1 -> a2 -> a) -> !(RE c a1) -> !(RE c a2) -> RE c a+ RLiftA2 :: !(a1 -> a2 -> Solo a) -> !(RE c a1) -> !(RE c a2) -> RE c a REmpty :: RE c a RAlt :: !(RE c a) -> !(RE c a) -> RE c a- RFold :: !Strictness -> !Greediness -> !(a -> a1 -> a) -> a -> !(RE c a1) -> RE c a- RMany :: !(a1 -> a) -> !(a2 -> a) -> !(a2 -> a1 -> a2) -> !a2 -> !(RE c a1) -> RE c a -- Strict and greedy implicitly--data Strictness = Strict | NonStrict-data Greediness = Greedy | Minimal+ RFoldGr :: !(a -> a1 -> Solo a) -> a -> !(RE c a1) -> RE c a+ RFoldMn :: !(a -> a1 -> Solo a) -> a -> !(RE c a1) -> RE c a+ RMany :: !(a1 -> Solo a) -> !(a2 -> Solo a) -> !(a2 -> a1 -> Solo a2) -> !a2 -> !(RE c a1) -> RE c a -- Greedy instance Functor (RE c) where- fmap = RFmap NonStrict+ fmap f = RFmap (\x -> mkSolo (f x))+ {-# INLINE fmap #-}+ (<$) = RFmap_ fmap' :: (a -> b) -> RE c a -> RE c b-fmap' = RFmap Strict+fmap' f = RFmap (\x -> mkSolo $! f x)+{-# INLINE fmap' #-} instance Applicative (RE c) where pure = RPure- liftA2 = RLiftA2 NonStrict- re1 *> re2 = Ap.liftA2 (const id) (void re1) re2- re1 <* re2 = Ap.liftA2 const re1 (void re2) + liftA2 f = RLiftA2 (\x y -> mkSolo (f x y))+ {-# INLINE liftA2 #-}++ re1 *> re2 = RLiftA2 (\_ y -> mkSolo y) (void re1) re2++ re1 <* re2 = RLiftA2 (\x _ -> mkSolo x) re1 (void re2)+ liftA2' :: (a1 -> a2 -> b) -> RE c a1 -> RE c a2 -> RE c b-liftA2' = RLiftA2 Strict+liftA2' f = RLiftA2 (\x y -> mkSolo $! f x y)+{-# INLINE liftA2' #-} instance Alternative (RE c) where empty = REmpty@@ -150,24 +158,33 @@ -- -- Also see the section "Looping parsers". manyr :: RE c a -> RE c (Many a)-manyr = RMany Repeat (Finite . reverse) (flip (:)) []+manyr =+ RMany+ (\xs -> mkSolo (Repeat xs))+ (\xs -> mkSolo (Finite (reverse xs)))+ (\xs x -> mkSolo (x:xs))+ [] -- | Parse many occurences of the given @RE@. Biased towards matching more. -- -- Also see the section "Looping parsers". foldlMany :: (b -> a -> b) -> b -> RE c a -> RE c b-foldlMany = RFold NonStrict Greedy+foldlMany f = RFoldGr (\z x -> mkSolo (f z x))+{-# INLINE foldlMany #-} foldlMany' :: (b -> a -> b) -> b -> RE c a -> RE c b-foldlMany' f !z = RFold Strict Greedy f z+foldlMany' f !z = RFoldGr (\z' x -> mkSolo $! f z' x) z+{-# INLINE foldlMany' #-} -- | Parse many occurences of the given @RE@. Minimal, i.e. biased towards -- matching less. foldlManyMin :: (b -> a -> b) -> b -> RE c a -> RE c b-foldlManyMin = RFold NonStrict Minimal+foldlManyMin f = RFoldMn (\z x -> mkSolo (f z x))+{-# INLINE foldlManyMin #-} foldlManyMin' :: (b -> a -> b) -> b -> RE c a -> RE c b-foldlManyMin' f !z = RFold Strict Minimal f z+foldlManyMin' f !z = RFoldMn (\z' x -> mkSolo $! f z' x) z+{-# INLINE foldlManyMin' #-} -- | Parse a @c@ if it satisfies the given predicate. satisfy :: (c -> Bool) -> RE c c@@ -362,3 +379,33 @@ toFindMany re = reverse <$> foldlMany' (flip ($)) [] ((:) <$> re <|> id <$ anySingle)++----------+-- Notes+----------++-- Note [Functions returning Solo]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- We use `-> Solo a` functions in RFmap, RLiftA2, RFold, RMany to get better+-- control of the evaluation and avoid wastefully creating thunks.+--+-- Under normal circumstances, GHC does a good job of avoiding such thunks using+-- demand analysis. However, for a function stored in a RE, there is no way to+-- know its demand characteristics, making such optimizations impossible.+--+-- So, Solo is a way to get some /manual/ control over evaluation. For functions+-- where we want to avoid thunks we use strict combinators, e.g. `liftA2' (:)`,+-- so that forcing the Solo forces the result. Where we don't want to force the+-- result, we use lazy combinators which simply put the thunk in the Solo, e.g.+-- `fmap reverse`.+--+-- On GHC, Solo is implemented as an unboxed 1-tuple at no extra cost. It does+-- have a cost on non-GHC however.+--+-- An alternative is to store the strictness of the function alongside it, as a+-- Bool for instance, and force the result when applying the function if it is+-- strict. In fact, this is how it was originally implemented here. This method+-- adds memory costs to the RE and makes the code a little more complicated. The+-- current setup also might incur a memory cost if an unknown function has to+-- be wrapped in a function which returns Solo. But in practice the function is+-- usually statically known and wrapping function gets simplified.
+ src/Regex/Internal/Solo.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-}+#ifdef __GLASGOW_HASKELL__+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnliftedNewtypes #-}+#endif++-- | This is an internal module. You probably don't need to import this.+--+module Regex.Internal.Solo+ ( Solo+ , mkSolo+ , matchSolo+ ) where++mkSolo :: a -> Solo a+matchSolo :: Solo a -> (a -> b) -> b++#ifdef __GLASGOW_HASKELL__+newtype Solo a = Solo (# a #)+mkSolo x = Solo (# x #)+matchSolo (Solo (# x #)) f = f x+#else+data Solo a = Solo a+mkSolo = Solo+matchSolo (Solo x) f = f x+#endif
src/Regex/Internal/Text.hs view
@@ -81,10 +81,11 @@ import qualified Data.CharSet as CS import Regex.Internal.Parser (Parser) import qualified Regex.Internal.Parser as P-import Regex.Internal.Regex (RE(..), Greediness(..), Strictness(..))+import Regex.Internal.Regex (RE(..)) import qualified Regex.Internal.Regex as R import qualified Regex.Internal.Num as RNum import qualified Regex.Internal.Generated.CaseFold as CF+import Regex.Internal.Solo (Solo, mkSolo, matchSolo) ---------------------- -- Token and Text REs@@ -400,17 +401,16 @@ go :: REText b -> REText Text go re = case re of RToken t -> tokenMatch t- RFmap _ _ re1 -> go re1+ RFmap _ re1 -> go re1 RFmap_ _ re1 -> go re1- RPure _ -> RPure T.empty- RLiftA2 _ _ re1 re2 ->- RLiftA2 Strict unsafeAdjacentAppend (go re1) (go re2)- REmpty -> REmpty- RAlt re1 re2 -> RAlt (go re1) (go re2)+ RPure _ -> pure T.empty+ RLiftA2 _ re1 re2 -> R.liftA2' unsafeAdjacentAppend (go re1) (go re2)+ REmpty -> Ap.empty+ RAlt re1 re2 -> go re1 <|> go re2+ RFoldGr _ _ re1 -> R.foldlMany' unsafeAdjacentAppend T.empty (go re1)+ RFoldMn _ _ re1 -> R.foldlManyMin' unsafeAdjacentAppend T.empty (go re1) RMany _ _ _ _ re1 ->- RFold Strict Greedy unsafeAdjacentAppend T.empty (go re1)- RFold _ gr _ _ re1 ->- RFold Strict gr unsafeAdjacentAppend T.empty (go re1)+ R.foldlMany' unsafeAdjacentAppend T.empty (go re1) #else toMatch = fmap (T.pack . map tChar) . RL.toMatch #endif@@ -420,45 +420,36 @@ #ifdef __GLASGOW_HASKELL__ data WithMatch a = WM {-# UNPACK #-} !Text a -instance Functor WithMatch where- fmap f (WM t x) = WM t (f x)--fmapWM' :: (a -> b) -> WithMatch a -> WithMatch b-fmapWM' f (WM t x) = WM t $! f x+pureWM :: a -> WithMatch a+pureWM x = WM T.empty x -instance Applicative WithMatch where- pure = WM T.empty- liftA2 f (WM t1 x) (WM t2 y) = WM (unsafeAdjacentAppend t1 t2) (f x y)+fmapWM :: (a -> Solo b) -> WithMatch a -> WithMatch b+fmapWM f (WM t x) = matchSolo (f x) (WM t) -liftA2WM' :: (a1 -> a2 -> b) -> WithMatch a1 -> WithMatch a2 -> WithMatch b-liftA2WM' f (WM t1 x) (WM t2 y) = WM (unsafeAdjacentAppend t1 t2) $! f x y+liftA2WM :: (a1 -> a2 -> Solo b) -> WithMatch a1 -> WithMatch a2 -> WithMatch b+liftA2WM f (WM t1 x) (WM t2 y) =+ matchSolo (f x y) (WM (unsafeAdjacentAppend t1 t2)) withMatch = R.fmap' (\(WM t x) -> (t,x)) . go where go :: REText b -> REText (WithMatch b) go re = case re of RToken t -> tokenWithMatch t- RFmap st f re1 ->- let g = case st of- Strict -> fmapWM' f- NonStrict -> fmap f- in RFmap Strict g (go re1)- RFmap_ b re1 -> RFmap Strict (flip WM b) (toMatch re1)- RPure b -> RPure (pure b)- RLiftA2 st f re1 re2 ->- let g = case st of- Strict -> liftA2WM' f- NonStrict -> Ap.liftA2 f- in RLiftA2 Strict g (go re1) (go re2)- REmpty -> REmpty- RAlt re1 re2 -> RAlt (go re1) (go re2)+ RFmap f re1 -> R.fmap' (fmapWM f) (go re1)+ RFmap_ b re1 -> R.fmap' (flip WM b) (toMatch re1)+ RPure b -> pure (pureWM b)+ RLiftA2 f re1 re2 -> R.liftA2' (liftA2WM f) (go re1) (go re2)+ REmpty -> Ap.empty+ RAlt re1 re2 -> go re1 <|> go re2+ RFoldGr f z re1 -> R.foldlMany' (liftA2WM f) (pureWM z) (go re1)+ RFoldMn f z re1 -> R.foldlManyMin' (liftA2WM f) (pureWM z) (go re1) RMany f1 f2 f z re1 ->- RMany (fmapWM' f1) (fmapWM' f2) (liftA2WM' f) (pure z) (go re1)- RFold st gr f z re1 ->- let g = case st of- Strict -> liftA2WM' f- NonStrict -> Ap.liftA2 f- in RFold Strict gr g (pure z) (go re1)+ RMany+ (\x -> mkSolo $! fmapWM f1 x)+ (\x -> mkSolo $! fmapWM f2 x)+ (\x y -> mkSolo $! liftA2WM f x y)+ (pureWM z)+ (go re1) #else withMatch = fmap (\(toks, x) -> (T.pack (map tChar toks), x)) . RL.withMatch #endif
src/Regex/Internal/Unique.hs view
@@ -1,5 +1,3 @@-{-# OPTIONS_HADDOCK not-home #-}- -- | This is an internal module. You probably don't need to import this. -- -- = WARNING