{-|
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'.
-}
module Text.Regex.TDFA.ByteString.Lazy(
  Regex
 ,CompOption
 ,ExecOption
 ,compile
 ,execute
 ,regexec
 ) where

import Data.Array.IArray((!),elems,amap)
import qualified Data.ByteString.Lazy.Char8 as L(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)

{- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -}

instance RegexContext Regex L.ByteString L.ByteString where
  match :: Regex -> ByteString -> ByteString
match = Regex -> ByteString -> ByteString
forall a b. RegexLike a b => a -> b -> b
polymatch
  matchM :: forall (m :: * -> *).
MonadFail m =>
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 L.ByteString where
  makeRegexOptsM :: forall (m :: * -> *).
MonadFail m =>
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
forall (m :: * -> *).
MonadFail m =>
CompOption -> ExecOption -> [Char] -> m Regex
makeRegexOptsM CompOption
c ExecOption
e (ByteString -> [Char]
L.unpack ByteString
source)

instance RegexLike Regex L.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 -> MatchOffset -> Char -> ByteString -> [MatchArray]
forall text.
Uncons text =>
Regex -> MatchOffset -> Char -> text -> [MatchArray]
execMatch Regex
r MatchOffset
0 Char
'\n' ByteString
s
  matchCount :: Regex -> ByteString -> MatchOffset
matchCount Regex
r ByteString
s = [MatchArray] -> MatchOffset
forall a. [a] -> MatchOffset
forall (t :: * -> *) a. Foldable t => t a -> MatchOffset
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 = (regex_execOptions r) {captureGroups = 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 a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\MatchArray
ma ->
            let (MatchOffset
o32,MatchOffset
l32) = MatchArray
maMatchArray -> MatchOffset -> (MatchOffset, MatchOffset)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!MatchOffset
0
                o :: Int64
o = MatchOffset -> Int64
forall a b. (Integral a, Num b) => a -> b
fi MatchOffset
o32
                l :: Int64
l = MatchOffset -> Int64
forall a b. (Integral a, Num b) => a -> b
fi MatchOffset
l32
            in (Int64 -> ByteString -> ByteString
L.take Int64
o ByteString
source
               ,((MatchOffset, MatchOffset)
 -> (ByteString, (MatchOffset, MatchOffset)))
-> MatchArray -> MatchText ByteString
forall a b. (a -> b) -> Array MatchOffset a -> Array MatchOffset b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\ol :: (MatchOffset, MatchOffset)
ol@(MatchOffset
off32,MatchOffset
len32) ->
                        let off :: Int64
off = MatchOffset -> Int64
forall a b. (Integral a, Num b) => a -> b
fi MatchOffset
off32
                            len :: Int64
len = MatchOffset -> Int64
forall a b. (Integral a, Num b) => a -> b
fi MatchOffset
len32
                        in (Int64 -> ByteString -> ByteString
L.take Int64
len (Int64 -> ByteString -> ByteString
L.drop Int64
off ByteString
source),(MatchOffset, MatchOffset)
ol)) MatchArray
ma
               ,Int64 -> ByteString -> ByteString
L.drop (Int64
oInt64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+Int64
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 =
    let go :: t -> ByteString -> [a i (t, t)] -> [a i (ByteString, (t, t))]
go t
i ByteString
_ [a i (t, t)]
_ | t
i t -> Bool -> Bool
forall a b. a -> b -> b
`seq` Bool
False = [a i (ByteString, (t, t))]
forall a. HasCallStack => a
undefined
        go t
_i ByteString
_t [] = []
        go t
i ByteString
t (a i (t, t)
x:[a i (t, t)]
xs) =
          let (t
off0,t
len0) = a i (t, t)
xa i (t, t) -> i -> (t, t)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!i
0
              trans :: (t, a) -> (ByteString, (t, a))
trans pair :: (t, a)
pair@(t
off32,a
len32) = (Int64 -> ByteString -> ByteString
L.take (a -> Int64
forall a b. (Integral a, Num b) => a -> b
fi a
len32) (Int64 -> ByteString -> ByteString
L.drop (t -> Int64
forall a b. (Integral a, Num b) => a -> b
fi (t
off32t -> t -> t
forall a. Num a => a -> a -> a
-t
i)) ByteString
t),(t, a)
pair)
              t' :: ByteString
t' = Int64 -> ByteString -> ByteString
L.drop (t -> Int64
forall a b. (Integral a, Num b) => a -> b
fi (t
off0t -> t -> t
forall a. Num a => a -> a -> a
+t
len0t -> t -> t
forall a. Num a => a -> a -> a
-t
i)) ByteString
t
          in ((t, t) -> (ByteString, (t, t)))
-> a i (t, t) -> a i (ByteString, (t, t))
forall (a :: * -> * -> *) e' e i.
(IArray a e', IArray a e, Ix i) =>
(e' -> e) -> a i e' -> a i e
amap (t, t) -> (ByteString, (t, t))
forall {a}. Integral a => (t, a) -> (ByteString, (t, a))
trans a i (t, t)
x a i (ByteString, (t, t))
-> [a i (ByteString, (t, t))] -> [a i (ByteString, (t, t))]
forall a. a -> [a] -> [a]
: ByteString
-> [a i (ByteString, (t, t))] -> [a i (ByteString, (t, t))]
forall a b. a -> b -> b
seq ByteString
t' (t -> ByteString -> [a i (t, t)] -> [a i (ByteString, (t, t))]
go (t
off0t -> t -> t
forall a. Num a => a -> a -> a
+t
len0) ByteString
t' [a i (t, t)]
xs)
    in MatchOffset -> ByteString -> [MatchArray] -> [MatchText ByteString]
forall {a :: * -> * -> *} {t} {i}.
(IArray a (t, t), IArray a (ByteString, (t, t)), Ix i, Integral t,
 Num i) =>
t -> ByteString -> [a i (t, t)] -> [a i (ByteString, (t, t))]
go MatchOffset
0 ByteString
source (Regex -> ByteString -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
regex ByteString
source)

fi :: (Integral a, Num b) => a -> b
fi :: forall a b. (Integral a, Num b) => a -> b
fi = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral

compile :: CompOption -- ^ Flags (summed together)
        -> ExecOption -- ^ Flags (summed together)
        -> L.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, (MatchOffset, DoPa))
parseRegex (ByteString -> [Char]
L.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, (MatchOffset, DoPa))
pattern -> Regex -> Either [Char] Regex
forall a b. b -> Either a b
Right ((Pattern, (MatchOffset, DoPa)) -> CompOption -> ExecOption -> Regex
patternToRegex (Pattern, (MatchOffset, DoPa))
pattern CompOption
compOpt ExecOption
execOpt)

execute :: Regex        -- ^ Compiled regular expression
        -> L.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
        -> L.ByteString -- ^ ByteString to match against
        -> Either String (Maybe (L.ByteString, L.ByteString, L.ByteString, [L.ByteString]))
regexec :: Regex
-> ByteString
-> Either
     [Char] (Maybe (ByteString, ByteString, ByteString, [ByteString]))
regexec Regex
r ByteString
txt = 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])
 -> Either
      [Char] (Maybe (ByteString, ByteString, ByteString, [ByteString])))
-> Maybe (ByteString, ByteString, ByteString, [ByteString])
-> Either
     [Char] (Maybe (ByteString, ByteString, ByteString, [ByteString]))
forall a b. (a -> b) -> a -> b
$
  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
txt of
    Just (ByteString
pre, MatchText ByteString
mt, ByteString
post) | ByteString
main:[ByteString]
rest <- ((ByteString, (MatchOffset, MatchOffset)) -> ByteString)
-> [(ByteString, (MatchOffset, MatchOffset))] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString, (MatchOffset, MatchOffset)) -> ByteString
forall a b. (a, b) -> a
fst (MatchText ByteString -> [(ByteString, (MatchOffset, MatchOffset))]
forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
elems MatchText ByteString
mt)
      -> (ByteString, ByteString, ByteString, [ByteString])
-> Maybe (ByteString, ByteString, ByteString, [ByteString])
forall a. a -> Maybe a
Just (ByteString
pre, ByteString
main, ByteString
post, [ByteString]
rest)
    Maybe (ByteString, MatchText ByteString, ByteString)
_ -> Maybe (ByteString, ByteString, ByteString, [ByteString])
forall a. Maybe a
Nothing