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 <- forall (m :: (* -> *) -> * -> *). C m => m Maybe Char
CharSource.get
      if Char -> Bool
p Char
c
        then forall (m :: * -> *) a. Monad m => a -> m a
return Char
c
        else 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 = forall (source :: (* -> *) -> * -> *).
C source =>
(Char -> Bool) -> Fallible source Char
satisfy (Char
cforall a. Eq a => a -> a -> Bool
==) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> 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 = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ 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 =
         forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a. a -> Maybe a -> a
fromMaybe []) forall a b. (a -> b) -> a -> b
$
         forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try
            (forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 (:) Fallible source a
p (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
      forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a
xforall a. a -> [a] -> [a]
:)) forall a b. (a -> b) -> a -> b
$
         forall b a. b -> (a -> b) -> Maybe a -> b
maybe Partial source [a]
ps (\String
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return (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 =
   forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a. a -> Maybe a -> a
fromMaybe (forall a e. a -> Exceptional e a
Async.pure [])) forall b c a. (b -> c) -> (a -> b) -> a -> c
.
   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 = forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source [a] -> Partial source [a]
absorbException (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 =
   forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source [a] -> Partial source [a]
absorbException forall a b. (a -> b) -> a -> b
$
   forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a
-> Partial source [a] -> PartialFallible source [a]
appendIncomplete PartialFallible source a
p forall a b. (a -> b) -> a -> b
$
   forall (source :: (* -> *) -> * -> *) a.
C source =>
PartialFallible source a -> Partial source [a]
manyIncomplete (Fallible source sep
sep 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 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
   forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible (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 <- forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try Fallible source close
close
      forall (m :: * -> *) a. Monad m => a -> m a
return (PossiblyIncomplete a
enclosed forall e a. Exceptional e a -> Maybe e -> Exceptional e a
`Async.maybeAbort`
              forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. a -> Maybe a
Just String
msg) (forall a b. a -> b -> a
const 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 =
   forall (m :: (* -> *) -> * -> *) a.
C m =>
m Identity a -> m Maybe a
CharSource.fallible (forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try Fallible source a
x) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall b a. b -> (a -> b) -> Maybe a -> b
maybe Fallible source a
y 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 =
   forall b a. b -> (a -> b) -> Maybe a -> b
maybe Straight source a
x forall (m :: * -> *) a. Monad m => a -> m a
return forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: (* -> *) -> * -> *) a.
C m =>
m Maybe a -> m Identity (Maybe a)
CharSource.try Fallible source a
y