mankala/Parser.hs
2022-10-30 12:09:15 +01:00

82 lines
2.2 KiB
Haskell

{-# LANGUAGE LambdaCase #-}
module Parser
( module Parser
, module Control.Applicative
) where
import Control.Applicative
import Data.Char
import Debug.Trace
newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }
instance Functor Parser where
fmap f (Parser p) = Parser $ \input -> do
(value, rest) <- p input
return (f value, rest)
instance Applicative Parser where
pure a = Parser $ \input -> Just (a, input)
(Parser f) <*> (Parser g) = Parser $ \input -> do
(fn, rest) <- f input
(value, rest') <- g rest
return (fn value, rest')
instance Monad Parser where
return = pure
(Parser a) >>= f = Parser $ \input -> do
(value, rest) <- a input
let Parser b = f value
in b rest
instance Alternative Parser where
empty = Parser $ const Nothing
(Parser a) <|> (Parser b) = Parser $ \input -> a input <|> b input
instance MonadFail Parser where
fail s = Parser $ const Nothing
charP :: Char -> Parser Char
charP c = Parser $ \case
[] -> Nothing
(x : xs)
| x == c -> Just (c, xs)
| otherwise -> Nothing
stringP :: String -> Parser String
stringP = sequence . map charP
predP :: (Char -> Bool) -> Parser Char
predP pred = Parser $ \case
[] -> Nothing
(x : xs)
| pred x -> Just (x, xs)
| otherwise -> Nothing
digitP :: Parser Char
digitP = predP isDigit
numberP :: Parser Int
numberP = read <$> some digitP
letterP :: Parser Char
letterP = predP (`notElem` [':','\\', 'λ', '.', ' ', '-', '>', '*', '(', ')', '=', '\n'])
wordP :: Parser String
wordP = some letterP
spaceP :: Parser ()
spaceP = () <$ predP isSpace
notFollowedBy :: Parser a -> Parser b -> Parser a
a `notFollowedBy` b = Parser $ \input -> do
(value, rest) <- runParser a input
case runParser b rest of
Just _ -> Nothing
Nothing -> Just (value, rest)
debug :: Show a => Parser a -> Parser a
debug p = Parser $ \input -> case runParser p input of
ret@(Just (value, rest)) -> trace ("Input: " ++ input ++ "\nParsed: " ++ show value ++ "\nRest: " ++ rest ++ " (" ++ show (length rest) ++ ")") ret
Nothing -> trace ("Input: " ++ input) Nothing