module Rattletrap.Get where

import qualified Control.Applicative as Applicative
import qualified Control.Exception as Exception
import qualified Data.Bifunctor as Bifunctor
import qualified Rattletrap.Exception.Empty as Empty
import qualified Rattletrap.Exception.Fail as Fail

newtype Get s m a = Get (s -> m (Either ([String], Exception.SomeException)  (s, a)))

instance Functor m => Functor (Get s m) where
  fmap :: (a -> b) -> Get s m a -> Get s m b
fmap a -> b
f Get s m a
g = (s -> m (Either ([String], SomeException) (s, b))) -> Get s m b
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, b))) -> Get s m b)
-> (s -> m (Either ([String], SomeException) (s, b))) -> Get s m b
forall a b. (a -> b) -> a -> b
$ (Either ([String], SomeException) (s, a)
 -> Either ([String], SomeException) (s, b))
-> m (Either ([String], SomeException) (s, a))
-> m (Either ([String], SomeException) (s, b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((s, a) -> (s, b))
-> Either ([String], SomeException) (s, a)
-> Either ([String], SomeException) (s, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> b) -> (s, a) -> (s, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f)) (m (Either ([String], SomeException) (s, a))
 -> m (Either ([String], SomeException) (s, b)))
-> (s -> m (Either ([String], SomeException) (s, a)))
-> s
-> m (Either ([String], SomeException) (s, b))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get s m a -> s -> m (Either ([String], SomeException) (s, a))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m a
g

instance Monad m => Applicative (Get s m) where
  pure :: a -> Get s m a
pure a
x = (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, a))) -> Get s m a)
-> (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall a b. (a -> b) -> a -> b
$ \s
s -> Either ([String], SomeException) (s, a)
-> m (Either ([String], SomeException) (s, a))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, a)
 -> m (Either ([String], SomeException) (s, a)))
-> Either ([String], SomeException) (s, a)
-> m (Either ([String], SomeException) (s, a))
forall a b. (a -> b) -> a -> b
$ (s, a) -> Either ([String], SomeException) (s, a)
forall a b. b -> Either a b
Right (s
s, a
x)

  Get s m (a -> b)
gf <*> :: Get s m (a -> b) -> Get s m a -> Get s m b
<*> Get s m a
gx = (s -> m (Either ([String], SomeException) (s, b))) -> Get s m b
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, b))) -> Get s m b)
-> (s -> m (Either ([String], SomeException) (s, b))) -> Get s m b
forall a b. (a -> b) -> a -> b
$ \s
s1 -> do
    Either ([String], SomeException) (s, a -> b)
r <- Get s m (a -> b)
-> s -> m (Either ([String], SomeException) (s, a -> b))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m (a -> b)
gf s
s1
    case Either ([String], SomeException) (s, a -> b)
r of
      Left ([String], SomeException)
e -> Either ([String], SomeException) (s, b)
-> m (Either ([String], SomeException) (s, b))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, b)
 -> m (Either ([String], SomeException) (s, b)))
-> Either ([String], SomeException) (s, b)
-> m (Either ([String], SomeException) (s, b))
forall a b. (a -> b) -> a -> b
$ ([String], SomeException)
-> Either ([String], SomeException) (s, b)
forall a b. a -> Either a b
Left ([String], SomeException)
e
      Right (s
s2, a -> b
f) -> Get s m b -> s -> m (Either ([String], SomeException) (s, b))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run ((a -> b) -> Get s m a -> Get s m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f Get s m a
gx) s
s2

instance Monad m => Monad (Get s m) where
  Get s m a
g >>= :: Get s m a -> (a -> Get s m b) -> Get s m b
>>= a -> Get s m b
f = (s -> m (Either ([String], SomeException) (s, b))) -> Get s m b
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, b))) -> Get s m b)
-> (s -> m (Either ([String], SomeException) (s, b))) -> Get s m b
forall a b. (a -> b) -> a -> b
$ \s
s1 -> do
    Either ([String], SomeException) (s, a)
r <- Get s m a -> s -> m (Either ([String], SomeException) (s, a))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m a
g s
s1
    case Either ([String], SomeException) (s, a)
r of
      Left ([String], SomeException)
e -> Either ([String], SomeException) (s, b)
-> m (Either ([String], SomeException) (s, b))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, b)
 -> m (Either ([String], SomeException) (s, b)))
-> Either ([String], SomeException) (s, b)
-> m (Either ([String], SomeException) (s, b))
forall a b. (a -> b) -> a -> b
$ ([String], SomeException)
-> Either ([String], SomeException) (s, b)
forall a b. a -> Either a b
Left ([String], SomeException)
e
      Right (s
s2, a
x) -> Get s m b -> s -> m (Either ([String], SomeException) (s, b))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run (a -> Get s m b
f a
x) s
s2

instance Monad m => MonadFail (Get s m) where
  fail :: String -> Get s m a
fail = Fail -> Get s m a
forall e (m :: * -> *) s a.
(Exception e, Applicative m) =>
e -> Get s m a
throw (Fail -> Get s m a) -> (String -> Fail) -> String -> Get s m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Fail
Fail.Fail

instance Monad m => Applicative.Alternative (Get s m) where
  empty :: Get s m a
empty = Empty -> Get s m a
forall e (m :: * -> *) s a.
(Exception e, Applicative m) =>
e -> Get s m a
throw Empty
Empty.Empty

  Get s m a
gx <|> :: Get s m a -> Get s m a -> Get s m a
<|> Get s m a
gy = (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, a))) -> Get s m a)
-> (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall a b. (a -> b) -> a -> b
$ \s
s -> do
    Either ([String], SomeException) (s, a)
r <- Get s m a -> s -> m (Either ([String], SomeException) (s, a))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m a
gx s
s
    case Either ([String], SomeException) (s, a)
r of
      Left ([String], SomeException)
_ -> Get s m a -> s -> m (Either ([String], SomeException) (s, a))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m a
gy s
s
      Right (s, a)
x -> Either ([String], SomeException) (s, a)
-> m (Either ([String], SomeException) (s, a))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, a)
 -> m (Either ([String], SomeException) (s, a)))
-> Either ([String], SomeException) (s, a)
-> m (Either ([String], SomeException) (s, a))
forall a b. (a -> b) -> a -> b
$ (s, a) -> Either ([String], SomeException) (s, a)
forall a b. b -> Either a b
Right (s, a)
x

run :: Get s m a -> s -> m (Either ([String], Exception.SomeException) (s, a))
run :: Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run (Get s -> m (Either ([String], SomeException) (s, a))
f) = s -> m (Either ([String], SomeException) (s, a))
f

get :: Applicative m => Get s m s
get :: Get s m s
get = (s -> m (Either ([String], SomeException) (s, s))) -> Get s m s
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, s))) -> Get s m s)
-> (s -> m (Either ([String], SomeException) (s, s))) -> Get s m s
forall a b. (a -> b) -> a -> b
$ \s
s -> Either ([String], SomeException) (s, s)
-> m (Either ([String], SomeException) (s, s))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, s)
 -> m (Either ([String], SomeException) (s, s)))
-> Either ([String], SomeException) (s, s)
-> m (Either ([String], SomeException) (s, s))
forall a b. (a -> b) -> a -> b
$ (s, s) -> Either ([String], SomeException) (s, s)
forall a b. b -> Either a b
Right (s
s, s
s)

put :: Applicative m => s -> Get s m ()
put :: s -> Get s m ()
put s
s = (s -> m (Either ([String], SomeException) (s, ()))) -> Get s m ()
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, ()))) -> Get s m ())
-> (s -> m (Either ([String], SomeException) (s, ())))
-> Get s m ()
forall a b. (a -> b) -> a -> b
$ \s
_ -> Either ([String], SomeException) (s, ())
-> m (Either ([String], SomeException) (s, ()))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, ())
 -> m (Either ([String], SomeException) (s, ())))
-> Either ([String], SomeException) (s, ())
-> m (Either ([String], SomeException) (s, ()))
forall a b. (a -> b) -> a -> b
$ (s, ()) -> Either ([String], SomeException) (s, ())
forall a b. b -> Either a b
Right (s
s, ())

lift :: Functor m => m a -> Get s m a
lift :: m a -> Get s m a
lift m a
m = (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, a))) -> Get s m a)
-> (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall a b. (a -> b) -> a -> b
$ \s
s -> (a -> Either ([String], SomeException) (s, a))
-> m a -> m (Either ([String], SomeException) (s, a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\a
x -> (s, a) -> Either ([String], SomeException) (s, a)
forall a b. b -> Either a b
Right (s
s, a
x)) m a
m

throw :: (Exception.Exception e, Applicative m) => e -> Get s m a
throw :: e -> Get s m a
throw = (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, a))) -> Get s m a)
-> (e -> s -> m (Either ([String], SomeException) (s, a)))
-> e
-> Get s m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m (Either ([String], SomeException) (s, a))
-> s -> m (Either ([String], SomeException) (s, a))
forall a b. a -> b -> a
const (m (Either ([String], SomeException) (s, a))
 -> s -> m (Either ([String], SomeException) (s, a)))
-> (e -> m (Either ([String], SomeException) (s, a)))
-> e
-> s
-> m (Either ([String], SomeException) (s, a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either ([String], SomeException) (s, a)
-> m (Either ([String], SomeException) (s, a))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ([String], SomeException) (s, a)
 -> m (Either ([String], SomeException) (s, a)))
-> (e -> Either ([String], SomeException) (s, a))
-> e
-> m (Either ([String], SomeException) (s, a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String], SomeException)
-> Either ([String], SomeException) (s, a)
forall a b. a -> Either a b
Left (([String], SomeException)
 -> Either ([String], SomeException) (s, a))
-> (e -> ([String], SomeException))
-> e
-> Either ([String], SomeException) (s, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (,) [] (SomeException -> ([String], SomeException))
-> (e -> SomeException) -> e -> ([String], SomeException)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> SomeException
forall e. Exception e => e -> SomeException
Exception.toException

embed :: Monad m => Get s m a -> s -> Get t m a
embed :: Get s m a -> s -> Get t m a
embed Get s m a
g s
s = do
  Either ([String], SomeException) (s, a)
r <- m (Either ([String], SomeException) (s, a))
-> Get t m (Either ([String], SomeException) (s, a))
forall (m :: * -> *) a s. Functor m => m a -> Get s m a
lift (m (Either ([String], SomeException) (s, a))
 -> Get t m (Either ([String], SomeException) (s, a)))
-> m (Either ([String], SomeException) (s, a))
-> Get t m (Either ([String], SomeException) (s, a))
forall a b. (a -> b) -> a -> b
$ Get s m a -> s -> m (Either ([String], SomeException) (s, a))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m a
g s
s
  case Either ([String], SomeException) (s, a)
r of
    Left ([String]
ls, SomeException
e) -> [String] -> Get t m a -> Get t m a
forall (m :: * -> *) s a.
Functor m =>
[String] -> Get s m a -> Get s m a
labels [String]
ls (Get t m a -> Get t m a) -> Get t m a -> Get t m a
forall a b. (a -> b) -> a -> b
$ SomeException -> Get t m a
forall e (m :: * -> *) s a.
(Exception e, Applicative m) =>
e -> Get s m a
throw SomeException
e
    Right (s
_, a
x) -> a -> Get t m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x

labels :: Functor m => [String] -> Get s m a -> Get s m a
labels :: [String] -> Get s m a -> Get s m a
labels [String]
ls Get s m a
g = (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall s (m :: * -> *) a.
(s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
Get ((s -> m (Either ([String], SomeException) (s, a))) -> Get s m a)
-> (s -> m (Either ([String], SomeException) (s, a))) -> Get s m a
forall a b. (a -> b) -> a -> b
$ (Either ([String], SomeException) (s, a)
 -> Either ([String], SomeException) (s, a))
-> m (Either ([String], SomeException) (s, a))
-> m (Either ([String], SomeException) (s, a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((([String], SomeException) -> ([String], SomeException))
-> Either ([String], SomeException) (s, a)
-> Either ([String], SomeException) (s, a)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
Bifunctor.first ((([String], SomeException) -> ([String], SomeException))
 -> Either ([String], SomeException) (s, a)
 -> Either ([String], SomeException) (s, a))
-> (([String], SomeException) -> ([String], SomeException))
-> Either ([String], SomeException) (s, a)
-> Either ([String], SomeException) (s, a)
forall a b. (a -> b) -> a -> b
$ ([String] -> [String])
-> ([String], SomeException) -> ([String], SomeException)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
Bifunctor.first ([String]
ls [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<>)) (m (Either ([String], SomeException) (s, a))
 -> m (Either ([String], SomeException) (s, a)))
-> (s -> m (Either ([String], SomeException) (s, a)))
-> s
-> m (Either ([String], SomeException) (s, a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get s m a -> s -> m (Either ([String], SomeException) (s, a))
forall s (m :: * -> *) a.
Get s m a -> s -> m (Either ([String], SomeException) (s, a))
run Get s m a
g

label :: Functor m => String -> Get s m a -> Get s m a
label :: String -> Get s m a -> Get s m a
label = [String] -> Get s m a -> Get s m a
forall (m :: * -> *) s a.
Functor m =>
[String] -> Get s m a -> Get s m a
labels ([String] -> Get s m a -> Get s m a)
-> (String -> [String]) -> String -> Get s m a -> Get s m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure