packages feed

regex-parsec-0.90: Text/Regex/Parsec/Sequence.hs

{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}
{-|
This offers type class instances for 'RegexMaker' and
'RegexLike'. This is usually used via import "Text.Regex.Full".

It is worth noting that 'RegexMaker' and 'RegexLike' methods for
'ByteString' are built on those for 'String' except the default
'matchOnceText' and 'matchAllText' are used since they are already
efficient for use on 'ByteString' (and they use 'matchOnce' and
'matchAll').

This exports instances of the high level API and the medium level
API of 'compile','execute', and 'regexec'.
-}
module Text.Regex.Parsec.Sequence(
  -- ** Types
  Regex
 ,MatchOffset
 ,MatchLength
 ,CompOption(..)
 ,ExecOption(..)
  -- ** Medium level API functions
 ,compile
 ,execute
 ,regexec
 ) where

import Data.Array(Array,elems,accumArray)
import qualified Data.IntMap as I (toList,(!))
import Text.Regex.Parsec.Common(MatchedStrings)
import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchText,MatchArray,MatchOffset,MatchLength)
import Text.Regex.Parsec.Wrap(Regex(..),CompOption(..),ExecOption(..),wrapCompile,wrapMatch)
import Text.Regex.Parsec.String() -- build on these instances for RegexMaker and RegexLike
import Data.Sequence(Seq)
import Data.Sequence(ViewL(..))
import qualified Data.Sequence as S
import Text.Regex.Base.Impl(polymatch,polymatchM)

instance RegexContext Regex (Seq Char) (Seq Char) where
  match = polymatch
  matchM = polymatchM

instance RegexMaker Regex CompOption ExecOption (Seq Char) where
  makeRegexOpts opts e source = makeRegexOpts opts e (unpack source)
  makeRegexOptsM opts e source = makeRegexOptsM opts e (unpack source)

instance RegexLike Regex (Seq Char) where
  matchOnce r bs = matchOnce r (unpack bs)
  matchAll r bs = matchAll r (unpack bs)
  matchTest r bs = matchTest r (unpack bs)
  matchCount r bs = matchCount r (unpack bs)
-- Use default matchOnceText and matchAllText

{-# INLINE unpack #-}
unpack :: (Seq Char) -> String
unpack s = case S.viewl s of
             EmptyL -> []
             (h :< t) -> h : unpack t

compile  :: CompOption -- ^ Flags (summed together)
         -> ExecOption -- ^ Flags (summed together)
         -> (Seq Char) -- ^ The regular expression to compile
         -> Either String Regex -- ^ Returns: the compiled regular expression
compile c e bs = wrapCompile c e (unpack bs)

execute :: Regex      -- ^ Compiled regular expression
        -> (Seq Char) -- ^ (Seq Char) to match against
        -> Either String (Maybe (Array Int (MatchOffset,MatchLength)))
execute r@(Regex {groups=g}) bs = either Left (Right . (fmap (toArr g))) (wrapMatch 0 r (unpack bs))

regexec :: Regex      -- ^ Compiled regular expression
        -> (Seq Char) -- ^ (Seq Char) to match against
        -> Either String (Maybe ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)]))
regexec r@(Regex {groups=g}) bs =
  case wrapMatch 0 r (unpack bs) of
    Left err -> Left err
    Right Nothing -> Right Nothing
    Right (Just ms) -> Right . Just $
      let (_,(o,l)) = ms I.! 0
      in (S.take o bs
         ,S.take l (S.drop o bs)
         ,S.drop (o+l) bs
         ,map (\(_,(o',l')) -> if (-1)==o' 
                                 then S.empty
                                 else S.take l' (S.drop o' bs))
              (tail (elems (toMT g ms))))

toMT :: Int -> MatchedStrings -> MatchText String
toMT maxSubs ms =  accumArray (\_ new->new) ("",(-1,0)) (0,maxSubs) (I.toList ms)

toArr :: Int -> MatchedStrings -> MatchArray
toArr maxSubs ms = accumArray (\_ (_,ol)->ol) (-1,0) (0,maxSubs) (I.toList ms)