packages feed

regex-parsec-0.90: Text/Regex/Parsec/String.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 all methods in 'RegexLike' are re-implemented for
efficiency instead of taking the default definitions.

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

import Data.Array(Array,elems,accumArray)
import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchArray,MatchText,MatchOffset,MatchLength)
import Text.Regex.Parsec.Wrap(wrapTest,wrapCount,wrapMatch,wrapMatchAll,wrapCompile
                             ,Regex(Regex,groups),CompOption(..),ExecOption(..),MatchedStrings)
import qualified Data.IntMap as I (toList,(!))
import Text.Regex.Base.Impl(polymatch,polymatchM)

instance RegexContext Regex String String where
  match = polymatch
  matchM = polymatchM

instance RegexMaker Regex CompOption ExecOption String where
  makeRegexOpts opts e source = unwrap $
    wrapCompile opts e source
  makeRegexOptsM opts e source = either fail return $
    wrapCompile opts e source

instance RegexLike Regex String where
  matchTest r s =  unwrap $ wrapTest r s
  matchCount r s = unwrap $ wrapCount r s
  matchOnce r@(Regex {groups=g}) s =
    fmap (toArr g) (unwrap (wrapMatch 0 r s))
  matchOnceText r@(Regex {groups=g}) s =
    fmap (\mt -> let (_,(o,l)) = mt I.! 0
                 in (take o s,toMT g mt,drop (o+l) s) )
         (unwrap (wrapMatch 0 r s))
  matchAll r@(Regex {groups=g}) s = map (toArr g) (unwrap $ wrapMatchAll r s)
  matchAllText r@(Regex {groups=g}) s = map (toMT g) (unwrap $ wrapMatchAll r s)

unwrap :: Either String v -> v
unwrap x = case x of Left err -> error ("Text.Regex.Parsec.String died: "++ err)
                     Right v -> v

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

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

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 = wrapCompile

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

regexec :: Regex      -- ^ Compiled regular expression
        -> String     -- ^ String to match against
        -> Either String (Maybe (String, String, String, [String]))
regexec r@(Regex {groups=g}) s =
  case wrapMatch 0 r s of
    Left err -> Left err
    Right Nothing -> Right Nothing
    Right (Just ms) -> Right . Just $
      let (main,(o,l)) = ms I.! 0
      in (take o s
         ,main
         ,drop (o+l) s
         ,map fst (tail (elems (toMT g ms))))