module Data.Picoparsec.Zepto
(
Parser
, parse
, atEnd
, string
, take
, takeCharsWhile
, takeWhile
) where
import Control.Applicative
import Control.Monad
import Data.Monoid.Cancellative (LeftReductiveMonoid(..))
import Data.Monoid.Null (MonoidNull(null))
import qualified Data.Monoid.Factorial as Factorial
import Data.Monoid.Factorial (FactorialMonoid)
import Data.Monoid.Textual (TextualMonoid)
import qualified Data.Monoid.Textual as Textual
import Prelude hiding (null, take, takeWhile)
data Result a = Fail String
| OK !a
newtype Parser t a = Parser {
runParser :: t -> (# Result a, t #)
}
instance Functor (Parser t) where
fmap f m = Parser $ \s -> case runParser m s of
(# OK a, s' #) -> (# OK (f a), s' #)
(# Fail err, s' #) -> (# Fail err, s' #)
instance Monad (Parser t) where
return a = Parser $ \s -> (# OK a, s #)
m >>= k = Parser $ \s -> case runParser m s of
(# OK a, s' #) -> runParser (k a) s'
(# Fail err, s' #) -> (# Fail err, s' #)
fail msg = Parser $ \s -> (# Fail msg, s #)
instance MonadPlus (Parser t) where
mzero = fail "mzero"
mplus a b = Parser $ \s ->
case runParser a s of
(# ok@(OK _), s' #) -> (# ok, s' #)
(# _, _ #) -> case runParser b s of
(# ok@(OK _), s'' #) -> (# ok, s'' #)
(# err, s'' #) -> (# err, s'' #)
instance Applicative (Parser t) where
pure = return
(<*>) = ap
gets :: (t -> a) -> Parser t a
gets f = Parser $ \s -> (# OK (f s), s #)
put :: t -> Parser t ()
put s = Parser $ \_ -> (# OK (), s #)
parse :: Parser t a -> t -> Either String a
parse p s = case runParser p s of
(# OK a, _ #) -> Right a
(# Fail err, _ #) -> Left err
instance Alternative (Parser t) where
empty = fail "empty"
(<|>) = mplus
takeWhile :: FactorialMonoid t => (t -> Bool) -> Parser t t
takeWhile p = do
(h,t) <- gets (Factorial.span p)
put t
return h
takeCharsWhile :: TextualMonoid t => (Char -> Bool) -> Parser t t
takeCharsWhile p = do
(h,t) <- gets (Textual.span_ False p)
put t
return h
take :: FactorialMonoid t => Int -> Parser t t
take !n = do
s <- gets id
if Factorial.length s >= n
then put (Factorial.drop n s) >> return (Factorial.take n s)
else fail "insufficient input"
string :: LeftReductiveMonoid t => t -> Parser t ()
string s = do
i <- gets id
case stripPrefix s i
of Just suffix -> put suffix >> return ()
Nothing -> fail "string"
atEnd :: MonoidNull t => Parser t Bool
atEnd = do
i <- gets id
return $! null i