content: {-|
  Module      : $Header$
  Description : Regular expression wrapper for marvin.
  Copyright   : (c) Justus Adam, 2016
  License     : BSD3
  Maintainer  : dev@justus.science
  Stability   : experimental
  Portability : POSIX
  -}
  module Marvin.Util.Regex
      ( Regex, Match, r, match
      , Re.MatchOption(..)
      ) where
  
  import           Control.DeepSeq
  import           Data.String
  import qualified Data.Text.ICU   as Re
  import qualified Data.Text.Lazy  as L
  
  
  -- | Abstract Wrapper for a reglar expression implementation. Has an 'IsString' implementation, so literal strings can be used to create a 'Regex'.
  -- Alternatively use 'r' to create one with custom options.
  newtype Regex = Regex Re.Regex
  
  instance NFData Regex where
      rnf (Regex a) = a `seq` ()
  
  -- Warning: This exposes the underlying representation of a 'Regex' and under no curcumstances should be considered stable.
  unwrapRegex :: Regex -> Re.Regex
  unwrapRegex (Regex re) = re
  
  
  instance Show Regex where
      show = show . unwrapRegex
  
  
  -- | A match to a 'Regex'. Index 0 is the full match, all other indices are match groups.
  type Match = [L.Text]
  
  -- | Compile a regex with options
  --
  -- Normally it is sufficient to just write the regex as a plain string and have it be converted automatically, but if you want certain match options you can use this function.
  r :: [Re.MatchOption] -> L.Text -> Regex
  r opts = Regex . Re.regex opts . L.toStrict
  
  
  instance IsString Regex where
      fromString "" = error "Empty regex is not permitted, use '.*' or similar instead"
      fromString s  = r [] (L.pack s)
  
  
  -- | Match a regex against a string and return the first match found (if any).
  match :: Regex -> L.Text -> Maybe Match
  match re s = map L.fromStrict . Re.unfold Re.group <$> Re.find (unwrapRegex re) (L.toStrict s)
  