{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Strict #-}
module Text.StringRandom.Parser
( Parsed(..)
, processParse
) where
import qualified Data.Attoparsec.Text as Attoparsec
import Data.Attoparsec.Text
( char
, anyChar
, satisfy
, string
, digit
, many1
, endOfInput
)
import Data.List ((\\))
import qualified Data.Text as Text
import Control.Applicative ((<|>), optional, many)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Strict (evalStateT, StateT, gets, put)
type RegParser a = StateT Int Attoparsec.Parser a
data Parsed = PClass [Char]
| PRange Int (Maybe Int) Parsed
| PConcat [Parsed]
| PSelect [Parsed]
| PGrouped Int Parsed
| PBackward Int
| PIgnored
deriving (Int -> Parsed -> ShowS
[Parsed] -> ShowS
Parsed -> String
(Int -> Parsed -> ShowS)
-> (Parsed -> String) -> ([Parsed] -> ShowS) -> Show Parsed
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Parsed] -> ShowS
$cshowList :: [Parsed] -> ShowS
show :: Parsed -> String
$cshow :: Parsed -> String
showsPrec :: Int -> Parsed -> ShowS
$cshowsPrec :: Int -> Parsed -> ShowS
Show, Parsed -> Parsed -> Bool
(Parsed -> Parsed -> Bool)
-> (Parsed -> Parsed -> Bool) -> Eq Parsed
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Parsed -> Parsed -> Bool
$c/= :: Parsed -> Parsed -> Bool
== :: Parsed -> Parsed -> Bool
$c== :: Parsed -> Parsed -> Bool
Eq)
pConcat :: [Parsed] -> Parsed
pConcat :: [Parsed] -> Parsed
pConcat [Parsed
x] = Parsed
x
pConcat [Parsed]
xs = [Parsed] -> Parsed
PConcat [Parsed]
xs
pSelect :: [Parsed] -> Parsed
pSelect :: [Parsed] -> Parsed
pSelect [Parsed
x] = Parsed
x
pSelect [Parsed]
xs = [Parsed] -> Parsed
PSelect [Parsed]
xs
processParse :: Text.Text -> Either String Parsed
processParse :: Text -> Either String Parsed
processParse = let p :: Parser Parsed
p = StateT Int Parser Parsed -> Int -> Parser Parsed
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT StateT Int Parser Parsed
selectParser Int
0
in Parser Parsed -> Text -> Either String Parsed
forall a. Parser a -> Text -> Either String a
Attoparsec.parseOnly (Parser Parsed
p Parser Parsed -> Parser Text () -> Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Text ()
forall t. Chunk t => Parser t ()
endOfInput)
selectParser :: RegParser Parsed
selectParser :: StateT Int Parser Parsed
selectParser = do
Parsed
p0 <- StateT Int Parser Parsed
concats
[Parsed]
ps <- StateT Int Parser Parsed -> StateT Int Parser [Parsed]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Parser Text Char -> StateT Int Parser Char
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Text Char
char Char
'|') StateT Int Parser Char
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> StateT Int Parser Parsed
concats)
Parsed -> StateT Int Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Parsed -> StateT Int Parser Parsed)
-> Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ [Parsed] -> Parsed
pSelect (Parsed
p0Parsed -> [Parsed] -> [Parsed]
forall a. a -> [a] -> [a]
:[Parsed]
ps)
where
concats :: StateT Int Parser Parsed
concats = [Parsed] -> Parsed
pConcat ([Parsed] -> Parsed)
-> StateT Int Parser [Parsed] -> StateT Int Parser Parsed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Int Parser Parsed -> StateT Int Parser [Parsed]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many StateT Int Parser Parsed
rangedParser
rangedParser :: RegParser Parsed
rangedParser :: StateT Int Parser Parsed
rangedParser = do
Parsed
p <- StateT Int Parser Parsed
groupingParser
let opt :: Parser Parsed
opt = Char -> Parser Text Char
char Char
'?' Parser Text Char -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Maybe Int -> Parsed -> Parsed
PRange Int
0 (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Parsed
p)
star :: Parser Parsed
star = Char -> Parser Text Char
char Char
'*' Parser Text Char -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Maybe Int -> Parsed -> Parsed
PRange Int
0 Maybe Int
forall a. Maybe a
Nothing Parsed
p)
plus :: Parser Parsed
plus = Char -> Parser Text Char
char Char
'+' Parser Text Char -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Maybe Int -> Parsed -> Parsed
PRange Int
1 Maybe Int
forall a. Maybe a
Nothing Parsed
p)
rep :: Parser Parsed
rep = do
Char -> Parser Text Char
char Char
'{'
Int
min <- String -> Int
forall a. Read a => String -> a
read (String -> Int) -> Parser Text String -> Parser Text Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Text Char -> Parser Text String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 Parser Text Char
digit
Maybe String
max' <- Parser Text String -> Parser Text (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser Text String -> Parser Text (Maybe String))
-> Parser Text String -> Parser Text (Maybe String)
forall a b. (a -> b) -> a -> b
$ Char -> Parser Text Char
char Char
',' Parser Text Char -> Parser Text String -> Parser Text String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Text Char -> Parser Text String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Text Char
digit
let max :: Maybe Int
max = case Maybe String
max' of
Maybe String
Nothing -> Int -> Maybe Int
forall a. a -> Maybe a
Just Int
min
Just [] -> Maybe Int
forall a. Maybe a
Nothing
Just String
ds -> Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ String -> Int
forall a. Read a => String -> a
read String
ds
Char -> Parser Text Char
char Char
'}'
Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Parsed -> Parser Parsed) -> Parsed -> Parser Parsed
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int -> Parsed -> Parsed
PRange Int
min Maybe Int
max Parsed
p
Parser Parsed -> StateT Int Parser Parsed
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Parser Parsed -> StateT Int Parser Parsed)
-> Parser Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ Parser Parsed
opt Parser Parsed -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Parsed
star Parser Parsed -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Parsed
plus Parser Parsed -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Parsed
rep Parser Parsed -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return Parsed
p
groupingParser :: RegParser Parsed
groupingParser :: StateT Int Parser Parsed
groupingParser = StateT Int Parser Parsed
ngroup StateT Int Parser Parsed
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT Int Parser Parsed
group StateT Int Parser Parsed
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT Int Parser Parsed
classParser StateT Int Parser Parsed
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT Int Parser Parsed
escaped StateT Int Parser Parsed
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT Int Parser Parsed
dot StateT Int Parser Parsed
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT Int Parser Parsed
ignored StateT Int Parser Parsed
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT Int Parser Parsed
others
where
ngroup :: StateT Int Parser Parsed
ngroup = Parser Text Text -> StateT Int Parser Text
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Text -> Parser Text Text
string Text
"(?:") StateT Int Parser Text
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> StateT Int Parser Parsed
selectParser StateT Int Parser Parsed
-> StateT Int Parser Char -> StateT Int Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Text Char -> StateT Int Parser Char
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Text Char
char Char
')')
group :: StateT Int Parser Parsed
group = do
Int
n <- (Int -> Int) -> StateT Int Parser Int
forall (m :: * -> *) s a. Monad m => (s -> a) -> StateT s m a
gets (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
Int -> StateT Int Parser ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put Int
n
Parsed
p <- Parser Text Char -> StateT Int Parser Char
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Text Char
char Char
'(') StateT Int Parser Char
-> StateT Int Parser Parsed -> StateT Int Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> StateT Int Parser Parsed
selectParser StateT Int Parser Parsed
-> StateT Int Parser Char -> StateT Int Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Text Char -> StateT Int Parser Char
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Char -> Parser Text Char
char Char
')')
Parsed -> StateT Int Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Parsed -> StateT Int Parser Parsed)
-> Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ Int -> Parsed -> Parsed
PGrouped Int
n Parsed
p
escaped :: StateT Int Parser Parsed
escaped = Parser Parsed -> StateT Int Parser Parsed
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Parser Parsed -> StateT Int Parser Parsed)
-> Parser Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ do
Char
ch <- Char -> Parser Text Char
char Char
'\\' Parser Text Char -> Parser Text Char -> Parser Text Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Text Char
anyChar
Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (Parsed -> Parser Parsed) -> Parsed -> Parser Parsed
forall a b. (a -> b) -> a -> b
$ case Char
ch of
Char
_ | Char
ch Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'b' -> Parsed
PIgnored
| Char
ch Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
'1' .. Char
'9'] -> Int -> Parsed
PBackward (String -> Int
forall a. Read a => String -> a
read [Char
ch])
| Bool
otherwise -> String -> Parsed
PClass (Char -> String
classes Char
ch)
dot :: StateT Int Parser Parsed
dot = Parser Parsed -> StateT Int Parser Parsed
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Parser Parsed -> StateT Int Parser Parsed)
-> Parser Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ Char -> Parser Text Char
char Char
'.' Parser Text Char -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Parsed
PClass String
allC)
ignored :: StateT Int Parser Parsed
ignored = Parser Parsed -> StateT Int Parser Parsed
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Parser Parsed -> StateT Int Parser Parsed)
-> Parser Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Parser Text Char
satisfy (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
'^', Char
'$']) Parser Text Char -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parsed -> Parser Parsed
forall (m :: * -> *) a. Monad m => a -> m a
return Parsed
PIgnored
others :: StateT Int Parser Parsed
others = Parser Parsed -> StateT Int Parser Parsed
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Parser Parsed -> StateT Int Parser Parsed)
-> Parser Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$ String -> Parsed
PClass (String -> Parsed) -> (Char -> String) -> Char -> Parsed
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> ShowS
forall a. a -> [a] -> [a]
: []) (Char -> Parsed) -> Parser Text Char -> Parser Parsed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser Text Char
satisfy (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` String
reservedChars)
classParser :: RegParser Parsed
classParser :: StateT Int Parser Parsed
classParser = Parser Parsed -> StateT Int Parser Parsed
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Parser Parsed -> StateT Int Parser Parsed)
-> Parser Parsed -> StateT Int Parser Parsed
forall a b. (a -> b) -> a -> b
$
String -> Parsed
PClass (String -> Parsed) -> ShowS -> String -> Parsed
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
allC String -> ShowS
forall a. Eq a => [a] -> [a] -> [a]
\\) (String -> Parsed) -> Parser Text String -> Parser Parsed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> Parser Text Text
string Text
"[^" Parser Text Text -> Parser Text String -> Parser Text String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Text String
p Parser Text String -> Parser Text Char -> Parser Text String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Text Char
char Char
']')
Parser Parsed -> Parser Parsed -> Parser Parsed
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> String -> Parsed
PClass (String -> Parsed) -> Parser Text String -> Parser Parsed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Parser Text Char
char Char
'[' Parser Text Char -> Parser Text String -> Parser Text String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Text String
p Parser Text String -> Parser Text Char -> Parser Text String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Text Char
char Char
']')
where
p :: Attoparsec.Parser [Char]
p :: Parser Text String
p = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> Parser Text [String] -> Parser Text String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Text String -> Parser Text [String]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Text String
p1
p1 :: Parser Text String
p1 = do
String
ch <- Parser Text String
onechar
Maybe String
r <- Parser Text String -> Parser Text (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Char -> Parser Text Char
char Char
'-' Parser Text Char -> Parser Text String -> Parser Text String
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Text String
onechar)
String -> Parser Text String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Parser Text String) -> String -> Parser Text String
forall a b. (a -> b) -> a -> b
$ case Maybe String
r of
Just String
rch
| String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
ch Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
&& String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
rch Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1
-> Char -> Char -> String
forall a. Enum a => a -> a -> [a]
enumFromTo (String -> Char
forall a. [a] -> a
head String
ch) (String -> Char
forall a. [a] -> a
head String
rch)
| Bool
otherwise
-> String
ch String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
'-' Char -> ShowS
forall a. a -> [a] -> [a]
: String
rch
Maybe String
Nothing -> String
ch
onechar :: Parser Text String
onechar = Char -> String
classes (Char -> String) -> Parser Text Char -> Parser Text String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Parser Text Char
char Char
'\\' Parser Text Char -> Parser Text Char -> Parser Text Char
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Text Char
anyChar)
Parser Text String -> Parser Text String -> Parser Text String
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Char -> ShowS
forall a. a -> [a] -> [a]
: []) (Char -> String) -> Parser Text Char -> Parser Text String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser Text Char
satisfy (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` String
classReservedChars)
uppersC, lowersC, digitsC, spacesC, othersC, allC :: [Char]
uppersC :: String
uppersC = [Char
'A'..Char
'Z']
lowersC :: String
lowersC = [Char
'a'..Char
'z']
digitsC :: String
digitsC = [Char
'0'..Char
'9']
spacesC :: String
spacesC = String
" \n\t"
othersC :: String
othersC = String
"!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~"
allC :: String
allC = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
uppersC, String
lowersC, String
digitsC, String
" ", String
othersC, String
"_"]
classes :: Char -> [Char]
classes :: Char -> String
classes Char
'd' = String
digitsC
classes Char
'D' = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
uppersC, String
lowersC, String
spacesC, String
othersC, String
"_"]
classes Char
'w' = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
uppersC, String
lowersC, String
digitsC, String
"_"]
classes Char
'W' = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
spacesC, String
othersC]
classes Char
't' = String
"\t"
classes Char
'n' = String
"\n"
classes Char
'v' = String
"\x000b"
classes Char
'f' = String
"\x000c"
classes Char
'r' = String
"\r"
classes Char
's' = String
spacesC
classes Char
'S' = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
uppersC, String
lowersC, String
digitsC, String
othersC, String
"_"]
classes Char
'0' = String
"\0"
classes Char
c = [Char
c]
reservedChars :: [Char]
reservedChars :: String
reservedChars = String
"\\()|^$*+{?[."
classReservedChars :: [Char]
classReservedChars :: String
classReservedChars = String
"\\]"