{- |
This modules provides 'RegexMaker' and 'RegexLike' instances for using
'String' with the TDFA backend.

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.String(
  -- ** Types
  Regex
 ,MatchOffset
 ,MatchLength
 ,CompOption
 ,ExecOption
  -- ** Medium level API functions
 ,compile
 ,execute
 ,regexec
 ) where

import Text.Regex.Base.Impl(polymatch,polymatchM)
import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchOffset,MatchLength,MatchArray)
import Text.Regex.TDFA.Common(common_error,Regex(..),CompOption,ExecOption(captureGroups))
import Text.Regex.TDFA.ReadRegex(parseRegex)
import Text.Regex.TDFA.TDFA(patternToRegex)

import Data.Array.IArray((!),elems,amap)
import Data.Maybe(listToMaybe)
import Text.Regex.TDFA.NewDFA.Engine(execMatch)
import Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest)

err :: String -> a
err :: forall a. [Char] -> a
err = [Char] -> [Char] -> a
forall a. [Char] -> [Char] -> a
common_error [Char]
"Text.Regex.TDFA.String"

unwrap :: Either String v -> v
unwrap :: forall v. Either [Char] v -> v
unwrap Either [Char] v
x = case Either [Char] v
x of Left [Char]
msg -> [Char] -> v
forall a. [Char] -> a
err ([Char]
"Text.Regex.TDFA.String died: "[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++[Char]
msg)
                     Right v
v -> v
v

compile  :: CompOption -- ^ Flags (summed together)
         -> ExecOption -- ^ Flags (summed together)
         -> String     -- ^ The regular expression to compile (ASCII only, no null bytes)
         -> Either String Regex -- ^ Returns: the compiled regular expression
compile :: CompOption -> ExecOption -> [Char] -> Either [Char] Regex
compile CompOption
compOpt ExecOption
execOpt [Char]
source =
  case [Char] -> Either ParseError (Pattern, (MatchOffset, DoPa))
parseRegex [Char]
source of
    Left ParseError
msg -> [Char] -> Either [Char] Regex
forall a b. a -> Either a b
Left ([Char]
"parseRegex for Text.Regex.TDFA.String failed:"[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ParseError -> [Char]
forall a. Show a => a -> [Char]
show ParseError
msg)
    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)

instance RegexMaker Regex CompOption ExecOption String where
  makeRegexOpts :: CompOption -> ExecOption -> [Char] -> Regex
makeRegexOpts CompOption
c ExecOption
e [Char]
source = Either [Char] Regex -> Regex
forall v. Either [Char] v -> v
unwrap (CompOption -> ExecOption -> [Char] -> Either [Char] Regex
compile CompOption
c ExecOption
e [Char]
source)
  makeRegexOptsM :: forall (m :: * -> *).
MonadFail m =>
CompOption -> ExecOption -> [Char] -> m Regex
makeRegexOptsM CompOption
c ExecOption
e [Char]
source = ([Char] -> m Regex)
-> (Regex -> m Regex) -> Either [Char] Regex -> m Regex
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either [Char] -> m Regex
forall a. HasCallStack => [Char] -> m a
forall (m :: * -> *) a.
(MonadFail m, HasCallStack) =>
[Char] -> m a
fail Regex -> m Regex
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either [Char] Regex -> m Regex) -> Either [Char] Regex -> m Regex
forall a b. (a -> b) -> a -> b
$ CompOption -> ExecOption -> [Char] -> Either [Char] Regex
compile CompOption
c ExecOption
e [Char]
source

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

regexec :: Regex      -- ^ Compiled regular expression
        -> String     -- ^ String to match against
        -> Either String (Maybe (String, String, String, [String]))
regexec :: Regex
-> [Char]
-> Either [Char] (Maybe ([Char], [Char], [Char], [[Char]]))
regexec Regex
r [Char]
txt = Maybe ([Char], [Char], [Char], [[Char]])
-> Either [Char] (Maybe ([Char], [Char], [Char], [[Char]]))
forall a b. b -> Either a b
Right (Maybe ([Char], [Char], [Char], [[Char]])
 -> Either [Char] (Maybe ([Char], [Char], [Char], [[Char]])))
-> Maybe ([Char], [Char], [Char], [[Char]])
-> Either [Char] (Maybe ([Char], [Char], [Char], [[Char]]))
forall a b. (a -> b) -> a -> b
$
  case Regex -> [Char] -> Maybe ([Char], MatchText [Char], [Char])
forall regex source.
RegexLike regex source =>
regex -> source -> Maybe (source, MatchText source, source)
matchOnceText Regex
r [Char]
txt of
    Just ([Char]
pre, MatchText [Char]
mt, [Char]
post) | [Char]
main:[[Char]]
rest <- (([Char], (MatchOffset, MatchOffset)) -> [Char])
-> [([Char], (MatchOffset, MatchOffset))] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], (MatchOffset, MatchOffset)) -> [Char]
forall a b. (a, b) -> a
fst (MatchText [Char] -> [([Char], (MatchOffset, MatchOffset))]
forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
elems MatchText [Char]
mt)
      -> ([Char], [Char], [Char], [[Char]])
-> Maybe ([Char], [Char], [Char], [[Char]])
forall a. a -> Maybe a
Just ([Char]
pre, [Char]
main, [Char]
post, [[Char]]
rest)
    Maybe ([Char], MatchText [Char], [Char])
_ -> Maybe ([Char], [Char], [Char], [[Char]])
forall a. Maybe a
Nothing

-- Minimal definition for now
instance RegexLike Regex String where
  matchOnce :: Regex -> [Char] -> Maybe MatchArray
matchOnce Regex
r [Char]
s = [MatchArray] -> Maybe MatchArray
forall a. [a] -> Maybe a
listToMaybe (Regex -> [Char] -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
r [Char]
s)
  matchAll :: Regex -> [Char] -> [MatchArray]
matchAll Regex
r [Char]
s = Regex -> MatchOffset -> Char -> [Char] -> [MatchArray]
forall text.
Uncons text =>
Regex -> MatchOffset -> Char -> text -> [MatchArray]
execMatch Regex
r MatchOffset
0 Char
'\n' [Char]
s
  matchCount :: Regex -> [Char] -> MatchOffset
matchCount Regex
r [Char]
s = [MatchArray] -> MatchOffset
forall a. [a] -> MatchOffset
forall (t :: * -> *) a. Foldable t => t a -> MatchOffset
length (Regex -> [Char] -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
r' [Char]
s)
    where r' :: Regex
r' = Regex
r { regex_execOptions = (regex_execOptions r) {captureGroups = False} }
  matchTest :: Regex -> [Char] -> Bool
matchTest = Regex -> [Char] -> Bool
forall text. Uncons text => Regex -> text -> Bool
Tester.matchTest
  -- matchOnceText
  matchAllText :: Regex -> [Char] -> [MatchText [Char]]
matchAllText Regex
r [Char]
s =
    let go :: MatchOffset
-> [a]
-> [a i (MatchOffset, MatchOffset)]
-> [a i ([a], (MatchOffset, MatchOffset))]
go MatchOffset
i [a]
_ [a i (MatchOffset, MatchOffset)]
_ | MatchOffset
i MatchOffset -> Bool -> Bool
forall a b. a -> b -> b
`seq` Bool
False = [a i ([a], (MatchOffset, MatchOffset))]
forall a. HasCallStack => a
undefined
        go MatchOffset
_i [a]
_t [] = []
        go MatchOffset
i [a]
t (a i (MatchOffset, MatchOffset)
x:[a i (MatchOffset, MatchOffset)]
xs) = let (MatchOffset
off0,MatchOffset
len0) = a i (MatchOffset, MatchOffset)
xa i (MatchOffset, MatchOffset) -> i -> (MatchOffset, MatchOffset)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!i
0
                            trans :: (MatchOffset, MatchOffset) -> ([a], (MatchOffset, MatchOffset))
trans pair :: (MatchOffset, MatchOffset)
pair@(MatchOffset
off,MatchOffset
len) = (MatchOffset -> [a] -> [a]
forall a. MatchOffset -> [a] -> [a]
take MatchOffset
len (MatchOffset -> [a] -> [a]
forall a. MatchOffset -> [a] -> [a]
drop (MatchOffset
offMatchOffset -> MatchOffset -> MatchOffset
forall a. Num a => a -> a -> a
-MatchOffset
i) [a]
t),(MatchOffset, MatchOffset)
pair)
                            t' :: [a]
t' = MatchOffset -> [a] -> [a]
forall a. MatchOffset -> [a] -> [a]
drop (MatchOffset
off0MatchOffset -> MatchOffset -> MatchOffset
forall a. Num a => a -> a -> a
+MatchOffset
len0MatchOffset -> MatchOffset -> MatchOffset
forall a. Num a => a -> a -> a
-MatchOffset
i) [a]
t
                        in ((MatchOffset, MatchOffset) -> ([a], (MatchOffset, MatchOffset)))
-> a i (MatchOffset, MatchOffset)
-> a i ([a], (MatchOffset, MatchOffset))
forall (a :: * -> * -> *) e' e i.
(IArray a e', IArray a e, Ix i) =>
(e' -> e) -> a i e' -> a i e
amap (MatchOffset, MatchOffset) -> ([a], (MatchOffset, MatchOffset))
trans a i (MatchOffset, MatchOffset)
x a i ([a], (MatchOffset, MatchOffset))
-> [a i ([a], (MatchOffset, MatchOffset))]
-> [a i ([a], (MatchOffset, MatchOffset))]
forall a. a -> [a] -> [a]
: [a]
-> [a i ([a], (MatchOffset, MatchOffset))]
-> [a i ([a], (MatchOffset, MatchOffset))]
forall a b. a -> b -> b
seq [a]
t' (MatchOffset
-> [a]
-> [a i (MatchOffset, MatchOffset)]
-> [a i ([a], (MatchOffset, MatchOffset))]
go (MatchOffset
off0MatchOffset -> MatchOffset -> MatchOffset
forall a. Num a => a -> a -> a
+MatchOffset
len0) [a]
t' [a i (MatchOffset, MatchOffset)]
xs)
    in MatchOffset -> [Char] -> [MatchArray] -> [MatchText [Char]]
forall {a :: * -> * -> *} {a} {i}.
(IArray a ([a], (MatchOffset, MatchOffset)),
 IArray a (MatchOffset, MatchOffset), Ix i, Num i) =>
MatchOffset
-> [a]
-> [a i (MatchOffset, MatchOffset)]
-> [a i ([a], (MatchOffset, MatchOffset))]
go MatchOffset
0 [Char]
s (Regex -> [Char] -> [MatchArray]
forall regex source.
RegexLike regex source =>
regex -> source -> [MatchArray]
matchAll Regex
r [Char]
s)

instance RegexContext Regex String String where
  match :: Regex -> [Char] -> [Char]
match = Regex -> [Char] -> [Char]
forall a b. RegexLike a b => a -> b -> b
polymatch
  matchM :: forall (m :: * -> *). MonadFail m => Regex -> [Char] -> m [Char]
matchM = Regex -> [Char] -> m [Char]
forall a b (m :: * -> *).
(RegexLike a b, MonadFail m) =>
a -> b -> m b
polymatchM