module ParserMonad where
import Data.Char
import Control.Applicative hiding (many, (<|>))
-- | Parser type
newtype Parser a = P (String -> [ (a, String) ])
-- | parse function
parse :: Parser a -> String -> [ (a, String) ]
parse (P p) s = p s
-- | conveyer of parsers
(<|>) :: Parser a -> Parser a -> Parser a
p1 <|> p2 = P $ \cs -> case parse p1 cs of
[] -> parse p2 cs
ps -> ps
instance Monad Parser where
p1 >>= fp2 = P $ \cs -> do
(a, cs') <- parse p1 cs
parse (fp2 a) cs'
return x = P $ \cs -> [ (x, cs) ]
fail _ = P $ \_ -> []
instance Applicative Parser where
pure x = P $ \cs -> [ (x, cs) ]
a <*> b = a >>= (\f -> fmap f b)
instance Functor Parser where
fmap f p = p >>= \x -> return (f x)
-- | Parses one char
anyChar :: Parser Char
anyChar = P $ \cs -> case cs of
(x:xs) -> [ (x, xs) ]
[] -> []
-- | Parses char by predicate
satisfy :: (Char -> Bool) -> Parser Char
satisfy p = do
c <- anyChar
if p c then return c else fail "Did not satisfy boolean predicate"
-- | Parses exact Char
char :: Char -> Parser Char
char = satisfy . (==)
-- | Parses exact String
string :: String -> Parser String
string = mapM char
-- | Parses zero or more instances of p.
many :: Parser a -> Parser [a]
many p = rest p <|> (return [])
-- | Parses one or more instances of p.
rest :: Parser a -> Parser [a]
rest p = do
x <- p
xs <- many p
return (x:xs)
-- | Parses one special character
alpha, digit, upper, lower, space :: Parser Char
alpha = satisfy isAlpha
digit = satisfy isDigit
upper = satisfy isUpper
lower = satisfy isLower
space = satisfy isSpace
-- | Parses integer
int :: Parser Int
int = do
s <- string "-" <|> return []
d <- rest digit
return (read (s ++ d) :: Int)
-- | Parses sequence of 'ok' chars
manySatisfiedChars :: (Char -> Bool) -> Parser String
manySatisfiedChars = many . satisfy
restSatisfiedChars :: (Char -> Bool) -> Parser String
restSatisfiedChars = rest . satisfy
-- | Parses word of non-space characters
-- | Skips spacing characters
skipSpaces :: Parser ()
skipSpaces = do
_ <- manySatisfiedChars isSpace
return ()
-- | Skips spacing characters (more than zero)
waitAndSkipSpaces :: Parser ()
waitAndSkipSpaces = do
_ <- restSatisfiedChars isSpace
return ()
-- | Returns remaining input
restOfInput :: Parser String
restOfInput = manySatisfiedChars $ const True
-- | Fails if end was not reached
end :: Parser ()
end = do
b <- do {
_ <- anyChar ;
return False ;
} <|> return True
if b then return () else fail "End wasn't reached"
-- | Connects all parsers
unlist :: [Parser a] -> Parser a
unlist = foldr (<|>) (fail "Could not parse")