-- |Basic types and interfaces
module Data.Deciparsec.Parser ( -- * Types
                                Parser, Result, ParserT, IResult(..), TokenSeq
                                -- * Running Parsers
                                -- ** Resupplyable parsers
                              , runParserT, feedT, runParser, feed
                                -- ** Non-resupplyable parsers
                              , runParserT', evalParserT, execParserT, runParser', evalParser, execParser
                                -- * User State
                              , getUserState, putUserState, modifyUserState
                                -- * Source Position
                              , SourcePos, spName, spLine, spColumn, getSourcePos, putSourcePos, modifySourcePos
                              ) where
import Data.Monoid

import Data.Functor.Identity

import Data.Deciparsec.Internal
import Data.Deciparsec.Internal.Types
import Data.Deciparsec.TokenSeq (TokenSeq)

-- |A Parser over the 'Identity' monad.
type Parser s u r = ParserT s u Identity r

-- |An 'IResult' in the 'Identity' monad.
type Result s u r = IResult s u Identity r

-- |The most general way to run a parser. A 'Partial' result can be resupplied with 'feedT'.
runParserT :: (Monad m, TokenSeq s t) =>
             ParserT s u m a -- ^The parser
           -> u -- ^The inital user state
           -> String -- ^The name of the source \"file\"
           -> s -- ^An inital token sequence. The rest can be supplied later
           -> m (IResult s u m a)
runParserT p u src ts = runParserT_ p (ParserState (SourcePos src 1 1) u) (I ts) mempty Incomplete failK successK

-- |Run a parser that cannot be resupplied. This will return either an error, or the result of the parse and the
--  final user state.
runParserT' :: (Monad m, TokenSeq s t) =>
              ParserT s u m a -- ^The parser
            -> u -- ^The initial user state
            -> String -- ^The name of the source \"file\"
            -> s -- ^The entire token sequence to parse
            -> m (Either ParseError (a, u))
runParserT' p u src ts = do
  ir <- runParserT_ p (ParserState (SourcePos src 1 1) u) (I ts) mempty Complete failK successK
  case ir of
    Fail _ _  pe -> return $ Left pe
    Done _ u' r  -> return $ Right (r, u')
    _            -> fail $ "runParserT': impossible error!"

-- |Run a parser that cannot be resupplied, and return either an error or the result of the parser. The
--  final user state will be discarded.
evalParserT :: (Monad m, TokenSeq s t) =>
              ParserT s u m a -- ^The parser
            -> u -- ^The initial user state
            -> String -- ^The name of the source \"file\"
            -> s -- ^The entire token sequence to parse
            -> m (Either ParseError a)
evalParserT p u src ts = do
  res <- runParserT' p u src ts
  return $ either Left (Right . fst) res
  -- either Left (Right . fst) <$> runParserT' p u src ts -- This requires :: Functor m

-- |Run a parser that cannot be resupplied, and return either an error or the final user state. The
--  result of the parser will be discarded.
execParserT :: (Monad m, TokenSeq s t) => ParserT s u m a -> u -> String -> s -> m (Either ParseError u)
execParserT p u src ts = do
  res <- runParserT' p u src ts
  return $ either Left (Right . snd) res
  -- either Left (Right . snd) <$> runParserT' p u src ts -- This requires :: Functor m

-- |Run a parser in the 'Identity' monad. A 'Partial' result can be resupplied with 'feed'.
runParser :: TokenSeq s t =>
            Parser s u a -- ^The parser
          -> u -- ^The initial user state
          -> String -- ^The name of the source \"file\"
          -> s -- ^An initial token sequence. The rest can be supplied later
          -> Result s u a
runParser p u src ts = runIdentity $ runParserT p u src ts

-- |Run a parser that cannot be resupplied in the 'Identity' monad.
runParser' :: TokenSeq s t =>
             Parser s u a -- ^The parser
           -> u -- ^The initial user state
           -> String -- ^The name of the source \"file\"
           -> s -- ^The entire token sequence to parse
           -> Either ParseError (a, u)
runParser' p u src ts = runIdentity $ runParserT' p u src ts

-- |Run a parser that cannot be resupplied in the 'Identity' monad, and return either an error or the result of
--  the parser. The final user state will be discarded.
evalParser :: TokenSeq s t => Parser s u a -> u -> String -> s -> Either ParseError a
evalParser p u src ts = runIdentity $ evalParserT p u src ts

-- |Run a parser that cannot be resupplied in the 'Identity' monad, and return either an error or the final user
--  state. The result of the parser will be discarded.
execParser :: TokenSeq s t => Parser s u a -> u -> String -> s -> Either ParseError u
execParser p u src ts = runIdentity $ execParserT p u src ts

-- |Provide additional input to a 'Partial' result from 'runParserT'. Provide an
--  'Data.Deciparsec.Internal.TokenSeq.empty' sequence to force the parser to \"finish\".
feedT :: (Monad m, TokenSeq s t) => IResult s u m a -> s -> m (IResult s u m a)
feedT f@(Fail {}) _ = return f
feedT (Partial k) ts = k ts
feedT (Done ts u r) ts' = return $ Done (ts <> ts') u r

-- |Provide additional input to a 'Partial' result from 'runParser'. Provide an
--  'Data.Deciparsec.Internal.TokenSeq.empty' sequence to force the parser to \"finish\".
feed :: TokenSeq s t => Result s u a -> s -> Result s u a
feed = ((.).(.)) runIdentity feedT

failK :: Monad m => Failure s u m a
failK s0 i0 _a0 _m0 pe = return $ Fail (unI i0) (psState s0) pe

successK :: Monad m => Success s u a m a
successK s0 i0 _a0 _m0 a = return $ Done (unI i0) (psState s0) a
