{-|
This modules provides 'RegexMaker' and 'RegexLike' instances for using
@ByteString@ with the DFA backend ("Text.Regex.Lib.WrapDFAEngine" and
"Text.Regex.Lazy.DFAEngineFPS").  This module is usually used via
import "Text.Regex.TDFA".

This exports instances of the high level API and the medium level
API of 'compile','execute', and 'regexec'.
-}
{- By Chris Kuklewicz, 2009. BSD License, see the LICENSE file. -}
module Text.Regex.TDFA.ByteString(
  Regex
 ,CompOption
 ,ExecOption
 ,compile
 ,execute
 ,regexec
 ) where

import Data.Array((!),elems)
import qualified Data.ByteString.Char8 as B(ByteString,take,drop,unpack)

import Text.Regex.Base(MatchArray,RegexContext(..),RegexMaker(..),RegexLike(..))
import Text.Regex.Base.Impl(polymatch,polymatchM)
import Text.Regex.TDFA.ReadRegex(parseRegex)
import Text.Regex.TDFA.String() -- piggyback on RegexMaker for String
import Text.Regex.TDFA.TDFA(patternToRegex)
import Text.Regex.TDFA.Common(Regex(..),CompOption,ExecOption(captureGroups))

import Data.Maybe(listToMaybe)
import Text.Regex.TDFA.NewDFA.Engine(execMatch)
import Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest)

instance RegexContext Regex B.ByteString B.ByteString where
  match :: Regex -> ByteString -> ByteString
match = Regex -> ByteString -> ByteString
forall a b. RegexLike a b => a -> b -> b
polymatch
  matchM :: Regex -> ByteString -> m ByteString
matchM = Regex -> ByteString -> m ByteString
forall a b (m :: * -> *).
(RegexLike a b, MonadFail m) =>
a -> b -> m b
polymatchM

instance RegexMaker Regex CompOption ExecOption B.ByteString where
  makeRegexOptsM :: CompOption -> ExecOption -> ByteString -> m Regex
makeRegexOptsM CompOption
c ExecOption
e ByteString
source = CompOption -> ExecOption -> [Char] -> m Regex
forall regex compOpt execOpt source (m :: * -> *).
(RegexMaker regex compOpt execOpt source, MonadFail m) =>
compOpt -> execOpt -> source -> m regex
makeRegexOptsM CompOption
c ExecOption
e (ByteString -> [Char]
B.unpack ByteString
source)

instance RegexLike Regex B.ByteString where
  matchOnce :: Regex -> ByteString -> Maybe MatchArray
matchOnce Regex
r ByteString
s = [MatchArray] -> Maybe MatchArray
forall a. [a] -> Maybe a
listToMaybe (Regex -> ByteString -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
r ByteString
s)
  matchAll :: Regex -> ByteString -> [MatchArray]
matchAll Regex
r ByteString
s = Regex -> Int -> Char -> ByteString -> [MatchArray]
forall text.
Uncons text =>
Regex -> Int -> Char -> text -> [MatchArray]
execMatch Regex
r Int
0 Char
'\n' ByteString
s
  matchCount :: Regex -> ByteString -> Int
matchCount Regex
r ByteString
s = [MatchArray] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Regex -> ByteString -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
r' ByteString
s)
    where r' :: Regex
r' = Regex
r { regex_execOptions :: ExecOption
regex_execOptions = (Regex -> ExecOption
regex_execOptions Regex
r) {captureGroups :: Bool
captureGroups = Bool
False} }
  matchTest :: Regex -> ByteString -> Bool
matchTest = Regex -> ByteString -> Bool
forall text. Uncons text => Regex -> text -> Bool
Tester.matchTest
  matchOnceText :: Regex
-> ByteString
-> Maybe (ByteString, MatchText ByteString, ByteString)
matchOnceText Regex
regex ByteString
source =
    (MatchArray -> (ByteString, MatchText ByteString, ByteString))
-> Maybe MatchArray
-> Maybe (ByteString, MatchText ByteString, ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\MatchArray
ma -> let (Int
o,Int
l) = MatchArray
maMatchArray -> Int -> (Int, Int)
forall i e. Ix i => Array i e -> i -> e
!Int
0
                 in (Int -> ByteString -> ByteString
B.take Int
o ByteString
source
                    ,((Int, Int) -> (ByteString, (Int, Int)))
-> MatchArray -> MatchText ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\ol :: (Int, Int)
ol@(Int
off,Int
len) -> (Int -> ByteString -> ByteString
B.take Int
len (Int -> ByteString -> ByteString
B.drop Int
off ByteString
source),(Int, Int)
ol)) MatchArray
ma
                    ,Int -> ByteString -> ByteString
B.drop (Int
oInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
l) ByteString
source))
         (Regex -> ByteString -> Maybe MatchArray
forall regex source.
RegexLike regex source =>
regex -> source -> Maybe MatchArray
matchOnce Regex
regex ByteString
source)
  matchAllText :: Regex -> ByteString -> [MatchText ByteString]
matchAllText Regex
regex ByteString
source =
    (MatchArray -> MatchText ByteString)
-> [MatchArray] -> [MatchText ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (((Int, Int) -> (ByteString, (Int, Int)))
-> MatchArray -> MatchText ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\ol :: (Int, Int)
ol@(Int
off,Int
len) -> (Int -> ByteString -> ByteString
B.take Int
len (Int -> ByteString -> ByteString
B.drop Int
off ByteString
source),(Int, Int)
ol)))
        (Regex -> ByteString -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
regex ByteString
source)

compile :: CompOption -- ^ Flags (summed together)
        -> ExecOption -- ^ Flags (summed together)
        -> B.ByteString -- ^ The regular expression to compile
        -> Either String Regex -- ^ Returns: the compiled regular expression
compile :: CompOption -> ExecOption -> ByteString -> Either [Char] Regex
compile CompOption
compOpt ExecOption
execOpt ByteString
bs =
  case [Char] -> Either ParseError (Pattern, (Int, DoPa))
parseRegex (ByteString -> [Char]
B.unpack ByteString
bs) of
    Left ParseError
err -> [Char] -> Either [Char] Regex
forall a b. a -> Either a b
Left ([Char]
"parseRegex for Text.Regex.TDFA.ByteString failed:"[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ParseError -> [Char]
forall a. Show a => a -> [Char]
show ParseError
err)
    Right (Pattern, (Int, DoPa))
pattern -> Regex -> Either [Char] Regex
forall a b. b -> Either a b
Right ((Pattern, (Int, DoPa)) -> CompOption -> ExecOption -> Regex
patternToRegex (Pattern, (Int, DoPa))
pattern CompOption
compOpt ExecOption
execOpt)

execute :: Regex      -- ^ Compiled regular expression
        -> B.ByteString -- ^ ByteString to match against
        -> Either String (Maybe MatchArray)
execute :: Regex -> ByteString -> Either [Char] (Maybe MatchArray)
execute Regex
r ByteString
bs = Maybe MatchArray -> Either [Char] (Maybe MatchArray)
forall a b. b -> Either a b
Right (Regex -> ByteString -> Maybe MatchArray
forall regex source.
RegexLike regex source =>
regex -> source -> Maybe MatchArray
matchOnce Regex
r ByteString
bs)

regexec :: Regex      -- ^ Compiled regular expression
        -> B.ByteString -- ^ ByteString to match against
        -> Either String (Maybe (B.ByteString, B.ByteString, B.ByteString, [B.ByteString]))
regexec :: Regex
-> ByteString
-> Either
     [Char] (Maybe (ByteString, ByteString, ByteString, [ByteString]))
regexec Regex
r ByteString
bs =
  case Regex
-> ByteString
-> Maybe (ByteString, MatchText ByteString, ByteString)
forall regex source.
RegexLike regex source =>
regex -> source -> Maybe (source, MatchText source, source)
matchOnceText Regex
r ByteString
bs of
    Maybe (ByteString, MatchText ByteString, ByteString)
Nothing -> Maybe (ByteString, ByteString, ByteString, [ByteString])
-> Either
     [Char] (Maybe (ByteString, ByteString, ByteString, [ByteString]))
forall a b. b -> Either a b
Right (Maybe (ByteString, ByteString, ByteString, [ByteString])
forall a. Maybe a
Nothing)
    Just (ByteString
pre,MatchText ByteString
mt,ByteString
post) ->
      let main :: ByteString
main = (ByteString, (Int, Int)) -> ByteString
forall a b. (a, b) -> a
fst (MatchText ByteString
mtMatchText ByteString -> Int -> (ByteString, (Int, Int))
forall i e. Ix i => Array i e -> i -> e
!Int
0)
          rest :: [ByteString]
rest = ((ByteString, (Int, Int)) -> ByteString)
-> [(ByteString, (Int, Int))] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString, (Int, Int)) -> ByteString
forall a b. (a, b) -> a
fst ([(ByteString, (Int, Int))] -> [(ByteString, (Int, Int))]
forall a. [a] -> [a]
tail (MatchText ByteString -> [(ByteString, (Int, Int))]
forall i e. Array i e -> [e]
elems MatchText ByteString
mt)) -- will be []
      in Maybe (ByteString, ByteString, ByteString, [ByteString])
-> Either
     [Char] (Maybe (ByteString, ByteString, ByteString, [ByteString]))
forall a b. b -> Either a b
Right ((ByteString, ByteString, ByteString, [ByteString])
-> Maybe (ByteString, ByteString, ByteString, [ByteString])
forall a. a -> Maybe a
Just (ByteString
pre,ByteString
main,ByteString
post,[ByteString]
rest))