{-# LANGUAGE RankNTypes #-}
module Data.Owoify.Internal.Parser.OwoifyParser
  ( count
  , OError(..)
  , OwoifyError
  , OwoifyParser
  , runParser
  )
  where

import Prelude

import Control.Monad ((>=>), foldM, replicateM)
import Data.Function ((&))
import Data.List (uncons)
import Data.Owoify.Internal.Entity.Word (InnerWord(InnerWord, innerWord, innerReplacedWords)) 
import Data.Text.Lazy (Text)

-- | Represents those types denoting errors when owoifying.
class OwoifyError e where
  -- | Representing that the source collection of strings has been exhausted.
  eof :: e
  -- | Representing general parser error. Currently not used.
  parseError :: Text -> e

-- | A simple type representing errors that occur during owoification.
data OError = EOF | ParseError Text deriving (Int -> OError -> ShowS
[OError] -> ShowS
OError -> String
(Int -> OError -> ShowS)
-> (OError -> String) -> ([OError] -> ShowS) -> Show OError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OError] -> ShowS
$cshowList :: [OError] -> ShowS
show :: OError -> String
$cshow :: OError -> String
showsPrec :: Int -> OError -> ShowS
$cshowsPrec :: Int -> OError -> ShowS
Show)

instance OwoifyError OError where
  eof :: OError
eof = OError
EOF
  parseError :: Text -> OError
parseError = Text -> OError
ParseError

type OwoifyResult a = ([Text], a)

type OwoifyFunction e a = OwoifyError e => [Text] -> Either e (OwoifyResult a)

newtype OwoifyParser e a = OwoifyParser (OwoifyFunction e a)

instance Functor (OwoifyParser e) where
  fmap :: (a -> b) -> OwoifyParser e a -> OwoifyParser e b
fmap a -> b
f (OwoifyParser OwoifyFunction e a
g) = OwoifyFunction e b -> OwoifyParser e b
forall e a. OwoifyFunction e a -> OwoifyParser e a
OwoifyParser ((([Text], a) -> ([Text], b))
-> Either e ([Text], a) -> Either e ([Text], b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> b) -> ([Text], a) -> ([Text], b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f) (Either e ([Text], a) -> Either e ([Text], b))
-> ([Text] -> Either e ([Text], a))
-> [Text]
-> Either e ([Text], b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Either e ([Text], a)
OwoifyFunction e a
g)

instance Applicative (OwoifyParser e) where
  <*> :: OwoifyParser e (a -> b) -> OwoifyParser e a -> OwoifyParser e b
(<*>) (OwoifyParser OwoifyFunction e (a -> b)
f) (OwoifyParser OwoifyFunction e a
g) = OwoifyFunction e b -> OwoifyParser e b
forall e a. OwoifyFunction e a -> OwoifyParser e a
OwoifyParser ([Text] -> Either e (OwoifyResult (a -> b))
OwoifyFunction e (a -> b)
f ([Text] -> Either e (OwoifyResult (a -> b)))
-> (OwoifyResult (a -> b) -> Either e ([Text], b))
-> [Text]
-> Either e ([Text], b)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> \([Text]
s', a -> b
ab) -> [Text] -> Either e (OwoifyResult a)
OwoifyFunction e a
g [Text]
s' Either e (OwoifyResult a)
-> (OwoifyResult a -> Either e ([Text], b)) -> Either e ([Text], b)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \([Text]
s'', a
a) -> ([Text], b) -> Either e ([Text], b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Text]
s'', a -> b
ab a
a))
  pure :: a -> OwoifyParser e a
pure a
x = OwoifyFunction e a -> OwoifyParser e a
forall e a. OwoifyFunction e a -> OwoifyParser e a
OwoifyParser (\[Text]
s -> OwoifyResult a -> Either e (OwoifyResult a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Text]
s, a
x))

instance Monad (OwoifyParser e) where
  >>= :: OwoifyParser e a -> (a -> OwoifyParser e b) -> OwoifyParser e b
(>>=) (OwoifyParser OwoifyFunction e a
f) a -> OwoifyParser e b
g = OwoifyFunction e b -> OwoifyParser e b
forall e a. OwoifyFunction e a -> OwoifyParser e a
OwoifyParser ([Text] -> Either e (OwoifyResult a)
OwoifyFunction e a
f ([Text] -> Either e (OwoifyResult a))
-> (OwoifyResult a -> Either e (OwoifyResult b))
-> [Text]
-> Either e (OwoifyResult b)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> \([Text]
s', a
a) -> OwoifyParser e b -> [Text] -> Either e (OwoifyResult b)
forall e a.
OwoifyError e =>
OwoifyParser e a -> [Text] -> Either e (OwoifyResult a)
runParser (a -> OwoifyParser e b
g a
a) [Text]
s')

-- | Executes (unwraps) the parser inside the monad.
runParser :: OwoifyError e => OwoifyParser e a -> [Text] -> Either e (OwoifyResult a)
runParser :: OwoifyParser e a -> [Text] -> Either e (OwoifyResult a)
runParser (OwoifyParser OwoifyFunction e a
f) = [Text] -> Either e (OwoifyResult a)
OwoifyFunction e a
f

word ::
  (Foldable t, Monad m, OwoifyError e)
  => t (InnerWord -> m InnerWord)
  -> OwoifyParser e (m InnerWord)
word :: t (InnerWord -> m InnerWord) -> OwoifyParser e (m InnerWord)
word t (InnerWord -> m InnerWord)
mappings = OwoifyFunction e (m InnerWord) -> OwoifyParser e (m InnerWord)
forall e a. OwoifyFunction e a -> OwoifyParser e a
OwoifyParser (\[Text]
s ->
  case [Text] -> Maybe (Text, [Text])
forall a. [a] -> Maybe (a, [a])
uncons [Text]
s of
    Maybe (Text, [Text])
Nothing -> e -> Either e (OwoifyResult (m InnerWord))
forall a b. a -> Either a b
Left e
forall e. OwoifyError e => e
eof
    Just (Text
head, [Text]
tail) -> do
      let w :: InnerWord
w = InnerWord :: Text -> [Text] -> InnerWord
InnerWord { innerWord :: Text
innerWord = Text
head, innerReplacedWords :: [Text]
innerReplacedWords = [] }
      let result :: m InnerWord
result = (InnerWord -> (InnerWord -> m InnerWord) -> m InnerWord)
-> InnerWord -> t (InnerWord -> m InnerWord) -> m InnerWord
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM InnerWord -> (InnerWord -> m InnerWord) -> m InnerWord
forall a b. a -> (a -> b) -> b
(&) InnerWord
w t (InnerWord -> m InnerWord)
mappings
      OwoifyResult (m InnerWord) -> Either e (OwoifyResult (m InnerWord))
forall a b. b -> Either a b
Right ([Text]
tail, m InnerWord
result))

-- | Replicate owoify parser according to the specified length (`n`) and a collection of owoify functions. 
count ::
  (Foldable t, Monad m, OwoifyError e)
  => Int
  -> t (InnerWord -> m InnerWord)
  -> OwoifyParser e [m InnerWord]
count :: Int -> t (InnerWord -> m InnerWord) -> OwoifyParser e [m InnerWord]
count Int
n t (InnerWord -> m InnerWord)
p | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = [m InnerWord] -> OwoifyParser e [m InnerWord]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
          | Bool
otherwise = Int -> OwoifyParser e (m InnerWord) -> OwoifyParser e [m InnerWord]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n (OwoifyParser e (m InnerWord) -> OwoifyParser e [m InnerWord])
-> OwoifyParser e (m InnerWord) -> OwoifyParser e [m InnerWord]
forall a b. (a -> b) -> a -> b
$ t (InnerWord -> m InnerWord) -> OwoifyParser e (m InnerWord)
forall (t :: * -> *) (m :: * -> *) e.
(Foldable t, Monad m, OwoifyError e) =>
t (InnerWord -> m InnerWord) -> OwoifyParser e (m InnerWord)
word t (InnerWord -> m InnerWord)
p