|
|
- {-# LANGUAGE LambdaCase #-}
- module Parser
- ( Parser()
- , module X
- , Parser.any
- , satisfy
- , string
- , digit
- , number
- , spaces
- , reserved
- , lexeme
- , (<?>)
- , runParser
- , between ) where
-
- import Control.Applicative as X
- import Control.Monad as X
-
- import Data.Char
-
- newtype Parser a
- = Parser { parse :: String -> Either String (a, String) }
-
- runParser :: Parser a -> String -> Either String a
- runParser (Parser p) s = fst <$> p s
-
- (<?>) :: Parser a -> String -> Parser a
- p <?> err = p <|> fail err
- infixl 2 <?>
-
- instance Functor Parser where
- fn `fmap` (Parser p) = Parser go where
- go st = case p st of
- Left e -> Left e
- Right (res, str') -> Right (fn res, str')
-
- instance Applicative Parser where
- pure x = Parser $ \str -> Right (x, str)
- (Parser p) <*> (Parser p') = Parser go where
- go st = case p st of
- Left e -> Left e
- Right (fn, st') -> case p' st' of
- Left e' -> Left e'
- Right (v, st'') -> Right (fn v, st'')
-
- instance Alternative Parser where
- empty = fail "nothing"
- (Parser p) <|> (Parser p') = Parser go where
- go st = case p st of
- Left _ -> p' st
- Right x -> Right x
-
- instance Monad Parser where
- return = pure
- (Parser p) >>= f = Parser go where
- go s = case p s of
- Left e -> Left e
- Right (x, s') -> parse (f x) s'
- fail m = Parser go where
- go = Left . go'
- go' [] = "expected " ++ m ++ ", got to the end of stream"
- go' (x:xs) = "expected " ++ m ++ ", got '" ++ x:"'"
-
-
- any :: Parser Char
- any = Parser go where
- go [] = Left "any: end of file"
- go (x:xs) = Right (x,xs)
-
- satisfy :: (Char -> Bool) -> Parser Char
- satisfy f = do
- x <- Parser.any
- if f x
- then return x
- else fail "a solution to the function"
-
-
- char :: Char -> Parser Char
- char c = satisfy (c ==) <?> "literal " ++ [c]
-
- oneOf :: String -> Parser Char
- oneOf s = satisfy (`elem` s) <?> "one of '" ++ s ++ "'"
-
- string :: String -> Parser String
- string [] = return []
- string (x:xs) = do
- char x
- string xs
- return $ x:xs
-
- natural :: Parser Integer
- natural = read <$> some (satisfy isDigit)
-
- lexeme :: Parser a -> Parser a
- lexeme = (<* spaces)
-
- reserved :: String -> Parser String
- reserved = lexeme . string
-
- spaces :: Parser String
- spaces = many $ oneOf " \n\r"
-
- digit :: Parser Char
- digit = satisfy isDigit
-
- number :: Parser Int
- number = do
- s <- string "-" <|> empty
- cs <- some digit
- return $ read (s ++ cs)
-
- between :: Parser b -> Parser c -> Parser a -> Parser a
- between o c x = o *> x <* c
-
- contents :: Parser a -> Parser a
- contents x = spaces *> x <* spaces
-
- sep :: Parser b -> Parser a -> Parser [a]
- sep s c = sep1 s c <|> return []
-
- sep1 :: Parser b -> Parser a -> Parser [a]
- sep1 s c = do
- x <- c
- xs <- many $ s >> c
- return $ x:xs
-
- option :: a -> Parser a -> Parser a
- option x p = p <|> return x
-
- optionMaybe :: Parser a -> Parser (Maybe a)
- optionMaybe p = option Nothing $ Just <$> p
-
- optional :: Parser a -> Parser ()
- optional p = void p <|> return ()
-
- eof :: Parser ()
- eof = Parser go where
- go (x:_) = Left $ "expected eof, got '" ++ x:"'"
- go [] = Right ((), [])
|