regex-parsec-0.90: Text/Regex/Parsec/Wrap.hs
{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}
module Text.Regex.Parsec.Wrap(
Regex(..),CompOption(..),ExecOption(..),(=~),(=~~),RegexOptionStrategy(..),
MatchedStrings,wrapCompile,wrapMatch,wrapMatchAll,wrapCount,wrapTest) where
import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..))
import Text.Regex.Parsec.Common(Regex(..),CompOption(..),RegexOptionStrategy(..),ExecOption(..),
StringRegex,MatchedStrings,FullState)
import Text.Regex.Parsec.ReadRegex(parseRegex)
import Text.Regex.Parsec.RegexParsecState(newState,updateUserState,getUserState,incState,lookupAccepted)
import Text.Regex.Parsec.FullParsec(patternToParsec,hasFrontCarat)
import Text.ParserCombinators.Parsec(GenParser,(<|>),option,runParser,getInput,try,anyChar,eof)
-- | This is a newtype of 'RegexOption' in "Text.Regex.Lazy.Common".
instance RegexOptions Regex CompOption ExecOption where
blankCompOpt = CompOption {multiline = False
,caseSensitive = True
,captureGroups = True
,strategy = Find_LongestMatch}
defaultCompOpt = CompOption {multiline = True
,caseSensitive = True
,captureGroups = True
,strategy = Find_LongestMatch}
blankExecOpt = ExecOption ()
defaultExecOpt = ExecOption ()
setExecOpts _ r = r
getExecOpts _ = ExecOption ()
(=~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target) => source1 -> source -> target
(=~) x r = let q :: Regex
q = makeRegex r
in match q x
(=~~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m) => source1 -> source -> m target
(=~~) x r = do (q :: Regex) <- makeRegexM r
matchM q x
wrapCompile :: CompOption
-> ExecOption
-> StringRegex
-> Either String Regex
wrapCompile options _ s =
case parseRegex s of
Left parseError -> Left (show parseError)
Right (pat,maxSubs) ->
let r0 = patternToParsec (options) pat
r1 = patternToParsec (options {captureGroups=False}) pat
r2 = patternToParsec (options {strategy=Find_All}) pat
r3 = patternToParsec (options {captureGroups=False}) pat -- Int
r = Regex {asString=s,asPattern=pat
,capture=r0,capture'=r0
,noCapture=r1,noCapture'=r1
,allMatches=r2,userInt=r3
,frontAnchor=(hasFrontCarat pat) && (not (multiline options))
,groups=maxSubs}
in Right r
-- I think the above could be built on a "matchHere with offset" thing
wrapMatch :: Int -> Regex -> [Char] -> Either String (Maybe MatchedStrings)
wrapMatch index (Regex {capture=regex,frontAnchor=anchored}) source =
let parser = (try regex)
<|> (anyChar >> incState >> parser)
<|> (eof >> return [])
once = option [] (try regex)
result = runParser (if anchored then once else parser) (newState index ()) "wrapMatch" source
in case result of
Left err -> Left (show err)
Right [] -> Right Nothing
Right (x:_) -> Right (Just x)
wrapMatchAll :: Regex -> [Char] -> Either String [MatchedStrings]
wrapMatchAll r@(Regex {capture=regex,frontAnchor=anchored}) source =
let parser = (try regex >>= found)
<|> (anyChar >> incState >> parser)
<|> (eof >> return Nothing)
found [] = return Nothing
found (x:_) = do pos <- lookupAccepted
here <- getInput
return (Just (x,pos,here))
loop acc pos here =
let result = runParser parser (newState pos ()) "wrapMatchAll" here
in case result of
Left err -> Left (show err)
Right Nothing -> Right (acc [])
Right (Just (x,pos',here')) ->
if pos'>pos
then loop (acc.(x:)) pos' here'
else Right (acc [x])
in if anchored -- punt to wrapMatch
then either Left (Right . (maybe [] (:[]))) (wrapMatch 0 r source)
else loop id 0 source
wrapTest :: Regex -> [Char] -> Either String Bool
wrapTest (Regex {noCapture=regex,frontAnchor=anchored}) source =
let parser = (try regex >> return True)
<|> (anyChar >> parser)
<|> (eof >> return False)
once = option False (try regex >> return True)
use :: GenParser Char (FullState ()) Bool
use = if anchored then once else parser
result = runParser use (newState 0 ()) "wrapTest" source
in case result of
Left err -> Left (show err)
Right x -> Right x
wrapCount :: Regex -> [Char] -> Either String Int
wrapCount r@(Regex {userInt=regex,frontAnchor=anchored}) source =
let parser = (try regex >> updateUserState succ >> parser)
<|> (anyChar >> parser)
<|> (eof >> getUserState)
in if anchored -- punt to wrapMatch
then case wrapMatch 0 r source of
Left err -> Left err
Right Nothing -> Right 0
Right (Just _) -> Right 1
else case runParser parser (newState 0 0) "wrapCount" source of
Left err -> Left (show err)
Right n -> Right n