{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
module Regex.KDE.Compile
  (compileRegex)
  where

import qualified Data.ByteString as B
import qualified Data.Text as T
import Data.ByteString (ByteString)
import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
import Data.Text.Encoding.Error (lenientDecode)
import Safe
import Data.Attoparsec.Text as A hiding (match)
import Data.Char
import Control.Applicative
import Regex.KDE.Regex
import Control.Monad
import Control.Monad.State.Strict
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup ((<>))
#endif

-- I believe the Regex engine used in KatePart is Qt's.
-- It is described here: https://doc.qt.io/qt-6/qregexp.html

-- | Compile a UTF-8 encoded ByteString as a Regex.  If the first
-- parameter is True, then the Regex will be case sensitive.
compileRegex :: Bool -> ByteString -> Either String Regex
compileRegex :: Bool -> ByteString -> Either [Char] Regex
compileRegex Bool
caseSensitive ByteString
bs =
  let !res :: Either [Char] Regex
res = forall a. Parser a -> Text -> Either [Char] a
parseOnly (forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT StateT RState (Parser Text) Regex
parser RState{
                                            rsCurrentCaptureNumber :: Int
rsCurrentCaptureNumber = Int
0,
                                            rsCaseSensitive :: Bool
rsCaseSensitive = Bool
caseSensitive })
                       (OnDecodeError -> ByteString -> Text
decodeUtf8With OnDecodeError
lenientDecode ByteString
bs)
   in Either [Char] Regex
res
 where
   parser :: StateT RState (Parser Text) Regex
parser = do
     !Regex
re <- StateT RState (Parser Text) Regex
pRegex
     (Regex
re forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall t. Chunk t => Parser t ()
A.endOfInput) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
       do Text
rest <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift Parser Text
A.takeText
          forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail forall a b. (a -> b) -> a -> b
$ [Char]
"parse error at byte position " forall a. [a] -> [a] -> [a]
++
                 forall a. Show a => a -> [Char]
show (ByteString -> Int
B.length ByteString
bs forall a. Num a => a -> a -> a
- ByteString -> Int
B.length (Text -> ByteString
encodeUtf8 Text
rest))

data RState =
  RState
  { RState -> Int
rsCurrentCaptureNumber :: Int
  , RState -> Bool
rsCaseSensitive :: Bool }
  deriving (Int -> RState -> ShowS
[RState] -> ShowS
RState -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [RState] -> ShowS
$cshowList :: [RState] -> ShowS
show :: RState -> [Char]
$cshow :: RState -> [Char]
showsPrec :: Int -> RState -> ShowS
$cshowsPrec :: Int -> RState -> ShowS
Show)

type RParser = StateT RState Parser

pRegex :: RParser Regex
pRegex :: StateT RState (Parser Text) Regex
pRegex =
  forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Regex
MatchNull forall a b. (a -> b) -> a -> b
$
  forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Regex -> Regex -> Regex
MatchAlt
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT RState (Parser Text) Regex
pAltPart
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Char
char Char
'|') forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (StateT RState (Parser Text) Regex
pAltPart forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Monoid a => a
mempty))

pAltPart :: RParser Regex
pAltPart :: StateT RState (Parser Text) Regex
pAltPart = forall a. Monoid a => [a] -> a
mconcat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 StateT RState (Parser Text) Regex
pRegexPart

pRegexPart :: RParser Regex
pRegexPart :: StateT RState (Parser Text) Regex
pRegexPart =
  StateT RState (Parser Text) Regex
pRegexChar forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT RState (Parser Text) Regex
pParenthesized forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Regex -> StateT RState (Parser Text) Regex
pSuffix

pParenthesized :: RParser Regex
pParenthesized :: StateT RState (Parser Text) Regex
pParenthesized = do
  Char
_ <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Char
char Char
'(')
  -- pcrepattern says: A group that starts with (?| resets the capturing
  -- parentheses numbers in each alternative.
  Bool
resetCaptureNumbers <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Bool
False (Bool
True forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Text -> Parser Text
string Text
"?|"))
  (Regex -> Regex
modifier, RState -> RState
stModifier) <-
              if Bool
resetCaptureNumbers
                 then forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> a
id, forall a. a -> a
id)
                 else forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Char
char Char
'?' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser (Regex -> Regex, RState -> RState)
pGroupModifiers)
                    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> do forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\RState
st -> RState
st{
                                      rsCurrentCaptureNumber :: Int
rsCurrentCaptureNumber =
                                             RState -> Int
rsCurrentCaptureNumber RState
st forall a. Num a => a -> a -> a
+ Int
1})
                           Int
num <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets RState -> Int
rsCurrentCaptureNumber
                           forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Regex -> Regex
MatchCapture Int
num, forall a. a -> a
id)
  Int
currentCaptureNumber <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets RState -> Int
rsCurrentCaptureNumber
  Regex
contents <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Regex
MatchNull forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) a. (s -> s) -> StateT s m a -> StateT s m a
withStateT RState -> RState
stModifier forall a b. (a -> b) -> a -> b
$
    forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Regex -> Regex -> Regex
MatchAlt
      forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT RState (Parser Text) Regex
pAltPart
      forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Char
char Char
'|') forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
            ((forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
resetCaptureNumbers
                  (forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\RState
st ->
                        RState
st{ rsCurrentCaptureNumber :: Int
rsCurrentCaptureNumber = Int
currentCaptureNumber }))
               forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> StateT RState (Parser Text) Regex
pAltPart) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Monoid a => a
mempty))
  Char
_ <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Char
char Char
')')
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Regex -> Regex
modifier Regex
contents

pGroupModifiers :: Parser (Regex -> Regex, RState -> RState)
pGroupModifiers :: Parser (Regex -> Regex, RState -> RState)
pGroupModifiers =
  (do RState -> RState
stmod <- Parser (RState -> RState)
pRegexModifier -- (?i:
      forall (f :: * -> *) a. Functor f => f a -> f ()
void (Char -> Parser Char
char Char
':')
      forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a. a -> a
id, RState -> RState
stmod))
   forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
     do Direction
dir <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Direction
Forward forall a b. (a -> b) -> a -> b
$ Direction
Backward forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'<'
        ((Direction -> Regex -> Regex
AssertPositive Direction
dir, forall a. a -> a
id) forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'=') forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
          ((Direction -> Regex -> Regex
AssertNegative Direction
dir, forall a. a -> a
id) forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'!')
   forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
     do Char
c <- Parser Char
digit
        forall (m :: * -> *) a. Monad m => a -> m a
return (\Regex
_ -> Int -> Regex
Subroutine (Char -> Int
ord Char
c forall a. Num a => a -> a -> a
- Int
48), forall a. a -> a
id)
   forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
     do forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ Char -> Parser Char
char Char
'R'
        forall (m :: * -> *) a. Monad m => a -> m a
return  (\Regex
_ -> Int -> Regex
Subroutine Int
0, forall a. a -> a
id)

pRegexModifier :: Parser (RState -> RState)
pRegexModifier :: Parser (RState -> RState)
pRegexModifier = do
  -- "adlupimnsx-imnsx"
  -- i = 105  - = 45
  [Char]
ons <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser Char
satisfy ([Char] -> Char -> Bool
inClass [Char]
"adlupimnsx")
  [Char]
offs <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option [] forall a b. (a -> b) -> a -> b
$ Char -> Parser Char
char Char
'-' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
                      forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Char -> Bool) -> Parser Char
satisfy ([Char] -> Char -> Bool
inClass [Char]
"imnsx"))
  forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ \RState
st -> RState
st{
    rsCaseSensitive :: Bool
rsCaseSensitive =
      if Char
'i' forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char]
ons Bool -> Bool -> Bool
&& Char
'i' forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Char]
offs
         then Bool
False
         else (Char
'i' forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char]
offs) Bool -> Bool -> Bool
|| RState -> Bool
rsCaseSensitive RState
st
  }

pSuffix :: Regex -> RParser Regex
pSuffix :: Regex -> StateT RState (Parser Text) Regex
pSuffix Regex
re = forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Regex
re forall a b. (a -> b) -> a -> b
$ do
  Char
w <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser Char
satisfy ([Char] -> Char -> Bool
inClass [Char]
"*+?{")
  (case Char
w of
    Char
'*'  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Regex -> Regex -> Regex
MatchAlt (Regex -> Regex
MatchSome Regex
re) Regex
MatchNull
    Char
'+'  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Regex -> Regex
MatchSome Regex
re
    Char
'?'  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Regex -> Regex -> Regex
MatchAlt Regex
re Regex
MatchNull
    Char
'{'  -> do
      Maybe Int
minn <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$
        forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option forall a. Maybe a
Nothing forall a b. (a -> b) -> a -> b
$ forall a. Read a => [Char] -> Maybe a
readMay forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser Text
A.takeWhile Char -> Bool
isDigit
      Maybe Int
maxn <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Maybe Int
minn forall a b. (a -> b) -> a -> b
$ Char -> Parser Char
char Char
',' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
                       (forall a. Read a => [Char] -> Maybe a
readMay forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser Text
A.takeWhile Char -> Bool
isDigit)
      Char
_ <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ Char -> Parser Char
char Char
'}'
      case (Maybe Int
minn, Maybe Int
maxn) of
          (Maybe Int
Nothing, Maybe Int
Nothing) -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
          (Just Int
n, Maybe Int
Nothing)  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! Int -> Regex -> Regex
atleast Int
n Regex
re
          (Maybe Int
Nothing, Just Int
n)  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! Int -> Regex -> Regex
atmost Int
n Regex
re
          (Just Int
m, Just Int
n)   -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! Int -> Int -> Regex -> Regex
between Int
m Int
n Regex
re
    Char
_   -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"pSuffix encountered impossible byte") forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
             forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. Regex -> Parser Regex
pQuantifierModifier
 where
   atmost :: Int -> Regex -> Regex
atmost Int
0 Regex
_ = Regex
MatchNull
   atmost Int
n Regex
r = Regex -> Regex -> Regex
MatchAlt (forall a. Monoid a => [a] -> a
mconcat (forall a. Int -> a -> [a]
replicate Int
n Regex
r)) (Int -> Regex -> Regex
atmost (Int
nforall a. Num a => a -> a -> a
-Int
1) Regex
r)

   between :: Int -> Int -> Regex -> Regex
between Int
0 Int
n Regex
r = Int -> Regex -> Regex
atmost Int
n Regex
r
   between Int
m Int
n Regex
r = forall a. Monoid a => [a] -> a
mconcat (forall a. Int -> a -> [a]
replicate Int
m Regex
r) forall a. Semigroup a => a -> a -> a
<> Int -> Regex -> Regex
atmost (Int
n forall a. Num a => a -> a -> a
- Int
m) Regex
r

   atleast :: Int -> Regex -> Regex
atleast Int
n Regex
r = forall a. Monoid a => [a] -> a
mconcat (forall a. Int -> a -> [a]
replicate Int
n Regex
r) forall a. Semigroup a => a -> a -> a
<> Regex -> Regex -> Regex
MatchAlt (Regex -> Regex
MatchSome Regex
r) Regex
MatchNull

pQuantifierModifier :: Regex -> Parser Regex
pQuantifierModifier :: Regex -> Parser Regex
pQuantifierModifier Regex
re = forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Regex
re forall a b. (a -> b) -> a -> b
$
  (Regex -> Regex
Possessive Regex
re forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'+') forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Regex -> Regex
Lazy Regex
re forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'?')

pRegexChar :: RParser Regex
pRegexChar :: StateT RState (Parser Text) Regex
pRegexChar = do
  Char
w <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift Parser Char
anyChar
  Bool
caseSensitive <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets RState -> Bool
rsCaseSensitive
  case Char
w of
    Char
'.'  -> forall (m :: * -> *) a. Monad m => a -> m a
return Regex
MatchAnyChar
    Char
'%' -> (do -- dynamic %1 %2
              [Char]
ds <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 Parser Char
digit
              case forall a. Read a => [Char] -> Maybe a
readMay [Char]
ds of
                Just !Int
n -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> Regex
MatchDynamic Int
n
                Maybe Int
Nothing -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"not a number")
            forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (m :: * -> *) a. Monad m => a -> m a
return ((Char -> Bool) -> Regex
MatchChar (forall a. Eq a => a -> a -> Bool
== Char
'%'))
    Char
'\\' -> forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift Parser Regex
pRegexEscapedChar
    Char
'$'  -> forall (m :: * -> *) a. Monad m => a -> m a
return Regex
AssertEnd
    Char
'^'  -> forall (m :: * -> *) a. Monad m => a -> m a
return Regex
AssertBeginning
    Char
'['  -> forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift Parser Regex
pRegexCharClass
    Char
_ | Char -> Bool
isSpecial Char
w -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
      | Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$!
            (Char -> Bool) -> Regex
MatchChar forall a b. (a -> b) -> a -> b
$ if Bool
caseSensitive
                           then (forall a. Eq a => a -> a -> Bool
== Char
w)
                           else (\Char
d -> Char -> Char
toLower Char
d forall a. Eq a => a -> a -> Bool
== Char -> Char
toLower Char
w)

pRegexEscapedChar :: Parser Regex
pRegexEscapedChar :: Parser Regex
pRegexEscapedChar = do
  Char
c <- Parser Char
A.anyChar
  (case Char
c of
    Char
'b' -> forall (m :: * -> *) a. Monad m => a -> m a
return Regex
AssertWordBoundary
    Char
'B' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Direction -> Regex -> Regex
AssertNegative Direction
Forward Regex
AssertWordBoundary
    Char
'{' -> do -- captured pattern: \1 \2 \{12}
              [Char]
ds <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 Parser Char
digit
              Char
_ <- Char -> Parser Char
char Char
'}'
              case forall a. Read a => [Char] -> Maybe a
readMay [Char]
ds of
                Just !Int
n -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int -> Regex
MatchCaptured Int
n
                Maybe Int
Nothing -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"not a number"
    Char
'd' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Regex
MatchChar Char -> Bool
isDigit
    Char
'D' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Regex
MatchChar (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isDigit)
    Char
's' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Regex
MatchChar Char -> Bool
isSpace
    Char
'S' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Regex
MatchChar (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace)
    Char
'w' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Regex
MatchChar Char -> Bool
isWordChar
    Char
'W' -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Regex
MatchChar (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isWordChar)
    Char
'p' -> (Char -> Bool) -> Regex
MatchChar forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Char -> Bool)
pUnicodeCharClass
    Char
_ | Char -> Bool
isDigit Char
c ->
       forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! Int -> Regex
MatchCaptured (Char -> Int
ord Char
c forall a. Num a => a -> a -> a
- Char -> Int
ord Char
'0')
      | Bool
otherwise -> forall (m :: * -> *) a. MonadPlus m => m a
mzero) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ((Char -> Bool) -> Regex
MatchChar forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Eq a => a -> a -> Bool
(==) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char -> Parser Char
pEscaped Char
c)

pEscaped :: Char -> Parser Char
pEscaped :: Char -> Parser Char
pEscaped Char
c =
  case Char
c of
    Char
'\\' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
c
    Char
'a' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\a'
    Char
'f' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\f'
    Char
'n' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\n'
    Char
'r' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\r'
    Char
't' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\t'
    Char
'v' -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\v'
    Char
'0' -> do -- \0ooo matches octal ooo
      Text
ds <- Int -> Parser Text
A.take Int
3
      case forall a. Read a => [Char] -> Maybe a
readMay ([Char]
"'\\o" forall a. [a] -> [a] -> [a]
++ Text -> [Char]
T.unpack Text
ds forall a. [a] -> [a] -> [a]
++ [Char]
"'") of
        Just Char
x  -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
x
        Maybe Char
Nothing -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"invalid octal character escape"
    Char
_ | Char
c forall a. Ord a => a -> a -> Bool
>= Char
'1' Bool -> Bool -> Bool
&& Char
c forall a. Ord a => a -> a -> Bool
<= Char
'7' -> do
      -- \123 matches octal 123, \1 matches octal 1
      let octalDigitScanner :: a -> Char -> Maybe a
octalDigitScanner a
s Char
w
            | a
s forall a. Ord a => a -> a -> Bool
< a
3, Char -> Bool
isOctDigit Char
w = forall a. a -> Maybe a
Just (a
s forall a. Num a => a -> a -> a
+ a
1) -- digits 0-7
            | Bool
otherwise = forall a. Maybe a
Nothing
      Text
ds <- forall s. s -> (s -> Char -> Maybe s) -> Parser Text
A.scan (Int
1 :: Int) forall {a}. (Ord a, Num a) => a -> Char -> Maybe a
octalDigitScanner
      case forall a. Read a => [Char] -> Maybe a
readMay ([Char]
"'\\o" forall a. [a] -> [a] -> [a]
++ [Char
c] forall a. [a] -> [a] -> [a]
++ Text -> [Char]
T.unpack Text
ds forall a. [a] -> [a] -> [a]
++ [Char]
"'") of
        Just Char
x  -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
x
        Maybe Char
Nothing -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"invalid octal character escape"
    Char
'z' -> do -- \zhhhh matches unicode hex char hhhh
      Text
ds <- Int -> Parser Text
A.take Int
4
      case forall a. Read a => [Char] -> Maybe a
readMay ([Char]
"'\\x" forall a. [a] -> [a] -> [a]
++ Text -> [Char]
T.unpack Text
ds forall a. [a] -> [a] -> [a]
++ [Char]
"'") of
        Just Char
x  -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
x
        Maybe Char
Nothing -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"invalid hex character escape"
    Char
'x' -> do -- \xhh matches hex hh, \x{h+} matches hex h+
      Text
ds <- (Char -> Parser Char
char Char
'{' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Char -> Bool) -> Parser Text
A.takeWhile (forall a. Eq a => a -> a -> Bool
/= Char
'}') forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Char
char Char
'}')
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Int -> Parser Text
A.take Int
2
      case forall a. Read a => [Char] -> Maybe a
readMay ([Char]
"'\\x" forall a. [a] -> [a] -> [a]
++ Text -> [Char]
T.unpack Text
ds forall a. [a] -> [a] -> [a]
++ [Char]
"'") of
        Just Char
x  -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
x
        Maybe Char
Nothing -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail [Char]
"invalid hex character escape"
    Char
_ | Char -> Bool
isPunctuation Char
c Bool -> Bool -> Bool
|| Char -> Bool
isSymbol Char
c Bool -> Bool -> Bool
|| Char -> Bool
isSpace Char
c -> forall (m :: * -> *) a. Monad m => a -> m a
return Char
c
      | Bool
otherwise -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail forall a b. (a -> b) -> a -> b
$ [Char]
"invalid escape \\" forall a. [a] -> [a] -> [a]
++ [Char
c]

pRegexCharClass :: Parser Regex
pRegexCharClass :: Parser Regex
pRegexCharClass = do
  Bool
negated <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Bool
False forall a b. (a -> b) -> a -> b
$ Bool
True forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'^'
  let getEscapedClass :: Parser (Char -> Bool)
getEscapedClass = do
        Char
_ <- Char -> Parser Char
char Char
'\\'
        (Char -> Bool
isDigit forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'd')
         forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isDigit forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'D')
         forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isSpace forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
's')
         forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'S')
         forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isWordChar forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'w')
         forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isWordChar forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'W')
  let getPosixClass :: Parser (Char -> Bool)
getPosixClass = do
        Text
_ <- Text -> Parser Text
string Text
"[:"
        Bool
localNegated <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option Bool
False forall a b. (a -> b) -> a -> b
$ Bool
True forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
'^'
        Char -> Bool
res <- (Char -> Bool
isAlphaNum forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"alnum")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isAlpha forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"alpha")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isAscii forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"ascii")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ((\Char
c -> Char -> Bool
isSpace Char
c Bool -> Bool -> Bool
&& Char
c forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Char
'\n',Char
'\r',Char
'\f',Char
'\v']) forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$
                   Text -> Parser Text
string Text
"blank")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isControl forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"cntrl")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ((\Char
c -> Char -> Bool
isPrint Char
c Bool -> Bool -> Bool
|| Char -> Bool
isSpace Char
c) forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"graph:")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isLower forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"lower")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isUpper forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"upper")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isPrint forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"print")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isPunctuation forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"punct")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isSpace forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"space")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ((\Char
c -> Char -> Bool
isAlphaNum Char
c Bool -> Bool -> Bool
||
                         Char -> GeneralCategory
generalCategory Char
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
ConnectorPunctuation)
                   forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"word:")
             forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> Bool
isHexDigit forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
string Text
"xdigit")
        Text
_ <- Text -> Parser Text
string Text
":]"
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! if Bool
localNegated then Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
res else Char -> Bool
res
  let getC :: Parser Char
getC = (Char -> Parser Char
char Char
'\\' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Char
anyChar forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Char -> Parser Char
pEscaped) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
             (Char -> Bool) -> Parser Char
satisfy (\Char
c -> Char
c forall a. Eq a => a -> a -> Bool
/= Char
'\\' Bool -> Bool -> Bool
&& Char
c forall a. Eq a => a -> a -> Bool
/= Char
']')
  let getCRange :: Parser (Char -> Bool)
getCRange = do
        Char
c <- Parser Char
getC
        (\Char
d Char
x -> Char
x forall a. Ord a => a -> a -> Bool
>= Char
c Bool -> Bool -> Bool
&& Char
x forall a. Ord a => a -> a -> Bool
<= Char
d) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Parser Char
char Char
'-' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Char
getC) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
          forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. Eq a => a -> a -> Bool
== Char
c)
  let getQELiteral :: Parser (Char -> Bool)
getQELiteral = do
        forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ Text -> Parser Text
A.string Text
"\\Q"
        [Char]
cs <- forall (f :: * -> *) a b. Alternative f => f a -> f b -> f [a]
manyTill Parser Char
anyChar (Text -> Parser Text
A.string Text
"\\E")
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! \Char
c -> forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (forall a. Eq a => a -> a -> Bool
== Char
c) [Char]
cs
  [Char -> Bool]
brack <- forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option [] forall a b. (a -> b) -> a -> b
$ [(forall a. Eq a => a -> a -> Bool
==Char
']')] forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> Parser Char
char Char
']'
  [Char -> Bool]
fs <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Parser (Char -> Bool)
getQELiteral forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (Char -> Bool)
getEscapedClass forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (Char -> Bool)
getPosixClass forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (Char -> Bool)
getCRange
              forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Text -> Parser Text
A.string Text
"\\p" forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser (Char -> Bool)
pUnicodeCharClass))
  forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ Char -> Parser Char
char Char
']'
  let f :: Char -> Bool
f Char
c = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (forall a b. (a -> b) -> a -> b
$ Char
c) forall a b. (a -> b) -> a -> b
$ [Char -> Bool]
brack forall a. [a] -> [a] -> [a]
++ [Char -> Bool]
fs
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$! (Char -> Bool) -> Regex
MatchChar forall a b. (a -> b) -> a -> b
$ if Bool
negated
                           then Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
f
                           else Char -> Bool
f

-- character class \p{Lo}; we assume \p is already parsed
pUnicodeCharClass :: Parser (Char -> Bool)
pUnicodeCharClass :: Parser (Char -> Bool)
pUnicodeCharClass = do
  Text
ds <- Char -> Parser Char
char Char
'{' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Char -> Bool) -> Parser Text
A.takeWhile (forall a. Eq a => a -> a -> Bool
/= Char
'}') forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Char
char Char
'}'
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
    (case Text
ds of
      Text
"Lu" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
UppercaseLetter)
      Text
"Ll" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
LowercaseLetter)
      Text
"Lt" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
TitlecaseLetter)
      Text
"Lm" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
ModifierLetter)
      Text
"Lo" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherLetter)
      Text
"L" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
UppercaseLetter Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
LowercaseLetter Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
TitlecaseLetter Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
ModifierLetter Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherLetter)
      Text
"Mn" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
NonSpacingMark)
      Text
"Mc" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
SpacingCombiningMark)
      Text
"Me" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
EnclosingMark)
      Text
"M" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
NonSpacingMark Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
SpacingCombiningMark Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
EnclosingMark)
      Text
"Nd" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
DecimalNumber)
      Text
"Nl" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
LetterNumber)
      Text
"No" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherNumber)
      Text
"N" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
DecimalNumber Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
LetterNumber Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherNumber)
      Text
"Pc" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
ConnectorPunctuation)
      Text
"Pd" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
DashPunctuation)
      Text
"Ps" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
OpenPunctuation)
      Text
"Pe" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
ClosePunctuation)
      Text
"Pi" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
InitialQuote)
      Text
"Pf" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
FinalQuote)
      Text
"Po" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherPunctuation)
      Text
"P" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
ConnectorPunctuation Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
DashPunctuation Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
OpenPunctuation Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
ClosePunctuation Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
InitialQuote Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
FinalQuote Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherPunctuation)
      Text
"Sm" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
MathSymbol)
      Text
"Sc" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
CurrencySymbol)
      Text
"Sk" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
ModifierSymbol)
      Text
"So" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherSymbol)
      Text
"S" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
MathSymbol Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
CurrencySymbol Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
ModifierSymbol Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
OtherSymbol)
      Text
"Zs" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
Space)
      Text
"Zl" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
LineSeparator)
      Text
"Zp" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
ParagraphSeparator)
      Text
"Z" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
Space Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
LineSeparator Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
ParagraphSeparator)
      Text
"Cc" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
Control)
      Text
"Cf" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
Format)
      Text
"Cs" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
Surrogate)
      Text
"Co" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
PrivateUse)
      Text
"Cn" -> (forall a. Eq a => a -> a -> Bool
== GeneralCategory
NotAssigned)
      Text
"C" -> (\GeneralCategory
c -> GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
Control Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
Format Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
Surrogate Bool -> Bool -> Bool
||
                    GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
PrivateUse Bool -> Bool -> Bool
|| GeneralCategory
c forall a. Eq a => a -> a -> Bool
== GeneralCategory
NotAssigned)
      Text
_    -> forall a b. a -> b -> a
const Bool
False) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> GeneralCategory
generalCategory


isSpecial :: Char -> Bool
isSpecial :: Char -> Bool
isSpecial Char
'\\' = Bool
True
isSpecial Char
'?'  = Bool
True
isSpecial Char
'*'  = Bool
True
isSpecial Char
'+'  = Bool
True
-- isSpecial '{' = True -- this is okay except in suffixes
isSpecial Char
'[' = Bool
True
isSpecial Char
']' = Bool
True
isSpecial Char
'%' = Bool
True
isSpecial Char
'(' = Bool
True
isSpecial Char
')' = Bool
True
isSpecial Char
'|' = Bool
True
isSpecial Char
'.' = Bool
True
isSpecial Char
'$' = Bool
True
isSpecial Char
'^' = Bool
True
isSpecial Char
_  = Bool
False