module Data.Spreadsheet.Parser where

import qualified Data.Spreadsheet.CharSource as CharSource

import qualified Control.Monad.Exception.Asynchronous as Async

import Data.Functor.Identity (Identity, )
import Control.Monad (liftM, liftM2, )

import Data.Maybe (fromMaybe, )


type T source a = source a

type Straight        source a = source Identity a
type Fallible        source a = source Maybe    a
type Partial         source a = source Identity (PossiblyIncomplete a)
type PartialFallible source a = source Maybe    (PossiblyIncomplete a)

type PossiblyIncomplete a = Async.Exceptional UserMessage a

type UserMessage = String


satisfy ::
   (CharSource.C source) =>
   (Char -> Bool) -> Fallible source Char
satisfy :: forall (source :: (* -> *) -> * -> *).
C source =>
(Char -> Bool) -> Fallible source Char
satisfy Char -> Bool
p =
   do Char
c <- Fallible source Char
forall (m :: (* -> *) -> * -> *). C m => m Maybe Char
CharSource.get
      if Char -> Bool
p Char
c
        then Char -> Fallible source Char
forall a. a -> source Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return Char
c
        else Fallible source Char
forall a. source Maybe a
forall (m :: (* -> *) -> * -> *) a. C m => m Maybe a
CharSource.stop

char :: (CharSource.C source) =>
   Char -> Fallible source ()
char :: forall (source :: (* -> *) -> * -> *).
C source =>
Char -> Fallible source ()
char Char
c = (Char -> Bool) -> Fallible source Char
forall (source :: (* -> *) -> * -> *).
C source =>
(Char -> Bool) -> Fallible source Char
satisfy (Char
cChar -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==) Fallible source Char -> source Maybe () -> source Maybe ()
forall a b. source Maybe a -> source Maybe b -> source Maybe b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> source Maybe ()
forall a. a -> source Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

string :: (CharSource.C source) =>
   String -> Fallible source ()
string :: forall (source :: (* -> *) -> * -> *).
C source =>
String -> Fallible source ()
string String
s = (Char -> source Maybe ()) -> String -> source Maybe ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Char -> source Maybe ()
forall (source :: (* -> *) -> * -> *).
C source =>
Char -> Fallible source ()
char String
s

many :: (CharSource.C source) =>
   Fallible source a -> Straight source [a]
many :: forall (source :: (* -> *) -> * -> *) a.
C source =>
Fallible source a -> Straight source [a]
many Fallible source a
p =
   let go :: source Identity [a]
go =
         (Maybe [a] -> [a])
-> source Identity (Maybe [a]) -> source Identity [a]
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ([a] -> Maybe [a] -> [a]
forall a. a -> Maybe a -> a
fromMaybe []) (source Identity (Maybe [a]) -> source Identity [a])
-> source Identity (Maybe [a]) -> source Identity [a]
forall a b. (a -> b) -> a -> b
$
         source Maybe [a] -> source Identity (Maybe [a])
forall a. source Maybe a -> source Identity (Maybe a)
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try
            ((a -> [a] -> [a])
-> Fallible source a -> source Maybe [a] -> source Maybe [a]
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 (:) Fallible source a
p (source Identity [a] -> source Maybe [a]
forall a. source Identity a -> source Maybe a
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible source Identity [a]
go))
   in  source Identity [a]
go

appendIncomplete ::
   CharSource.C source =>
   PartialFallible source a ->
   Partial source [a] ->
   PartialFallible source [a]
appendIncomplete :: forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a
-> Partial source [a] -> PartialFallible source [a]
appendIncomplete PartialFallible source a
p Partial source [a]
ps =
   do ~(Async.Exceptional Maybe String
me a
x) <- PartialFallible source a
p
      Partial source [a] -> PartialFallible source [a]
forall a. source Identity a -> source Maybe a
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible (Partial source [a] -> PartialFallible source [a])
-> Partial source [a] -> PartialFallible source [a]
forall a b. (a -> b) -> a -> b
$ (Exceptional String [a] -> Exceptional String [a])
-> Partial source [a] -> Partial source [a]
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (([a] -> [a]) -> Exceptional String [a] -> Exceptional String [a]
forall a b.
(a -> b) -> Exceptional String a -> Exceptional String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:)) (Partial source [a] -> Partial source [a])
-> Partial source [a] -> Partial source [a]
forall a b. (a -> b) -> a -> b
$
         Partial source [a]
-> (String -> Partial source [a])
-> Maybe String
-> Partial source [a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Partial source [a]
ps (\String
_ -> Exceptional String [a] -> Partial source [a]
forall a. a -> source Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe String -> [a] -> Exceptional String [a]
forall e a. Maybe e -> a -> Exceptional e a
Async.Exceptional Maybe String
me [])) Maybe String
me

absorbException ::
   (CharSource.C source) =>
   PartialFallible source [a] ->
   Partial source [a]
absorbException :: forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source [a] -> Partial source [a]
absorbException =
   (Maybe (PossiblyIncomplete [a]) -> PossiblyIncomplete [a])
-> source Identity (Maybe (PossiblyIncomplete [a]))
-> source Identity (PossiblyIncomplete [a])
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (PossiblyIncomplete [a]
-> Maybe (PossiblyIncomplete [a]) -> PossiblyIncomplete [a]
forall a. a -> Maybe a -> a
fromMaybe ([a] -> PossiblyIncomplete [a]
forall a e. a -> Exceptional e a
Async.pure [])) (source Identity (Maybe (PossiblyIncomplete [a]))
 -> source Identity (PossiblyIncomplete [a]))
-> (PartialFallible source [a]
    -> source Identity (Maybe (PossiblyIncomplete [a])))
-> PartialFallible source [a]
-> source Identity (PossiblyIncomplete [a])
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
   PartialFallible source [a]
-> source Identity (Maybe (PossiblyIncomplete [a]))
forall a. source Maybe a -> source Identity (Maybe a)
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try

manyIncomplete :: CharSource.C source =>
   PartialFallible source a -> Partial source [a]
manyIncomplete :: forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a -> Partial source [a]
manyIncomplete PartialFallible source a
p =
   let go :: Partial source [a]
go = PartialFallible source [a] -> Partial source [a]
forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source [a] -> Partial source [a]
absorbException (PartialFallible source a
-> Partial source [a] -> PartialFallible source [a]
forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a
-> Partial source [a] -> PartialFallible source [a]
appendIncomplete PartialFallible source a
p Partial source [a]
go)
   in  Partial source [a]
go

sepByIncomplete :: CharSource.C source =>
   Fallible source sep -> PartialFallible source a -> Partial source [a]
sepByIncomplete :: forall (source :: (* -> *) -> * -> *) sep a.
C source =>
Fallible source sep
-> PartialFallible source a -> Partial source [a]
sepByIncomplete Fallible source sep
sep PartialFallible source a
p =
   PartialFallible source [a] -> Partial source [a]
forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source [a] -> Partial source [a]
absorbException (PartialFallible source [a] -> Partial source [a])
-> PartialFallible source [a] -> Partial source [a]
forall a b. (a -> b) -> a -> b
$
   PartialFallible source a
-> Partial source [a] -> PartialFallible source [a]
forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a
-> Partial source [a] -> PartialFallible source [a]
appendIncomplete PartialFallible source a
p (Partial source [a] -> PartialFallible source [a])
-> Partial source [a] -> PartialFallible source [a]
forall a b. (a -> b) -> a -> b
$
   PartialFallible source a -> Partial source [a]
forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a -> Partial source [a]
manyIncomplete (Fallible source sep
sep Fallible source sep
-> PartialFallible source a -> PartialFallible source a
forall a b. source Maybe a -> source Maybe b -> source Maybe b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> PartialFallible source a
p)

between :: (CharSource.C source) =>
   UserMessage ->
   Fallible source open -> Fallible source close ->
   Partial source a -> PartialFallible source a
between :: forall (source :: (* -> *) -> * -> *) open close a.
C source =>
String
-> Fallible source open
-> Fallible source close
-> Partial source a
-> PartialFallible source a
between String
msg Fallible source open
open Fallible source close
close Partial source a
p =
   Fallible source open
open Fallible source open
-> source Maybe (PossiblyIncomplete a)
-> source Maybe (PossiblyIncomplete a)
forall a b. source Maybe a -> source Maybe b -> source Maybe b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
   Partial source a -> source Maybe (PossiblyIncomplete a)
forall a. source Identity a -> source Maybe a
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible (String
-> Fallible source close -> Partial source a -> Partial source a
forall (source :: (* -> *) -> * -> *) close a.
C source =>
String
-> Fallible source close -> Partial source a -> Partial source a
terminated String
msg Fallible source close
close Partial source a
p)

terminated :: (CharSource.C source) =>
   UserMessage ->
   Fallible source close ->
   Partial source a -> Partial source a
terminated :: forall (source :: (* -> *) -> * -> *) close a.
C source =>
String
-> Fallible source close -> Partial source a -> Partial source a
terminated String
msg Fallible source close
close Partial source a
p =
   do PossiblyIncomplete a
enclosed <- Partial source a
p
      Maybe close
term <- Fallible source close -> source Identity (Maybe close)
forall a. source Maybe a -> source Identity (Maybe a)
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try Fallible source close
close
      PossiblyIncomplete a -> Partial source a
forall a. a -> source Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (PossiblyIncomplete a
enclosed PossiblyIncomplete a -> Maybe String -> PossiblyIncomplete a
forall e a. Exceptional e a -> Maybe e -> Exceptional e a
`Async.maybeAbort`
              Maybe String
-> (close -> Maybe String) -> Maybe close -> Maybe String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Maybe String
forall a. a -> Maybe a
Just String
msg) (Maybe String -> close -> Maybe String
forall a b. a -> b -> a
const Maybe String
forall a. Maybe a
Nothing) Maybe close
term)


-- mplus
eitherOr :: (CharSource.C source) =>
   Fallible source a -> Fallible source a -> Fallible source a
eitherOr :: forall (source :: (* -> *) -> * -> *) a.
C source =>
Fallible source a -> Fallible source a -> Fallible source a
eitherOr Fallible source a
x Fallible source a
y =
   source Identity (Maybe a) -> source Maybe (Maybe a)
forall a. source Identity a -> source Maybe a
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible (Fallible source a -> source Identity (Maybe a)
forall a. source Maybe a -> source Identity (Maybe a)
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try Fallible source a
x) source Maybe (Maybe a)
-> (Maybe a -> Fallible source a) -> Fallible source a
forall a b.
source Maybe a -> (a -> source Maybe b) -> source Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Fallible source a
-> (a -> Fallible source a) -> Maybe a -> Fallible source a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Fallible source a
y a -> Fallible source a
forall a. a -> source Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return

deflt :: (CharSource.C source) =>
   Straight source a -> Fallible source a -> Straight source a
deflt :: forall (source :: (* -> *) -> * -> *) a.
C source =>
Straight source a -> Fallible source a -> Straight source a
deflt Straight source a
x Fallible source a
y =
   Straight source a
-> (a -> Straight source a) -> Maybe a -> Straight source a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Straight source a
x a -> Straight source a
forall a. a -> source Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a -> Straight source a)
-> source Identity (Maybe a) -> Straight source a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Fallible source a -> source Identity (Maybe a)
forall a. source Maybe a -> source Identity (Maybe a)
forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try Fallible source a
y