packages feed

regex-base 0.93.2 → 0.94.0.0

raw patch · 10 files changed

+882/−807 lines, 10 filesdep +faildep +textdep ~arraydep ~basedep ~bytestringnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: fail, text

Dependency ranges changed: array, base, bytestring, containers, mtl

API changes (from Hackage documentation)

+ Text.Regex.Base.RegexLike: instance Text.Regex.Base.RegexLike.Extract Data.Text.Internal.Lazy.Text
+ Text.Regex.Base.RegexLike: instance Text.Regex.Base.RegexLike.Extract Data.Text.Internal.Text
- Text.Regex.Base.Impl: polymatchM :: (RegexLike a b, Monad m) => a -> b -> m b
+ Text.Regex.Base.Impl: polymatchM :: (RegexLike a b, MonadFail m) => a -> b -> m b
- Text.Regex.Base.RegexLike: makeRegexM :: (RegexMaker regex compOpt execOpt source, Monad m) => source -> m regex
+ Text.Regex.Base.RegexLike: makeRegexM :: (RegexMaker regex compOpt execOpt source, MonadFail m) => source -> m regex
- Text.Regex.Base.RegexLike: makeRegexOptsM :: (RegexMaker regex compOpt execOpt source, Monad m) => compOpt -> execOpt -> source -> m regex
+ Text.Regex.Base.RegexLike: makeRegexOptsM :: (RegexMaker regex compOpt execOpt source, MonadFail m) => compOpt -> execOpt -> source -> m regex
- Text.Regex.Base.RegexLike: matchM :: (RegexContext regex source target, Monad m) => regex -> source -> m target
+ Text.Regex.Base.RegexLike: matchM :: (RegexContext regex source target, MonadFail m) => regex -> source -> m target

Files

+ ChangeLog.md view
@@ -0,0 +1,13 @@+See also http://pvp.haskell.org/faq++## 0.94.0.0++- **Breaking change**: Switch RegExp API from the previously used `Monad(fail)` to `MonadFail(fail)` to denote matching failures++- Define `Extract Text` instances for strict and lazy `Text` types++- Compatibility with `base-4.13.0`++- Explicitly declare all modules `Safe` under SafeHaskell for GHC 7.4 and higher++----
− Text/Regex/Base.hs
@@ -1,56 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}--------------------------------------------------------------------------------- |------ Module      :  Text.Regex.Base--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (MPTC+FD)------ Classes and instances for Regex matching.------ --- This module merely imports and re-exports the common part of the new--- api: "Text.Regex.Base.RegexLike" and "Text.Regex.Base.Context".--- --- To see what result types the instances of RegexContext can produce,--- please read the "Text.Regex.Base.Context" haddock documentation.--- --- This does not provide any of the backends, just the common interface--- they all use.  The modules which provide the backends and their cabal--- packages are:--- ---  * @Text.Regex.Posix@ from regex-posix--- ---  * @Text.Regex@ from regex-compat (uses regex-posix)--- ---  * @Text.Regex.Parsec@ from regex-parsec--- ---  * @Text.Regex.DFA@ from regex-dfa--- ---  * @Text.Regex.PCRE@ from regex-pcre--- ---  * @Test.Regex.TRE@ from regex-tre--- --- In fact, just importing one of the backends is adequate, you do not--- also need to import this module.--- --- TODO: Copy Example*hs files into this haddock comment--------------------------------------------------------------------------------module Text.Regex.Base (getVersion_Text_Regex_Base-  -- | RegexLike defines classes and type, and 'Extract' instances-  ,module Text.Regex.Base.RegexLike) where--import Data.Version(Version(..))-import Text.Regex.Base.RegexLike-import Text.Regex.Base.Context()--getVersion_Text_Regex_Base :: Version-getVersion_Text_Regex_Base =-  Version { versionBranch = [0,93,2]-          , versionTags = ["unstable"]-          }
− Text/Regex/Base/Context.hs
@@ -1,409 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-|--Module      :  Text.Regex.Base.Context-Copyright   :  (c) Chris Kuklewicz 2006-License     :  BSD-style (see the file LICENSE)--Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com-Stability   :  experimental-Portability :  non-portable (MPTC+FD)--This is a module of instances of 'RegexContext' (defined in-Text.Regex.Base.RegexLike).  Nothing else is exported.  This is-usually imported via the Text.Regex.Base convenience package which-itself is re-exported from newer Text.Regex.XXX modules provided by-the different regex-xxx backends.--These instances work for all the supported types and backends-interchangably.  These instances provide the different results that-can be gotten from a match or matchM operation (often via the @=~@ and-@=~~@ operators with combine @makeRegex@ with @match@ and @matchM@-respectively).  This module name is Context because they operators are-context dependent: use them in a context that expects an Int and you-get a count of matches, use them in a Bool context and get True if-there is a match, etc.--@RegexContext a b c@ takes a regular expression suppied in a type 'a'-generated by 'RegexMaker' and a target text supplied in type 'b' to a-result type 'c' using the 'match' class function.  The 'matchM' class-function works like 'match' unless there is no match found, in which-case it calls 'fail' in the (arbitrary) monad context.--There are a few type synonyms from RegexLike that are used here:--@ --- | 0 based index from start of source, or (-1) for unused-type MatchOffset = Int--- | non-negative length of a match-type MatchLength = Int-type MatchArray = Array Int (MatchOffset, MatchLength)-type MatchText source = Array Int (source, (MatchOffset, MatchLength))-@--There are also a few newtypes that used to prevent any possible-overlap of types, which were not needed for GHC's late overlap-detection but are needed for use in Hugs.--@-newtype AllSubmatches f b = AllSubmatches {getAllSubmatches :: (f b)}-newtype AllTextSubmatches f b = AllTextSubmatches {getAllTextSubmatches :: (f b)}-newtype AllMatches f b = AllMatches {getAllMatches :: (f b)}-newtype AllTextMatches f b = AllTextMatches {getAllTextMatches :: (f b) }-@--The newtypes' @f@ parameters are the containers, usually @[]@ or-@Array Int@, (where the arrays all have lower bound 0).--The two *Submatches newtypes return only information on the first-match.  The other two newtypes return information on all the-non-overlapping matches.  The two *Text* newtypes are used to mark-result types that contain the same type as the target text.--Where provided, noncaptured submatches will have a @MatchOffset@ of-(-1) and non-negative otherwise.  The semantics of submatches depend-on the backend and its compile and execution options.  Where provided,-@MatchLength@ will always be non-negative.  Arrays with no elements-are returned with bounds of (1,0).  Arrays with elements will have a-lower bound of 0.--XXX THIS HADDOCK DOCUMENTATION IS OUT OF DATE XXX--These are for finding the first match in the target text:---@ RegexContext a b Bool @ :-  Whether there is any match or not.---@ RegexContext a b () @ :-  Useful as a guard with @matchM@ or @=~~@ in a monad, since failure to match calls 'fail'.---@ RegexContext a b b @ :-  This returns the text of the whole match.-  It will return 'empty' from the 'Extract' type class if there is no match.-  These are defined in each backend module, but documented here for convenience.---@ RegexContext a b (MatchOffset,MatchLength) @ :-  This returns the initial index and length of the whole match.-  MatchLength will always be non-negative, and 0 for a failed match.---@ RegexContext a b (MatchResult b) @ : The-  'MatchResult' structure with details for the match.  This is the-  structure copied from the old @JRegex@ pacakge.---@ RegexContext a b (b, b, b) @ :-  The text before the match, the text of the match, the text after the match---@ RegexContext a b (b, MatchText b, b) @ :-  The text before the match, the details of the match, and the text after the match---@ RegexContext a b (b, b, b, [b]) @ : -  The text before the match, the text of the match, the text after the-  match, and a list of the text of the 1st and higher sub-parts of the-  match.  This is the same return value as used in the old-  @Text.Regex@ API.--Two containers of the submatch offset information:---@ RegexContext a b MatchArray @ :-  Array of @(MatchOffset,MatchLength)@ for all the sub matches.-  The whole match is at the intial 0th index.-  Noncaptured submatches will have a @MatchOffset@ of (-1)-  The array will have no elements and bounds (1,0) if there is no match.---@ RegexContext a b (AllSubmatches [] (MatchOffset,MatchLength) @ :-  List of @(MatchOffset,MatchLength)@-  The whole match is the first element, the rest are the submatches (if any) in order.-  The list is empty if there is no match.--Two containers of the submatch text and offset information:--@ RegexContext a b (AllTextSubmatches (Array Int) (b, (MatchOffset, MatchLength))) @--@ RegexContext a b (AllTextSubmatches [] (b, (MatchOffset, MatchLength)))  @--Two containers of the submatch text information:--@ RegexContext a b (AllTextSubmatches [] b) @--@ RegexContext a b (AllTextSubmatches (Array Int) b) @--These instances are for all the matches (non-overlapping).  Note that-backends are supposed to supply 'RegexLike' instances for which the-default 'matchAll' and 'matchAllText' stop searching after returning-any successful but empty match.---@ RegexContext a b Int @ :-  The number of matches, non-negative.--Two containers for locations of all matches:--@ RegexContext a b (AllMatches [] (MatchOffset, MatchLength)) @--@ RegexContext a b (AllMatches (Array Int) (MatchOffset,MatchLength)) @--Two containers for the locations of all matches and their submatches:--@ RegexContext a b [MatchArray] @ :--@ RegexContext a b (AllMatches (Array Int) MatchArray) @--Two containers for the text and locations of all matches and their submatches:--@ RegexContext a b [MatchText b] @--@ RegexContext a b (AllTextMatches (Array Int) (MatchText b)) @--Two containers for text of all matches:-@ RegexContext a b (AllTextMatches [] b) @--@ RegexContext a b (AllTextMatches (Array Int) b) @--Four containers for text of all matches and their submatches:--@ RegexContext a b [[b]] @--@ RegexContext a b (AllTextMatches (Array Int) [b]) @--@ RegexContext a b (AllTextMatches [] (Array Int b)) @--@ RegexContext a b (AllTextMatches (Array Int) (Array Int b)) @--Unused matches are 'empty' (defined via 'Extract')---}--module Text.Regex.Base.Context() where--import Control.Monad(liftM)-import Data.Array(Array,(!),elems,listArray)---  import Data.Maybe(maybe)-import Text.Regex.Base.RegexLike(RegexLike(..),RegexContext(..)-  ,AllSubmatches(..),AllTextSubmatches(..),AllMatches(..),AllTextMatches(..)-  ,MatchResult(..),Extract(empty),MatchOffset,MatchLength,MatchArray,MatchText)---{---- Get the ByteString type for mood/doom-import Data.ByteString(ByteString)--- Get the Regex types for the mood/doom workaround-import qualified Text.Regex.Lib.WrapPosix as R1(Regex)-import qualified Text.Regex.Lib.WrapPCRE as R2(Regex)-import qualified Text.Regex.Lib.WrapLazy as R3(Regex)-import qualified Text.Regex.Lib.WrapDFAEngine as R4(Regex)--- Get the RegexLike instances-import Text.Regex.Lib.StringPosix()-import Text.Regex.Lib.StringPCRE()-import Text.Regex.Lib.StringLazy()-import Text.Regex.Lib.StringDFAEngine()-import Text.Regex.Lib.ByteStringPosix()-import Text.Regex.Lib.ByteStringPCRE()-import Text.Regex.Lib.ByteStringLazy()-import Text.Regex.Lib.ByteStringDFAEngine()--}-{---mood :: (RegexLike a b) => a -> b -> b-{-# INLINE mood #-}-mood r s = case matchOnceText r s of-    Nothing -> empty-    Just (_,ma,_) -> fst (ma!0)--doom :: (RegexLike a b,Monad m) => a -> b -> m b-{-# INLINE doom #-}-doom =  actOn (\(_,ma,_)->fst (ma!0))--{- These run afoul of various restrictions if I say-   "instance RegexContext a b b where"-   so I am listing these cases explicitly--}--instance RegexContext R1.Regex String String where match = mood; matchM = doom-instance RegexContext R2.Regex String String where match = mood; matchM = doom-instance RegexContext R3.Regex String String where match = mood; matchM = doom-instance RegexContext R4.Regex String String where match = mood; matchM = doom-instance RegexContext R1.Regex ByteString ByteString where match = mood; matchM = doom-instance RegexContext R2.Regex ByteString ByteString where match = mood; matchM = doom-instance RegexContext R3.Regex ByteString ByteString where match = mood; matchM = doom-instance RegexContext R4.Regex ByteString ByteString where match = mood; matchM = doom--}---nullArray :: Array Int a-{-# INLINE nullArray #-}-nullArray = listArray (1,0) []--nullFail :: (RegexContext regex source (AllMatches [] target),Monad m) => regex -> source -> m (AllMatches [] target)-{-# INLINE nullFail #-}-nullFail r s = case match r s of-                 (AllMatches []) -> regexFailed-                 xs -> return xs--nullFailText :: (RegexContext regex source (AllTextMatches [] target),Monad m) => regex -> source -> m (AllTextMatches [] target)-{-# INLINE nullFailText #-}-nullFailText r s = case match r s of-                     (AllTextMatches []) -> regexFailed-                     xs -> return xs--nullFail' :: (RegexContext regex source ([] target),Monad m) => regex -> source -> m ([] target)-{-# INLINE nullFail' #-}-nullFail' r s = case match r s of-                 ([]) -> regexFailed-                 xs -> return xs--regexFailed :: (Monad m) => m b-{-# INLINE regexFailed #-}-regexFailed =  fail $ "regex failed to match"--actOn :: (RegexLike r s,Monad m) => ((s,MatchText s,s)->t) -> r -> s -> m t-{-# INLINE actOn #-}-actOn f r s = case matchOnceText r s of-    Nothing -> regexFailed-    Just preMApost -> return (f preMApost)---- ** Instances based on matchTest ()--instance (RegexLike a b) => RegexContext a b Bool where -  match = matchTest-  matchM r s = case match r s of-                 False -> regexFailed-                 True -> return True--instance (RegexLike a b) => RegexContext a b () where-  match _ _ = ()-  matchM r s = case matchTest r s of-                 False -> regexFailed-                 True -> return ()---- ** Instance based on matchCount--instance (RegexLike a b) => RegexContext a b Int where-  match = matchCount-  matchM r s = case match r s of-                 0 -> regexFailed-                 x -> return x---- ** Instances based on matchOnce,matchOnceText--instance (RegexLike a b) => RegexContext a b (MatchOffset,MatchLength) where -  match r s = maybe (-1,0) (!0) (matchOnce r s)-  matchM r s = maybe regexFailed (return.(!0)) (matchOnce r s)--instance (RegexLike a b) => RegexContext a b (MatchResult b) where -  match r s = maybe (MR {mrBefore = s,mrMatch = empty,mrAfter = empty-                        ,mrSubs = nullArray,mrSubList = []}) id (matchM r s)-  matchM = actOn (\(pre,ma,post) -> -     let ((whole,_):subs) = elems ma-     in MR { mrBefore = pre-           , mrMatch = whole-           , mrAfter = post-           , mrSubs = fmap fst ma-           , mrSubList = map fst subs })--instance (RegexLike a b) => RegexContext a b (b,MatchText b,b) where -  match r s = maybe (s,nullArray,empty) id (matchOnceText r s)-  matchM r s = maybe regexFailed return (matchOnceText r s)--instance (RegexLike a b) => RegexContext a b (b,b,b) where -  match r s = maybe (s,empty,empty) id (matchM r s)-  matchM = actOn (\(pre,ma,post) -> let ((whole,_):_) = elems ma-                                    in (pre,whole,post))--instance (RegexLike a b) => RegexContext a b (b,b,b,[b]) where -  match r s = maybe (s,empty,empty,[]) id (matchM r s)-  matchM = actOn (\(pre,ma,post) -> let ((whole,_):subs) = elems ma-                                    in (pre,whole,post,map fst subs))---- now AllSubmatches wrapper-instance (RegexLike a b) => RegexContext a b MatchArray where -  match r s = maybe nullArray id (matchOnce r s)-  matchM r s = maybe regexFailed return (matchOnce r s)-instance (RegexLike a b) => RegexContext a b (AllSubmatches [] (MatchOffset,MatchLength)) where -  match r s = maybe (AllSubmatches []) id (matchM r s)-  matchM r s = case matchOnce r s of-                 Nothing -> regexFailed-                 Just ma -> return (AllSubmatches (elems ma))---- essentially AllSubmatches applied to (MatchText b)-instance (RegexLike a b) => RegexContext a b (AllTextSubmatches (Array Int) (b, (MatchOffset, MatchLength))) where -  match r s = maybe (AllTextSubmatches nullArray) id (matchM r s)-  matchM r s = actOn (\(_,ma,_) -> AllTextSubmatches ma) r s-instance (RegexLike a b) => RegexContext a b (AllTextSubmatches [] (b, (MatchOffset, MatchLength))) where -  match r s = maybe (AllTextSubmatches []) id (matchM r s)-  matchM r s = actOn (\(_,ma,_) -> AllTextSubmatches (elems ma)) r s--instance (RegexLike a b) => RegexContext a b (AllTextSubmatches [] b) where -  match r s = maybe (AllTextSubmatches []) id (matchM r s)-  matchM r s = liftM AllTextSubmatches $ actOn (\(_,ma,_) -> map fst . elems $ ma) r s-instance (RegexLike a b) => RegexContext a b (AllTextSubmatches (Array Int) b) where -  match r s = maybe (AllTextSubmatches nullArray) id (matchM r s)-  matchM r s = liftM AllTextSubmatches $ actOn (\(_,ma,_) -> fmap fst ma) r s---- ** Instances based on matchAll,matchAllText--instance (RegexLike a b) => RegexContext a b (AllMatches [] (MatchOffset,MatchLength)) where-  match r s = AllMatches [ ma!0 | ma <- matchAll r s ]-  matchM r s = nullFail r s-instance (RegexLike a b) => RegexContext a b (AllMatches (Array Int) (MatchOffset,MatchLength)) where-  match r s = maybe (AllMatches nullArray) id (matchM r s)-  matchM r s = case match r s of-                 (AllMatches []) -> regexFailed-                 (AllMatches pairs) -> return . AllMatches . listArray (0,pred $ length pairs) $ pairs---- No AllMatches wrapper-instance (RegexLike a b) => RegexContext a b [MatchArray] where-  match = matchAll-  matchM = nullFail'-instance (RegexLike a b) => RegexContext a b (AllMatches (Array Int) MatchArray) where-  match r s = maybe (AllMatches nullArray) id (matchM r s)-  matchM r s = case match r s of-                 [] -> regexFailed-                 mas -> return . AllMatches . listArray (0,pred $ length mas) $ mas---- No AllTextMatches wrapper-instance (RegexLike a b) => RegexContext a b [MatchText b] where-  match = matchAllText-  matchM = nullFail'-instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) (MatchText b)) where-  match r s = maybe (AllTextMatches nullArray) id (matchM r s)-  matchM r s = case match r s of-                 ([]) -> regexFailed-                 (mts) -> return . AllTextMatches . listArray (0,pred $ length mts) $ mts--instance (RegexLike a b) => RegexContext a b (AllTextMatches [] b) where-  match r s = AllTextMatches [ fst (ma!0) | ma <- matchAllText r s ]-  matchM r s = nullFailText r s-instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) b) where-  match r s = maybe (AllTextMatches nullArray) id (matchM r s)-  matchM r s = case match r s of-                 (AllTextMatches []) -> regexFailed-                 (AllTextMatches bs) -> return . AllTextMatches . listArray (0,pred $ length bs) $ bs---- No AllTextMatches wrapper-instance (RegexLike a b) => RegexContext a b [[b]] where-  match r s = [ map fst (elems ma) | ma <- matchAllText r s ]-  matchM r s = nullFail' r s-instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) [b]) where-  match r s = maybe (AllTextMatches nullArray) id (matchM r s)-  matchM r s = case match r s of-                 ([]) -> regexFailed-                 (ls) -> return . AllTextMatches . listArray (0,pred $ length ls) $ ls-instance (RegexLike a b) => RegexContext a b (AllTextMatches [] (Array Int b)) where-  match r s = AllTextMatches [ fmap fst ma | ma <- matchAllText r s ]-  matchM r s = nullFailText r s-instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) (Array Int b)) where-  match r s = maybe (AllTextMatches nullArray) id (matchM r s)-  matchM r s = case match r s of-                 (AllTextMatches []) -> regexFailed-                 (AllTextMatches as) -> return . AllTextMatches . listArray (0,pred $ length as) $ as
− Text/Regex/Base/Impl.hs
@@ -1,58 +0,0 @@--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Impl--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (Text.Regex.Base needs MPTC+FD)--- --- Helper functions for defining certain instances of--- RegexContext. These help when defining instances of RegexContext--- with repeated types:--- --- @--- instance (RegexLike regex source) => RegexContext regex source source where--- @--- --- runs into overlapping restrictions. To avoid this I have each backend--- define, for its own Regex type:--- --- @--- instance RegexContext Regex String String where---   match = polymatch---   matchM = polymatchM--- @--- --- @--- instance RegexContext Regex ByteString ByteString where---   match = polymatch---   matchM = polymatchM--- @----------------------------------------------------------------------------------module Text.Regex.Base.Impl(polymatch,polymatchM) where--import Text.Regex.Base-import Data.Array((!))--regexFailed :: (Monad m) => m b-{-# INLINE regexFailed #-}-regexFailed =  fail $ "regex failed to match"--actOn :: (RegexLike r s,Monad m) => ((s,MatchText s,s)->t) -> r -> s -> m t-{-# INLINE actOn #-}-actOn f r s = case matchOnceText r s of-    Nothing -> regexFailed-    Just preMApost -> return (f preMApost)--polymatch :: (RegexLike a b) => a -> b -> b-{-# INLINE polymatch #-}-polymatch r s = case matchOnceText r s of-    Nothing -> empty-    Just (_,ma,_) -> fst (ma!0)--polymatchM :: (RegexLike a b,Monad m) => a -> b -> m b-{-# INLINE polymatchM #-}-polymatchM =  actOn (\(_,ma,_)->fst (ma!0))
− Text/Regex/Base/RegexLike.hs
@@ -1,228 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Base.RegexLike--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (MPTC+FD)------ Classes and instances for Regex matching.------ --- All the classes are declared here, and some common type aliases, and--- the MatchResult data type.--- --- The only instances here are for Extract String and Extract ByteString.--- There are no data values.  The 'RegexContext' instances are in--- "Text.Regex.Base.Context", except for ones which run afoul of a--- repeated variable (RegexContext regex a a), which are defined in each--- modules' String and ByteString modules.--------------------------------------------------------------------------------module Text.Regex.Base.RegexLike (-  -- ** Type aliases-  MatchOffset,-  MatchLength,-  MatchArray,-  MatchText,-  -- ** Data types-  MatchResult(..),-  -- ** Classes-  RegexOptions(..),-  RegexMaker(..),-  RegexLike(..),-  RegexContext(..),-  Extract(..),-  AllSubmatches(..),AllTextSubmatches(..),AllMatches(..),AllTextMatches(..)-  ) where--import Data.Array(Array,(!))-import Data.Maybe(isJust)-import qualified Data.ByteString as B (take,drop,empty,ByteString)-import qualified Data.ByteString.Lazy as L (take,drop,empty,ByteString)-import qualified Data.Sequence as S(take,drop,empty,Seq)---- | 0 based index from start of source, or (-1) for unused-type MatchOffset = Int--- | non-negative length of a match-type MatchLength = Int--- | 0 based array, with 0th index indicating the full match.  If the--- full match location is not available, represent as (0,0).-type MatchArray = Array Int (MatchOffset,MatchLength)-type MatchText source = Array Int (source,(MatchOffset,MatchLength))---- | This is the same as the type from JRegex.-data MatchResult a = MR {-    mrBefore :: a,-    mrMatch  :: a,-    mrAfter  :: a,-    mrSubList :: [a],-    mrSubs   :: Array Int a-}--------------------- | Rather than carry them around spearately, the options for how to--- execute a regex are kept as part of the regex.  There are two types--- of options.  Those that can only be specified at compilation time--- and never changed are CompOpt.  Those that can be changed later and--- affect how matching is performed are ExecOpt.  The actually types--- for these depend on the backend.-class RegexOptions regex compOpt execOpt -  | regex->compOpt execOpt, compOpt->regex execOpt, execOpt->regex compOpt where-  blankCompOpt :: compOpt    -- ^ no options set at all in the backend-  blankExecOpt :: execOpt    -- ^ no options set at all in the backend-  defaultCompOpt :: compOpt  -- ^ reasonable options (extended,caseSensitive,multiline regex)-  defaultExecOpt :: execOpt  -- ^ reasonable options (extended,caseSensitive,multiline regex)-  setExecOpts :: execOpt -> regex -> regex-  -- ^ forget old flags and use new ones-  getExecOpts :: regex -> execOpt-  -- ^ retrieve the current flags--------------------- | RegexMaker captures the creation of the compiled regular--- expression from a source type and an option type.  'makeRegexM' and--- 'makeRegexM' report parse error using 'MonadError', usually (Either--- String regex).--- --- The 'makeRegex' function has a default implementation that depends--- on makeRegexOpts and used 'defaultCompOpt' and 'defaultExecOpt'.--- Similarly for 'makeRegexM' and 'makeRegexOptsM'.------ There are also default implementaions for 'makeRegexOpts' and--- 'makeRegexOptsM' in terms of each other.  So a minimal instance--- definition needs to only define one of these, hopefully--- 'makeRegexOptsM'.-class (RegexOptions regex compOpt execOpt) => RegexMaker regex compOpt execOpt source -  | regex -> compOpt execOpt, compOpt -> regex execOpt, execOpt -> regex compOpt where-  -- | make using the defaultCompOpt and defaultExecOpt-  makeRegex :: source -> regex-  -- | Specify your own options-  makeRegexOpts :: compOpt -> execOpt -> source -> regex-  -- | make using the defaultCompOpt and defaultExecOpt, reporting errors with fail-  makeRegexM :: (Monad m) => source -> m regex-  -- | Specify your own options, reporting errors with fail-  makeRegexOptsM :: (Monad m) => compOpt -> execOpt -> source -> m regex--  makeRegex = makeRegexOpts defaultCompOpt defaultExecOpt-  makeRegexM = makeRegexOptsM defaultCompOpt defaultExecOpt-  makeRegexOpts c e s = maybe (error "makeRegexOpts failed") id (makeRegexOptsM c e s)-  makeRegexOptsM c e s = return (makeRegexOpts c e s)--------------------- | RegexLike is parametrized on a regular expression type and a--- source type to run the matching on.------ There are default implementations: matchTest and matchOnceText use--- matchOnce; matchCount and matchAllText use matchAll. matchOnce uses--- matchOnceText and matchAll uses matchAllText. So a minimal complete--- instance need to provide at least (matchOnce or matchOnceText) and--- (matchAll or matchAllText).  Additional definitions are often--- provided where they will increase efficiency.------ > [ c | let notVowel = makeRegex "[^aeiou]" :: Regex, c <- ['a'..'z'], matchTest notVowel [c]  ]--- >--- > "bcdfghjklmnpqrstvwxyz"------ The strictness of these functions is instance dependent.-class (Extract source)=> RegexLike regex source where-  -- | This returns the first match in the source (it checks the whole-  -- source, not just at the start). This returns an array of-  -- (offset,length) index pairs for the match and captured-  -- substrings.  The offset is 0-based.  A (-1) for an offset means a-  -- failure to match.  The lower bound of the array is 0, and the 0th-  -- element is the (offset,length) for the whole match.-  matchOnce  :: regex -> source-> Maybe MatchArray-  -- | matchAll returns a list of matches.  The matches are in order-  -- and do not overlap. If any match succeeds but has 0 length then-  -- this will be the last match in the list.-  matchAll   :: regex -> source-> [MatchArray]-  -- | matchCount returns the number of non-overlapping matches-  -- returned by matchAll.-  matchCount :: regex -> source-> Int-  -- | matchTest return True if there is a match somewhere in the-  -- source (it checks the whole source not just at the start).-  matchTest  :: regex -> source-> Bool-  -- | This is matchAll with the actual subsections of the source-  -- instead of just the (offset,length) information.-  matchAllText  :: regex -> source-> [MatchText source]-  -- | This can return a tuple of three items: the source before the-  -- match, an array of the match and captured substrings (with their-  -- indices), and the source after the match.-  matchOnceText :: regex -> source-> Maybe (source,MatchText source,source)--  matchAll regex source = map (fmap snd) (matchAllText regex source)-  matchOnce regex source = fmap (\(_,mt,_) -> fmap snd mt) (matchOnceText regex source)-  matchTest regex source = isJust (matchOnce regex source)-  matchCount regex source = length (matchAll regex source)-  matchOnceText regex source = -    fmap (\ma -> let (o,l) = ma!0-                 in (before o source-                    ,fmap (\ol -> (extract ol source,ol)) ma-                    ,after (o+l) source))-         (matchOnce regex source)-  matchAllText regex source =-    map (fmap (\ol -> (extract ol source,ol)))-        (matchAll regex source)--------------------- | RegexContext is the polymorphic interface to do matching.  Since--- 'target' is polymorphic you may need to suply the type explicitly--- in contexts where it cannot be inferred.------ The monadic 'matchM' version uses 'fail' to report when the 'regex'--- has no match in 'source'.  Two examples:------ Here the contest 'Bool' is inferred:------ > [ c | let notVowel = makeRegex "[^aeiou]" :: Regex, c <- ['a'..'z'], match notVowel [c]  ]--- >--- > "bcdfghjklmnpqrstvwxyz"------ Here the context '[String]' must be supplied:------ > let notVowel = (makeRegex "[^aeiou]" :: Regex )--- > in do { c <- ['a'..'z'] ; matchM notVowel [c] } :: [String]--- >--- > ["b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z"]-class (RegexLike regex source) => RegexContext regex source target where-  match :: regex -> source -> target-  matchM :: (Monad m) => regex -> source -> m target--------------------- | Extract allows for indexing operations on String or ByteString.-class Extract source where-  -- | before is a renamed "take"-  before :: Int -> source -> source-  -- | after is a renamed "drop"-  after :: Int -> source -> source-  -- | For when there is no match, this can construct an empty data value-  empty :: source-  -- | extract takes an offset and length and has a default-  -- implementation of @extract (off,len) source = before len (after-  -- off source)@-  extract :: (Int,Int) -> source -> source-  extract (off,len) source = before len (after off source)--instance Extract String where-  before =  take; after = drop; empty = []--instance Extract B.ByteString where-  before = B.take; after = B.drop; empty = B.empty--instance Extract L.ByteString where-  before = L.take . toEnum; after = L.drop . toEnum; empty = L.empty--instance Extract (S.Seq a) where-  before = S.take; after = S.drop; empty = S.empty---- | Used in results of RegexContext instances-newtype AllSubmatches f b = AllSubmatches {getAllSubmatches :: (f b)}--- | Used in results of RegexContext instances-newtype AllTextSubmatches f b = AllTextSubmatches {getAllTextSubmatches :: (f b)}--- | Used in results of RegexContext instances-newtype AllMatches f b = AllMatches {getAllMatches :: (f b)}--- | Used in results of RegexContext instances-newtype AllTextMatches f b = AllTextMatches {getAllTextMatches :: (f b) }
regex-base.cabal view
@@ -1,58 +1,72 @@-Name:                   regex-base--- Keep the version below in sync with ./Text/Regex/Base.hs value getVersion_Text_Regex_Base :: Version-Version:                0.93.2-Cabal-Version:          >=1.2-License:                BSD3-License-File:           LICENSE-Copyright:              Copyright (c) 2006, Christopher Kuklewicz-Author:                 Christopher Kuklewicz-Maintainer:             TextRegexLazy@personal.mightyreason.com-Stability:              Seems to work, passes a few tests-Homepage:               http://sourceforge.net/projects/lazy-regex-Package-URL:            http://darcs.haskell.org/packages/regex-unstable/regex-base/-Synopsis:               Replaces/Enhances Text.Regex-Description:            Interface API for regex-posix,pcre,parsec,tdfa,dfa-Category:               Text-Tested-With:            GHC+cabal-version:          1.12+name:                   regex-base+version:                0.94.0.0+ build-type:             Simple-flag newBase-  description: Choose base >= 4-  default: True-flag splitBase-  description: Choose the new smaller, split-up base package.-  default: True+license:                BSD3+license-file:           LICENSE+copyright:              Copyright (c) 2006, Christopher Kuklewicz+author:                 Christopher Kuklewicz+maintainer:             hvr@gnu.org+homepage:               https://wiki.haskell.org/Regular_expressions+bug-reports:            https://github.com/hvr/regex-base/issues+synopsis:               Common "Text.Regex.*" API for Regex matching+category:               Text+description:+  This package doesn't provide the ability to do regex matching, but instead provides the type-classes that constitute the abstract API that is implemented by @regex-*@ backends such as+  .+  * <//hackage.haskell.org/package/regex-posix regex-posix>+  .+  * <//hackage.haskell.org/package/regex-parsec regex-parsec>+  .+  * <//hackage.haskell.org/package/regex-dfa regex-dfa>+  .+  * <//hackage.haskell.org/package/regex-tdfa regex-tdfa>+  .+  * <//hackage.haskell.org/package/regex-pcre regex-pcre>+  .+  See also <https://wiki.haskell.org/Regular_expressions> for more information.++extra-source-files:+  ChangeLog.md++source-repository head+  type:     git+  location: https://github.com/hvr/regex-base.git+ library-  if flag(newBase)-    Build-Depends:      base >=4 && < 5, mtl, containers, bytestring, array-    Extensions:         MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances, FlexibleContexts-  else-    if flag(splitBase)-      Build-Depends:      base >= 3.0, mtl, containers, bytestring, array-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances, FlexibleContexts-    else-      Build-Depends:      base < 3.0, mtl-      Extensions:         MultiParamTypeClasses, FunctionalDependencies-  -- Data-Files:-  -- Extra-Source-Files:-  -- Extra-Tmp-Files:-  Exposed-Modules:        Text.Regex.Base-                          Text.Regex.Base.RegexLike-                          Text.Regex.Base.Context-                          Text.Regex.Base.Impl-  Buildable:              True-  -- Other-Modules:-  -- HS-Source-Dirs:         "."-  GHC-Options:            -Wall -O2-  -- GHC-Options:            -Wall -Werror -O2-  -- GHC-Options:            -Wall -ddump-minimal-GHC-  -- imports-Prof-Options:       -auto-all-  -- Hugs-Options:-  -- NHC-Options:-  -- Includes:-  -- Include-Dirs:-  -- C-Sources:-  -- Extra-Libraries:-  -- Extra-Lib-Dirs:-  -- CC-Options:-  -- LD-Options:-  -- Frameworks:+  hs-source-dirs: src++  exposed-modules:+      Text.Regex.Base+      Text.Regex.Base.RegexLike+      Text.Regex.Base.Context+      Text.Regex.Base.Impl++  other-modules:+      Paths_regex_base++  default-language: Haskell2010+  other-extensions:+      MultiParamTypeClasses+      FunctionalDependencies+      TypeSynonymInstances+      FlexibleInstances+      FlexibleContexts++  if impl(ghc >= 7.4)+    default-extensions: Safe+    build-depends: containers >= 0.4.2.1+                 , bytestring >= 0.9.2.1++  build-depends: base       >= 4.3 && < 4.14+               , mtl        >= 1.1 && < 2.3+               , containers >= 0.4 && < 0.7+               , bytestring >= 0.9 && < 0.11+               , array      >= 0.3 && < 0.6+               , text       >= 1.2.3 && < 1.3++  if !impl(ghc >= 8)+      build-depends: fail == 4.9.*++  ghc-options: -Wall -O2
+ src/Text/Regex/Base.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}+-----------------------------------------------------------------------------+-- |+--+-- Module      :  Text.Regex.Base+-- Copyright   :  (c) Chris Kuklewicz 2006+-- SPDX-License-Identifier: BSD-3-Clause+--+-- Maintainer  :  hvr@gnu.org+-- Stability   :  experimental+-- Portability :  non-portable (MPTC+FD)+--+-- Classes and instances for Regex matching.+--+--+-- This module merely imports and re-exports the common part of the new+-- api: "Text.Regex.Base.RegexLike" and "Text.Regex.Base.Context".+--+-- To see what result types the instances of RegexContext can produce,+-- please read the "Text.Regex.Base.Context" haddock documentation.+--+-- This does not provide any of the backends, just the common interface+-- they all use.  The modules which provide the backends and their cabal+-- packages are:+--+--  * @Text.Regex.Posix@ from regex-posix+--+--  * @Text.Regex@ from regex-compat (uses regex-posix)+--+--  * @Text.Regex.Parsec@ from regex-parsec+--+--  * @Text.Regex.DFA@ from regex-dfa+--+--  * @Text.Regex.PCRE@ from regex-pcre+--+--  * @Test.Regex.TRE@ from regex-tre+--+-- In fact, just importing one of the backends is adequate, you do not+-- also need to import this module.+--+-- == Example+--+-- The code below+--+-- @+-- import Text.Regex.Base+-- import Text.Regex.Posix((=~),(=~~)) -- or DFA or PCRE or PosixRE+--+-- main = let b :: Bool+--            b = ("abaca" =~ "(.)a")+--            c :: [MatchArray]+--            c = ("abaca" =~ "(.)a")+--            d :: Maybe (String,String,String,[String])+--            d = ("abaca" =~~ "(.)a")+--        in do print b+--              print c+--              print d+-- @+--+-- will output+--+-- > True+-- > [array (0,1) [(0,(1,2)),(1,(1,1))],array (0,1) [(0,(3,2)),(1,(3,1))]]+-- > Just ("a","ba","ca",["b"])+--++-----------------------------------------------------------------------------++module Text.Regex.Base (getVersion_Text_Regex_Base+  -- | RegexLike defines classes and type, and 'Extract' instances+  ,module Text.Regex.Base.RegexLike) where++import Data.Version(Version(..))+import Text.Regex.Base.RegexLike+import Text.Regex.Base.Context()++import qualified Paths_regex_base++getVersion_Text_Regex_Base :: Version+getVersion_Text_Regex_Base = Paths_regex_base.version
+ src/Text/Regex/Base/Context.hs view
@@ -0,0 +1,412 @@+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-|++Module      :  Text.Regex.Base.Context+Copyright   :  (c) Chris Kuklewicz 2006+SPDX-License-Identifier: BSD-3-Clause++Maintainer  :  hvr@gnu.org+Stability   :  experimental+Portability :  non-portable (MPTC+FD)++This is a module of instances of 'RegexContext' (defined in+Text.Regex.Base.RegexLike).  Nothing else is exported.  This is+usually imported via the Text.Regex.Base convenience package which+itself is re-exported from newer Text.Regex.XXX modules provided by+the different regex-xxx backends.++These instances work for all the supported types and backends+interchangably.  These instances provide the different results that+can be gotten from a match or matchM operation (often via the @=~@ and+@=~~@ operators with combine @makeRegex@ with @match@ and @matchM@+respectively).  This module name is Context because they operators are+context dependent: use them in a context that expects an Int and you+get a count of matches, use them in a Bool context and get True if+there is a match, etc.++@RegexContext a b c@ takes a regular expression suppied in a type 'a'+generated by 'RegexMaker' and a target text supplied in type 'b' to a+result type 'c' using the 'match' class function.  The 'matchM' class+function works like 'match' unless there is no match found, in which+case it calls 'fail' in the (arbitrary) monad context.++There are a few type synonyms from RegexLike that are used here:++@ +-- | 0 based index from start of source, or (-1) for unused+type MatchOffset = Int+-- | non-negative length of a match+type MatchLength = Int+type MatchArray = Array Int (MatchOffset, MatchLength)+type MatchText source = Array Int (source, (MatchOffset, MatchLength))+@++There are also a few newtypes that used to prevent any possible+overlap of types, which were not needed for GHC's late overlap+detection but are needed for use in Hugs.++@+newtype AllSubmatches f b = AllSubmatches {getAllSubmatches :: (f b)}+newtype AllTextSubmatches f b = AllTextSubmatches {getAllTextSubmatches :: (f b)}+newtype AllMatches f b = AllMatches {getAllMatches :: (f b)}+newtype AllTextMatches f b = AllTextMatches {getAllTextMatches :: (f b) }+@++The newtypes' @f@ parameters are the containers, usually @[]@ or+@Array Int@, (where the arrays all have lower bound 0).++The two *Submatches newtypes return only information on the first+match.  The other two newtypes return information on all the+non-overlapping matches.  The two *Text* newtypes are used to mark+result types that contain the same type as the target text.++Where provided, noncaptured submatches will have a @MatchOffset@ of+(-1) and non-negative otherwise.  The semantics of submatches depend+on the backend and its compile and execution options.  Where provided,+@MatchLength@ will always be non-negative.  Arrays with no elements+are returned with bounds of (1,0).  Arrays with elements will have a+lower bound of 0.++XXX THIS HADDOCK DOCUMENTATION IS OUT OF DATE XXX++These are for finding the first match in the target text:+++@ RegexContext a b Bool @ :+  Whether there is any match or not.+++@ RegexContext a b () @ :+  Useful as a guard with @matchM@ or @=~~@ in a monad, since failure to match calls 'fail'.+++@ RegexContext a b b @ :+  This returns the text of the whole match.+  It will return 'empty' from the 'Extract' type class if there is no match.+  These are defined in each backend module, but documented here for convenience.+++@ RegexContext a b (MatchOffset,MatchLength) @ :+  This returns the initial index and length of the whole match.+  MatchLength will always be non-negative, and 0 for a failed match.+++@ RegexContext a b (MatchResult b) @ : The+  'MatchResult' structure with details for the match.  This is the+  structure copied from the old @JRegex@ pacakge.+++@ RegexContext a b (b, b, b) @ :+  The text before the match, the text of the match, the text after the match+++@ RegexContext a b (b, MatchText b, b) @ :+  The text before the match, the details of the match, and the text after the match+++@ RegexContext a b (b, b, b, [b]) @ : +  The text before the match, the text of the match, the text after the+  match, and a list of the text of the 1st and higher sub-parts of the+  match.  This is the same return value as used in the old+  @Text.Regex@ API.++Two containers of the submatch offset information:+++@ RegexContext a b MatchArray @ :+  Array of @(MatchOffset,MatchLength)@ for all the sub matches.+  The whole match is at the intial 0th index.+  Noncaptured submatches will have a @MatchOffset@ of (-1)+  The array will have no elements and bounds (1,0) if there is no match.+++@ RegexContext a b (AllSubmatches [] (MatchOffset,MatchLength) @ :+  List of @(MatchOffset,MatchLength)@+  The whole match is the first element, the rest are the submatches (if any) in order.+  The list is empty if there is no match.++Two containers of the submatch text and offset information:++@ RegexContext a b (AllTextSubmatches (Array Int) (b, (MatchOffset, MatchLength))) @++@ RegexContext a b (AllTextSubmatches [] (b, (MatchOffset, MatchLength)))  @++Two containers of the submatch text information:++@ RegexContext a b (AllTextSubmatches [] b) @++@ RegexContext a b (AllTextSubmatches (Array Int) b) @++These instances are for all the matches (non-overlapping).  Note that+backends are supposed to supply 'RegexLike' instances for which the+default 'matchAll' and 'matchAllText' stop searching after returning+any successful but empty match.+++@ RegexContext a b Int @ :+  The number of matches, non-negative.++Two containers for locations of all matches:++@ RegexContext a b (AllMatches [] (MatchOffset, MatchLength)) @++@ RegexContext a b (AllMatches (Array Int) (MatchOffset,MatchLength)) @++Two containers for the locations of all matches and their submatches:++@ RegexContext a b [MatchArray] @ :++@ RegexContext a b (AllMatches (Array Int) MatchArray) @++Two containers for the text and locations of all matches and their submatches:++@ RegexContext a b [MatchText b] @++@ RegexContext a b (AllTextMatches (Array Int) (MatchText b)) @++Two containers for text of all matches:+@ RegexContext a b (AllTextMatches [] b) @++@ RegexContext a b (AllTextMatches (Array Int) b) @++Four containers for text of all matches and their submatches:++@ RegexContext a b [[b]] @++@ RegexContext a b (AllTextMatches (Array Int) [b]) @++@ RegexContext a b (AllTextMatches [] (Array Int b)) @++@ RegexContext a b (AllTextMatches (Array Int) (Array Int b)) @++Unused matches are 'empty' (defined via 'Extract')++-}++module Text.Regex.Base.Context() where++import Prelude hiding (fail)+import Control.Monad.Fail (MonadFail(fail)) -- see 'regexFailed'++import Control.Monad(liftM)+import Data.Array(Array,(!),elems,listArray)+--  import Data.Maybe(maybe)+import Text.Regex.Base.RegexLike(RegexLike(..),RegexContext(..)+  ,AllSubmatches(..),AllTextSubmatches(..),AllMatches(..),AllTextMatches(..)+  ,MatchResult(..),Extract(empty),MatchOffset,MatchLength,MatchArray,MatchText)+++{-+-- Get the ByteString type for mood/doom+import Data.ByteString(ByteString)+-- Get the Regex types for the mood/doom workaround+import qualified Text.Regex.Lib.WrapPosix as R1(Regex)+import qualified Text.Regex.Lib.WrapPCRE as R2(Regex)+import qualified Text.Regex.Lib.WrapLazy as R3(Regex)+import qualified Text.Regex.Lib.WrapDFAEngine as R4(Regex)+-- Get the RegexLike instances+import Text.Regex.Lib.StringPosix()+import Text.Regex.Lib.StringPCRE()+import Text.Regex.Lib.StringLazy()+import Text.Regex.Lib.StringDFAEngine()+import Text.Regex.Lib.ByteStringPosix()+import Text.Regex.Lib.ByteStringPCRE()+import Text.Regex.Lib.ByteStringLazy()+import Text.Regex.Lib.ByteStringDFAEngine()+-}+{-++mood :: (RegexLike a b) => a -> b -> b+{-# INLINE mood #-}+mood r s = case matchOnceText r s of+    Nothing -> empty+    Just (_,ma,_) -> fst (ma!0)++doom :: (RegexLike a b,Monad m) => a -> b -> m b+{-# INLINE doom #-}+doom =  actOn (\(_,ma,_)->fst (ma!0))++{- These run afoul of various restrictions if I say+   "instance RegexContext a b b where"+   so I am listing these cases explicitly+-}++instance RegexContext R1.Regex String String where match = mood; matchM = doom+instance RegexContext R2.Regex String String where match = mood; matchM = doom+instance RegexContext R3.Regex String String where match = mood; matchM = doom+instance RegexContext R4.Regex String String where match = mood; matchM = doom+instance RegexContext R1.Regex ByteString ByteString where match = mood; matchM = doom+instance RegexContext R2.Regex ByteString ByteString where match = mood; matchM = doom+instance RegexContext R3.Regex ByteString ByteString where match = mood; matchM = doom+instance RegexContext R4.Regex ByteString ByteString where match = mood; matchM = doom+-}+++nullArray :: Array Int a+{-# INLINE nullArray #-}+nullArray = listArray (1,0) []++nullFail :: (RegexContext regex source (AllMatches [] target),MonadFail m) => regex -> source -> m (AllMatches [] target)+{-# INLINE nullFail #-}+nullFail r s = case match r s of+                 (AllMatches []) -> regexFailed+                 xs -> return xs++nullFailText :: (RegexContext regex source (AllTextMatches [] target),MonadFail m) => regex -> source -> m (AllTextMatches [] target)+{-# INLINE nullFailText #-}+nullFailText r s = case match r s of+                     (AllTextMatches []) -> regexFailed+                     xs -> return xs++nullFail' :: (RegexContext regex source ([] target),MonadFail m) => regex -> source -> m ([] target)+{-# INLINE nullFail' #-}+nullFail' r s = case match r s of+                 ([]) -> regexFailed+                 xs -> return xs++regexFailed :: (MonadFail m) => m b+{-# INLINE regexFailed #-}+regexFailed =  fail $ "regex failed to match"++actOn :: (RegexLike r s,MonadFail m) => ((s,MatchText s,s)->t) -> r -> s -> m t+{-# INLINE actOn #-}+actOn f r s = case matchOnceText r s of+    Nothing -> regexFailed+    Just preMApost -> return (f preMApost)++-- ** Instances based on matchTest ()++instance (RegexLike a b) => RegexContext a b Bool where +  match = matchTest+  matchM r s = case match r s of+                 False -> regexFailed+                 True -> return True++instance (RegexLike a b) => RegexContext a b () where+  match _ _ = ()+  matchM r s = case matchTest r s of+                 False -> regexFailed+                 True -> return ()++-- ** Instance based on matchCount++instance (RegexLike a b) => RegexContext a b Int where+  match = matchCount+  matchM r s = case match r s of+                 0 -> regexFailed+                 x -> return x++-- ** Instances based on matchOnce,matchOnceText++instance (RegexLike a b) => RegexContext a b (MatchOffset,MatchLength) where +  match r s = maybe (-1,0) (!0) (matchOnce r s)+  matchM r s = maybe regexFailed (return.(!0)) (matchOnce r s)++instance (RegexLike a b) => RegexContext a b (MatchResult b) where +  match r s = maybe (MR {mrBefore = s,mrMatch = empty,mrAfter = empty+                        ,mrSubs = nullArray,mrSubList = []}) id (matchM r s)+  matchM = actOn (\(pre,ma,post) -> +     let ((whole,_):subs) = elems ma+     in MR { mrBefore = pre+           , mrMatch = whole+           , mrAfter = post+           , mrSubs = fmap fst ma+           , mrSubList = map fst subs })++instance (RegexLike a b) => RegexContext a b (b,MatchText b,b) where +  match r s = maybe (s,nullArray,empty) id (matchOnceText r s)+  matchM r s = maybe regexFailed return (matchOnceText r s)++instance (RegexLike a b) => RegexContext a b (b,b,b) where +  match r s = maybe (s,empty,empty) id (matchM r s)+  matchM = actOn (\(pre,ma,post) -> let ((whole,_):_) = elems ma+                                    in (pre,whole,post))++instance (RegexLike a b) => RegexContext a b (b,b,b,[b]) where +  match r s = maybe (s,empty,empty,[]) id (matchM r s)+  matchM = actOn (\(pre,ma,post) -> let ((whole,_):subs) = elems ma+                                    in (pre,whole,post,map fst subs))++-- now AllSubmatches wrapper+instance (RegexLike a b) => RegexContext a b MatchArray where +  match r s = maybe nullArray id (matchOnce r s)+  matchM r s = maybe regexFailed return (matchOnce r s)+instance (RegexLike a b) => RegexContext a b (AllSubmatches [] (MatchOffset,MatchLength)) where +  match r s = maybe (AllSubmatches []) id (matchM r s)+  matchM r s = case matchOnce r s of+                 Nothing -> regexFailed+                 Just ma -> return (AllSubmatches (elems ma))++-- essentially AllSubmatches applied to (MatchText b)+instance (RegexLike a b) => RegexContext a b (AllTextSubmatches (Array Int) (b, (MatchOffset, MatchLength))) where +  match r s = maybe (AllTextSubmatches nullArray) id (matchM r s)+  matchM r s = actOn (\(_,ma,_) -> AllTextSubmatches ma) r s+instance (RegexLike a b) => RegexContext a b (AllTextSubmatches [] (b, (MatchOffset, MatchLength))) where +  match r s = maybe (AllTextSubmatches []) id (matchM r s)+  matchM r s = actOn (\(_,ma,_) -> AllTextSubmatches (elems ma)) r s++instance (RegexLike a b) => RegexContext a b (AllTextSubmatches [] b) where +  match r s = maybe (AllTextSubmatches []) id (matchM r s)+  matchM r s = liftM AllTextSubmatches $ actOn (\(_,ma,_) -> map fst . elems $ ma) r s+instance (RegexLike a b) => RegexContext a b (AllTextSubmatches (Array Int) b) where +  match r s = maybe (AllTextSubmatches nullArray) id (matchM r s)+  matchM r s = liftM AllTextSubmatches $ actOn (\(_,ma,_) -> fmap fst ma) r s++-- ** Instances based on matchAll,matchAllText++instance (RegexLike a b) => RegexContext a b (AllMatches [] (MatchOffset,MatchLength)) where+  match r s = AllMatches [ ma!0 | ma <- matchAll r s ]+  matchM r s = nullFail r s+instance (RegexLike a b) => RegexContext a b (AllMatches (Array Int) (MatchOffset,MatchLength)) where+  match r s = maybe (AllMatches nullArray) id (matchM r s)+  matchM r s = case match r s of+                 (AllMatches []) -> regexFailed+                 (AllMatches pairs) -> return . AllMatches . listArray (0,pred $ length pairs) $ pairs++-- No AllMatches wrapper+instance (RegexLike a b) => RegexContext a b [MatchArray] where+  match = matchAll+  matchM = nullFail'+instance (RegexLike a b) => RegexContext a b (AllMatches (Array Int) MatchArray) where+  match r s = maybe (AllMatches nullArray) id (matchM r s)+  matchM r s = case match r s of+                 [] -> regexFailed+                 mas -> return . AllMatches . listArray (0,pred $ length mas) $ mas++-- No AllTextMatches wrapper+instance (RegexLike a b) => RegexContext a b [MatchText b] where+  match = matchAllText+  matchM = nullFail'+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) (MatchText b)) where+  match r s = maybe (AllTextMatches nullArray) id (matchM r s)+  matchM r s = case match r s of+                 ([]) -> regexFailed+                 (mts) -> return . AllTextMatches . listArray (0,pred $ length mts) $ mts++instance (RegexLike a b) => RegexContext a b (AllTextMatches [] b) where+  match r s = AllTextMatches [ fst (ma!0) | ma <- matchAllText r s ]+  matchM r s = nullFailText r s+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) b) where+  match r s = maybe (AllTextMatches nullArray) id (matchM r s)+  matchM r s = case match r s of+                 (AllTextMatches []) -> regexFailed+                 (AllTextMatches bs) -> return . AllTextMatches . listArray (0,pred $ length bs) $ bs++-- No AllTextMatches wrapper+instance (RegexLike a b) => RegexContext a b [[b]] where+  match r s = [ map fst (elems ma) | ma <- matchAllText r s ]+  matchM r s = nullFail' r s+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) [b]) where+  match r s = maybe (AllTextMatches nullArray) id (matchM r s)+  matchM r s = case match r s of+                 ([]) -> regexFailed+                 (ls) -> return . AllTextMatches . listArray (0,pred $ length ls) $ ls+instance (RegexLike a b) => RegexContext a b (AllTextMatches [] (Array Int b)) where+  match r s = AllTextMatches [ fmap fst ma | ma <- matchAllText r s ]+  matchM r s = nullFailText r s+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) (Array Int b)) where+  match r s = maybe (AllTextMatches nullArray) id (matchM r s)+  matchM r s = case match r s of+                 (AllTextMatches []) -> regexFailed+                 (AllTextMatches as) -> return . AllTextMatches . listArray (0,pred $ length as) $ as
+ src/Text/Regex/Base/Impl.hs view
@@ -0,0 +1,67 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Impl+-- Copyright   :  (c) Chris Kuklewicz 2006+-- SPDX-License-Identifier: BSD-3-Clause+-- +-- Maintainer  :  hvr@gnu.org+-- Stability   :  experimental+-- Portability :  non-portable (Text.Regex.Base needs MPTC+FD)+-- +-- Helper functions for defining certain instances of+-- RegexContext. These help when defining instances of RegexContext+-- with repeated types:+-- +-- @+-- instance (RegexLike regex source) => RegexContext regex source source where+-- @+-- +-- runs into overlapping restrictions. To avoid this I have each backend+-- define, for its own Regex type:+-- +-- @+-- instance RegexContext Regex String String where+--   match = polymatch+--   matchM = polymatchM+-- @+-- +-- @+-- instance RegexContext Regex ByteString ByteString where+--   match = polymatch+--   matchM = polymatchM+-- @+-- +-- @+-- instance RegexContext Regex Text Text where+--   match = polymatch+--   matchM = polymatchM+-- @+-------------------------------------------------------------------------------++module Text.Regex.Base.Impl(polymatch,polymatchM) where++import Prelude hiding (fail)+import Control.Monad.Fail (MonadFail(fail))++import Text.Regex.Base+import Data.Array((!))++regexFailed :: (MonadFail m) => m b+{-# INLINE regexFailed #-}+regexFailed =  fail $ "regex failed to match"++actOn :: (RegexLike r s,MonadFail m) => ((s,MatchText s,s)->t) -> r -> s -> m t+{-# INLINE actOn #-}+actOn f r s = case matchOnceText r s of+    Nothing -> regexFailed+    Just preMApost -> return (f preMApost)++polymatch :: (RegexLike a b) => a -> b -> b+{-# INLINE polymatch #-}+polymatch r s = case matchOnceText r s of+    Nothing -> empty+    Just (_,ma,_) -> fst (ma!0)++polymatchM :: (RegexLike a b,MonadFail m) => a -> b -> m b+{-# INLINE polymatchM #-}+polymatchM =  actOn (\(_,ma,_)->fst (ma!0))
+ src/Text/Regex/Base/RegexLike.hs view
@@ -0,0 +1,240 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, TypeSynonymInstances #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Base.RegexLike+-- Copyright   :  (c) Chris Kuklewicz 2006+-- SPDX-License-Identifier: BSD-3-Clause+--+-- Maintainer  :  hvr@gnu.org+-- Stability   :  experimental+-- Portability :  non-portable (MPTC+FD)+--+-- Classes and instances for Regex matching.+--+-- All the classes are declared here, and some common type aliases, and+-- the MatchResult data type.+--+-- The only instances here are for 'Extract' 'String', 'Extract' 'SB.ByteString',+-- and 'Extract' 'ST.Text'. There are no data values.  The 'RegexContext'+-- instances are in "Text.Regex.Base.Context", except for ones which+-- run afoul of a repeated variable ('RegexContext' regex a a), which+-- are defined in each modules' String and ByteString modules.+-----------------------------------------------------------------------------++module Text.Regex.Base.RegexLike (+  -- ** Type aliases+  MatchOffset,+  MatchLength,+  MatchArray,+  MatchText,+  -- ** Data types+  MatchResult(..),+  -- ** Classes+  RegexOptions(..),+  RegexMaker(..),+  RegexLike(..),+  RegexContext(..),+  Extract(..),+  AllSubmatches(..),AllTextSubmatches(..),AllMatches(..),AllTextMatches(..)+  ) where++import Prelude hiding (fail)+import Control.Monad.Fail as Fail (MonadFail)++import Data.Array(Array,(!))+import Data.Maybe(isJust)+import qualified Data.ByteString as SB (take,drop,empty,ByteString)+import qualified Data.ByteString.Lazy as LB (take,drop,empty,ByteString)+import qualified Data.Sequence as S(take,drop,empty,Seq)+import qualified Data.Text as ST (take,drop,empty,Text)+import qualified Data.Text.Lazy as LT (take,drop,empty,Text)++-- | 0 based index from start of source, or (-1) for unused+type MatchOffset = Int+-- | non-negative length of a match+type MatchLength = Int+-- | 0 based array, with 0th index indicating the full match.  If the+-- full match location is not available, represent as (0,0).+type MatchArray = Array Int (MatchOffset,MatchLength)+type MatchText source = Array Int (source,(MatchOffset,MatchLength))++-- | This is the same as the type from JRegex.+data MatchResult a = MR {+    mrBefore :: a,+    mrMatch  :: a,+    mrAfter  :: a,+    mrSubList :: [a],+    mrSubs   :: Array Int a+}++----------------+-- | Rather than carry them around spearately, the options for how to+-- execute a regex are kept as part of the regex.  There are two types+-- of options.  Those that can only be specified at compilation time+-- and never changed are CompOpt.  Those that can be changed later and+-- affect how matching is performed are ExecOpt.  The actually types+-- for these depend on the backend.+class RegexOptions regex compOpt execOpt +  | regex->compOpt execOpt, compOpt->regex execOpt, execOpt->regex compOpt where+  blankCompOpt :: compOpt    -- ^ no options set at all in the backend+  blankExecOpt :: execOpt    -- ^ no options set at all in the backend+  defaultCompOpt :: compOpt  -- ^ reasonable options (extended,caseSensitive,multiline regex)+  defaultExecOpt :: execOpt  -- ^ reasonable options (extended,caseSensitive,multiline regex)+  setExecOpts :: execOpt -> regex -> regex+  -- ^ forget old flags and use new ones+  getExecOpts :: regex -> execOpt+  -- ^ retrieve the current flags++----------------+-- | RegexMaker captures the creation of the compiled regular+-- expression from a source type and an option type.  'makeRegexM' and+-- 'makeRegexM' report parse error using 'MonadError', usually (Either+-- String regex).+-- +-- The 'makeRegex' function has a default implementation that depends+-- on makeRegexOpts and used 'defaultCompOpt' and 'defaultExecOpt'.+-- Similarly for 'makeRegexM' and 'makeRegexOptsM'.+--+-- There are also default implementaions for 'makeRegexOpts' and+-- 'makeRegexOptsM' in terms of each other.  So a minimal instance+-- definition needs to only define one of these, hopefully+-- 'makeRegexOptsM'.+class (RegexOptions regex compOpt execOpt) => RegexMaker regex compOpt execOpt source +  | regex -> compOpt execOpt, compOpt -> regex execOpt, execOpt -> regex compOpt where+  -- | make using the defaultCompOpt and defaultExecOpt+  makeRegex :: source -> regex+  -- | Specify your own options+  makeRegexOpts :: compOpt -> execOpt -> source -> regex+  -- | make using the defaultCompOpt and defaultExecOpt, reporting errors with fail+  makeRegexM :: (Fail.MonadFail m) => source -> m regex+  -- | Specify your own options, reporting errors with fail+  makeRegexOptsM :: (MonadFail m) => compOpt -> execOpt -> source -> m regex++  makeRegex = makeRegexOpts defaultCompOpt defaultExecOpt+  makeRegexM = makeRegexOptsM defaultCompOpt defaultExecOpt+  makeRegexOpts c e s = maybe (error "makeRegexOpts failed") id (makeRegexOptsM c e s)+  makeRegexOptsM c e s = return (makeRegexOpts c e s)++----------------+-- | RegexLike is parametrized on a regular expression type and a+-- source type to run the matching on.+--+-- There are default implementations: matchTest and matchOnceText use+-- matchOnce; matchCount and matchAllText use matchAll. matchOnce uses+-- matchOnceText and matchAll uses matchAllText. So a minimal complete+-- instance need to provide at least (matchOnce or matchOnceText) and+-- (matchAll or matchAllText).  Additional definitions are often+-- provided where they will increase efficiency.+--+-- > [ c | let notVowel = makeRegex "[^aeiou]" :: Regex, c <- ['a'..'z'], matchTest notVowel [c]  ]+-- >+-- > "bcdfghjklmnpqrstvwxyz"+--+-- The strictness of these functions is instance dependent.+class (Extract source)=> RegexLike regex source where+  -- | This returns the first match in the source (it checks the whole+  -- source, not just at the start). This returns an array of+  -- (offset,length) index pairs for the match and captured+  -- substrings.  The offset is 0-based.  A (-1) for an offset means a+  -- failure to match.  The lower bound of the array is 0, and the 0th+  -- element is the (offset,length) for the whole match.+  matchOnce  :: regex -> source-> Maybe MatchArray+  -- | matchAll returns a list of matches.  The matches are in order+  -- and do not overlap. If any match succeeds but has 0 length then+  -- this will be the last match in the list.+  matchAll   :: regex -> source-> [MatchArray]+  -- | matchCount returns the number of non-overlapping matches+  -- returned by matchAll.+  matchCount :: regex -> source-> Int+  -- | matchTest return True if there is a match somewhere in the+  -- source (it checks the whole source not just at the start).+  matchTest  :: regex -> source-> Bool+  -- | This is matchAll with the actual subsections of the source+  -- instead of just the (offset,length) information.+  matchAllText  :: regex -> source-> [MatchText source]+  -- | This can return a tuple of three items: the source before the+  -- match, an array of the match and captured substrings (with their+  -- indices), and the source after the match.+  matchOnceText :: regex -> source-> Maybe (source,MatchText source,source)++  matchAll regex source = map (fmap snd) (matchAllText regex source)+  matchOnce regex source = fmap (\(_,mt,_) -> fmap snd mt) (matchOnceText regex source)+  matchTest regex source = isJust (matchOnce regex source)+  matchCount regex source = length (matchAll regex source)+  matchOnceText regex source = +    fmap (\ma -> let (o,l) = ma!0+                 in (before o source+                    ,fmap (\ol -> (extract ol source,ol)) ma+                    ,after (o+l) source))+         (matchOnce regex source)+  matchAllText regex source =+    map (fmap (\ol -> (extract ol source,ol)))+        (matchAll regex source)++----------------+-- | RegexContext is the polymorphic interface to do matching.  Since+-- 'target' is polymorphic you may need to suply the type explicitly+-- in contexts where it cannot be inferred.+--+-- The monadic 'matchM' version uses 'fail' to report when the 'regex'+-- has no match in 'source'.  Two examples:+--+-- Here the contest 'Bool' is inferred:+--+-- > [ c | let notVowel = makeRegex "[^aeiou]" :: Regex, c <- ['a'..'z'], match notVowel [c]  ]+-- >+-- > "bcdfghjklmnpqrstvwxyz"+--+-- Here the context '[String]' must be supplied:+--+-- > let notVowel = (makeRegex "[^aeiou]" :: Regex )+-- > in do { c <- ['a'..'z'] ; matchM notVowel [c] } :: [String]+-- >+-- > ["b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z"]+class (RegexLike regex source) => RegexContext regex source target where+  match :: regex -> source -> target+  matchM :: (MonadFail m) => regex -> source -> m target++----------------+-- | Extract allows for indexing operations on String or ByteString.+class Extract source where+  -- | before is a renamed "take"+  before :: Int -> source -> source+  -- | after is a renamed "drop"+  after :: Int -> source -> source+  -- | For when there is no match, this can construct an empty data value+  empty :: source+  -- | extract takes an offset and length and has a default+  -- implementation of @extract (off,len) source = before len (after+  -- off source)@+  extract :: (Int,Int) -> source -> source+  extract (off,len) source = before len (after off source)++instance Extract String where+  before =  take; after = drop; empty = []++instance Extract SB.ByteString where+  before = SB.take; after = SB.drop; empty = SB.empty++instance Extract LB.ByteString where+  before = LB.take . toEnum; after = LB.drop . toEnum; empty = LB.empty++instance Extract (S.Seq a) where+  before = S.take; after = S.drop; empty = S.empty++-- | @since 0.94.0.0+instance Extract ST.Text where+  before = ST.take; after = ST.drop; empty = ST.empty++-- | @since 0.94.0.0+instance Extract LT.Text where+  before = LT.take . toEnum; after = LT.drop . toEnum; empty = LT.empty++-- | Used in results of RegexContext instances+newtype AllSubmatches f b = AllSubmatches {getAllSubmatches :: (f b)}+-- | Used in results of RegexContext instances+newtype AllTextSubmatches f b = AllTextSubmatches {getAllTextSubmatches :: (f b)}+-- | Used in results of RegexContext instances+newtype AllMatches f b = AllMatches {getAllMatches :: (f b)}+-- | Used in results of RegexContext instances+newtype AllTextMatches f b = AllTextMatches {getAllTextMatches :: (f b) }