{-# LANGUAGE CPP #-}
module Ersatz.Internal.Parser
( Parser
, runParser
, sepBy, sepBy1
, token, string
, integer, natural
, eof
, satisfy
) where
import Control.Applicative
import Control.Monad.State
import Data.Char (isDigit)
#if __GLASGOW_HASKELL__ < 710
import Data.Traversable (traverse)
#endif
type Parser t a = StateT [t] [] a
runParser :: Parser t a -> [t] -> [a]
runParser = evalStateT
sepBy :: Parser t a -> Parser t sep -> Parser t [a]
sepBy p sep = sepBy1 p sep <|> pure []
sepBy1 :: Parser t a -> Parser t sep -> Parser t [a]
sepBy1 p sep = (:) <$> p <*> many (sep *> p)
token :: Eq t => t -> Parser t t
token t = satisfy (== t)
string :: Eq t => [t] -> Parser t [t]
string = traverse token
integer :: (Num i, Read i) => Parser Char i
integer = negation <*> natural
negation :: Num n => Parser Char (n -> n)
negation = negate <$ token '-'
<|> pure id
natural :: Read i => Parser Char i
natural = read <$> some (satisfy isDigit)
eof :: Parser t ()
eof = do
[] <- get
return ()
satisfy :: (t -> Bool) -> Parser t t
satisfy f = do
(t:ts) <- get
guard (f t)
t <$ put ts