-- |A module providing simple Parser combinator functionality. Useful
-- for small parsing tasks such as identifier parsing or command-line
-- argument parsing
module Control.Parser (
  module SimpleH,
  -- * The ParserT Type
  ParserT(..),Parser,ParserA(..),_ParserA,

  -- ** The Stream class
  Stream(..),emptyStream,

  -- ** Converting to/from Parsers
  parserT,parser,runParser,runParserT,pureParser,eitherParser,

  -- * Basic combinators
  (<+>),(>*>),(<*<),
  token,satisfy,
  oneOf,noneOf,single,
  several,
  remaining,eoi,

  -- ** Specialized utilities
  readable,number,digit,letter,alNum,quotedString,space,spaces,eol,
  
  -- * Basic combinators
  many,many1,sepBy,sepBy1,
  chainl,chainr                          
  ) where

import SimpleH

import qualified Data.ByteString.Char8 as BS
import Data.Char

newtype ParserT w s m a = ParserT (StateT s (ListT (WriterT w m)) a)
                        deriving (Unit,Functor,Applicative,Monoid,Semigroup,
                                  Monad,MonadFix,MonadState s,MonadWriter w)
type Parser w c a = ParserT w c Id a
deriving instance (Monad m,Monoid w) => MonadError Void (ParserT w c m)
instance Monoid w => MonadTrans (ParserT w s) where
  lift = ParserT . lift . lift . lift
  generalize = parserT %%~ map (pure.yb _Id)
_ParserT :: Iso (ParserT w s m a) (ParserT x t n b) (StateT s (ListT (WriterT w m)) a) (StateT t (ListT (WriterT x n)) b)
_ParserT = iso ParserT (\(ParserT p) -> p)
parserT :: (Functor n,Functor m) => Iso (ParserT w s m a) (ParserT x t n b) (s -> m (w,[(s,a)])) (t -> n (x,[(t,b)]))
parserT = _mapping (_writerT._listT).stateT._ParserT
parser :: Iso (Parser w s a) (Parser x t b) (s -> (w,[(s,a)])) (t -> (x,[(t,b)]))
parser = _mapping _Id.parserT
runParser :: Parser Void s a -> s -> [(s,a)]
runParser = map snd . yb parser
runParserT :: Functor m => ParserT Void s m a -> s -> m [(s,a)]
runParserT = map2 snd . (^..parserT)
pureParser :: (Monoid w,Monad m) => (s -> [a]) -> ParserT w s m a
pureParser p = (\a -> pure (zero,[(a,b) | b <- p a]))^.parserT
eitherParser :: Monoid w => (s -> Either w a) :<->: Parser w s a
eitherParser = iso (\p s -> (,[])<|>pure.pure.(s,) $ p s)
               (\p' s -> case p' s of
                   (w,[]) -> Left w
                   (_,((_,a):_)) -> Right a).parser
               
  
-- |The @(+)@ operator with lower priority
(<+>) :: Semigroup m => m -> m -> m
(<+>) = (+)
(>*>) :: (Monoid w, Monad m) => ParserT w a m b -> ParserT w b m c -> ParserT w a m c
(>*>) = (>>>)^..(_ParserA<.>_ParserA<.>_ParserA)
(<*<) :: (Monoid w, Monad m) => ParserT w b m c -> ParserT w a m b -> ParserT w a m c
(<*<) = flip (>*>)

newtype ParserA w m s a = ParserA (ParserT w s m a)
_ParserA :: Iso (ParserA w m s a) (ParserA w' m' s' a') (ParserT w s m a) (ParserT w' s' m' a')
_ParserA = iso ParserA (\(ParserA p) -> p)
parserA :: Iso (ParserA w m s a) (ParserA w' m' s' a') (StateA (ListT (WriterT w m)) s a) (StateA (ListT (WriterT w' m')) s' a') 
parserA = from stateA._ParserT._ParserA
instance (Monoid w,Monad m) => Category (ParserA w m) where
  id = ParserA get
  (.) = (.)^.(parserA<.>parserA<.>parserA)
instance (Monoid w,Monad m) => Split (ParserA w m) where
  (<#>) = (<#>)^.(parserA<.>parserA<.>parserA)
instance (Monoid w,Monad m) => Choice (ParserA w m) where
  (<|>) = (<|>)^.(parserA<.>parserA<.>parserA)
instance (Monoid w,Monad m) => Arrow (ParserA w m) where
  arr f = arr f^.parserA

-- |The remaining Stream to parse
remaining :: (Monad m,Monoid w) => ParserT w s m s
remaining = get
-- |Consume a token from the Stream
token :: (Monad m,Monoid w,Stream c s) => ParserT w s m c
{-# SPECIALIZE token :: (Monad m,Monoid w) => ParserT w [c] m c #-}
token = get >>= \s -> case uncons s of
  Nothing -> zero
  Just (c,t) -> put t >> pure c

-- |Parse zero, one or more successive occurences of a parser.
many :: (Monoid w,Monad m) => ParserT w c m a -> ParserT w c m [a]
many p = liftA2 (:) p (many p) <+> pure []
-- |Parse one or more successiveé occurences of a parser.
many1 :: (Monoid w,Monad m) => ParserT w c m a -> ParserT w c m [a]
many1 p = (:)<$>p<*>many p

-- |Consume a token and succeed if it verifies a predicate
satisfy :: (Monoid w, Monad m, Stream c s) => (c -> Bool) -> ParserT w s m c
{-# SPECIALIZE satisfy :: (Monoid w, Monad m) => (c -> Bool) -> ParserT w [c] m c #-}
satisfy p = token <*= guard . p
-- |Consume a single fixed token or fail.
single :: (Eq c, Monoid w, Monad m, Stream c s) => c -> ParserT w s m ()
single = void . satisfy . (==)

-- |Consume a structure of characters or fail
several :: (Eq c, Monoid w, Monad m, Foldable t, Stream c s) => t c -> ParserT w s m ()
{-# SPECIALIZE several :: (Eq c, Monoid w, Monad m) => [c] -> ParserT w [c] m () #-}
several l = traverse_ single l

-- |Try to consume a parser. Return a default value when it fails.
option :: (Monoid w,Monad m) => a -> ParserT w s m a -> ParserT w s m a
option a p = p+pure a

-- |Succeed only if we are by the End Of Input.
eoi :: (Monad m,Monoid w,Stream c s) => ParserT w s m ()
eoi = remaining >>= guard.emptyStream
-- |The end of line
eol :: (Monad m,Monoid w,Stream Char s) => ParserT w s m ()
eol = single '\n'

-- |Parse one or more successive occurences of a parser separated by
-- occurences of a second parser.
sepBy1 ::(Monoid w, Monad m) => ParserT w c m a -> ParserT w c m b -> ParserT w c m [a]
sepBy1 p sep = (:)<$>p<*>many (sep >> p)
-- |Parse zero or more successive occurences of a parser separated by
-- occurences of a second parser.
sepBy ::(Monoid w, Monad m) => ParserT w c m a -> ParserT w c m b -> ParserT w c m [a]
sepBy p sep = option [] (sepBy1 p sep)

-- |Parse a member of a set of values
oneOf :: (Eq c, Monoid w, Monad m, Foldable t, Stream c s) => t c -> ParserT w s m c
oneOf = satisfy . flip elem
-- |Parse anything but a member of a set
noneOf :: (Eq c, Monoid w, Monad m, Foldable t, Stream c s) => t c -> ParserT w s m c
noneOf = satisfy . map not . flip elem

-- |Parse a litteral decimal number
number :: (Monoid w,Monad m,Stream Char s,Num n) => ParserT w s m n
number = fromInteger.read <$> many1 digit
-- |Parse a single decimal digit
digit :: (Monoid w,Monad m,Stream Char s) => ParserT w s m Char
digit = satisfy isDigit
alNum :: (Monoid w,Monad m,Stream Char s) => ParserT w s m Char
alNum = satisfy isAlphaNum
letter :: (Monoid w,Monad m,Stream Char s) => ParserT w s m Char
letter = satisfy isAlpha
-- |Parse a delimited string, unsing '\\' as the quoting character
quotedString :: (Monoid w,Monad m,Stream Char s) => Char -> ParserT w s m String
quotedString d = between (single d) (single d) (many ch)
  where ch = single '\\' *> unquote<$>token
             <+> noneOf (d:"\\")
        unquote 'n' = '\n'
        unquote 't' = '\t'
        unquote c = c
-- |A single space
space :: (Monoid w,Monad m,Stream Char s) => ParserT w s m Char
space = satisfy isSpace
-- |Many spaces
spaces :: (Monoid w,Monad m,Stream Char s) => ParserT w s m String
spaces = many1 space

infixl 1 `sepBy`,`sepBy1`
infixr 0 <+>

-- |Chain an operator with an initial value and several tail values.
chainr :: (Monoid w,Stream c s,Monad m) => ParserT w s m a -> ParserT w s m (b -> a -> a) -> ParserT w s m b -> ParserT w s m a
chainr expr op e = compose<$>many (op<**>e)<*>expr
-- |Chain an operator with an initial value
chainl :: (Monoid w,Stream c s,Monad m) => ParserT w s m a -> ParserT w s m (a -> b -> a) -> ParserT w s m b -> ParserT w s m a
chainl expr op e = compose<$>many (flip<$>op<*>e)<**>expr

class Stream c s | s -> c where
  uncons :: s -> Maybe (c,s)
  cons :: c -> s -> s
instance Stream a [a] where
  uncons [] = Nothing
  uncons (x:xs) = Just (x,xs)
  cons = (:)
instance Stream Char BS.ByteString where
  uncons = BS.uncons
  cons = BS.cons

-- |Test if a Stream is empty
emptyStream :: Stream c s => s -> Bool
emptyStream = maybe True (const False) . uncons

class Serializable t where
  encode :: t -> BS.ByteString
  decode :: Parser String BS.ByteString t
instance Serializable BS.ByteString where
  encode = id ; decode = get

readable :: (Monoid w,Monad m,Read a) => ParserT w String m a 
readable = map (pure.pure.map swap) (readsPrec 0)^.parserT