{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
module Network.MPD.Applicative.Internal
( Parser(..)
, liftParser
, getResponse
, emptyResponse
, unexpected
, Command(..)
, runCommand
) where
import Control.Applicative
import Control.Monad
import Data.ByteString.Char8 (ByteString)
import Network.MPD.Core hiding (getResponse)
import qualified Network.MPD.Core as Core
import Control.Monad.Error
newtype Parser a
= Parser { runParser :: [ByteString] -> Either String (a, [ByteString]) }
deriving Functor
instance Monad Parser where
fail = Parser . const . Left
return a = Parser $ \input -> Right (a, input)
p1 >>= p2 = Parser $ \input -> runParser p1 input >>= uncurry (runParser . p2)
instance Applicative Parser where
pure = return
(<*>) = ap
liftParser :: ([ByteString] -> Either String a) -> Parser a
liftParser p = Parser $ \input -> case break (== "list_OK") input of
(xs, ys) -> fmap (, drop 1 ys) (p xs)
getResponse :: Parser [ByteString]
getResponse = Parser $ \input -> case break (== "list_OK") input of
(xs, ys) -> Right (xs, drop 1 ys)
emptyResponse :: Parser ()
emptyResponse = do
r <- getResponse
unless (null r) $
unexpected r
unexpected :: [ByteString] -> Parser a
unexpected = fail . ("unexpected Response: " ++) . show
data Command a = Command {
commandParser :: Parser a
, commandRequest :: [String]
} deriving Functor
instance Applicative Command where
pure a = Command (pure a) []
(Command p1 c1) <*> (Command p2 c2) = Command (p1 <*> p2) (c1 ++ c2)
runCommand :: MonadMPD m => Command a -> m a
runCommand (Command p c) = do
r <- Core.getResponse command
case runParser p r of
Left err -> throwError (Unexpected err)
Right (a, []) -> return a
Right (_, xs) -> throwError (Unexpected $ "superfluous input: " ++ show xs)
where
command = case c of
[x] -> x
xs -> unlines ("command_list_ok_begin" : xs)
++ "command_list_end"