module Text.Parsec.Extra
(
eol
, digit
, natural
, integer
, caseInsensitiveChar
, caseInsensitiveString
, parseM
) where
import Control.Applicative (Applicative,(<$>),(<*>),(<*),(*>),pure)
import Control.Monad.Error (Error,ErrorType,MonadError,throwError)
import Control.Monad.Trans.Error (noMsg,strMsg)
import Data.Char (toLower,toUpper)
import Data.List (foldl')
import Text.ParserCombinators.Parsec.Prim (GenParser,(<|>),(<?>),parse)
import Text.ParserCombinators.Parsec.Combinator (many1,option)
import qualified Text.ParserCombinators.Parsec.Char as Char
import Text.ParserCombinators.Parsec.Char (char)
eol :: GenParser Char state ()
eol = (char '\n' <|> (char '\r' >> option '\n' (char '\n'))) >> return ()
digit :: (Integral a) => GenParser Char state a
digit = fromIntegral . (\ c -> fromEnum c fromEnum '0') <$> Char.digit
natural :: (Integral a) => GenParser Char state a
natural = (foldl' (\ a b -> a * 10 + b) 0 <$> many1 digit) <?> "nonnegative decimal integer"
integer :: (Integral a) => GenParser Char state a
integer = (option id (char '-' *> pure negate) <*> natural) <?> "decimal integer"
caseInsensitiveChar :: Char -> GenParser Char state Char
caseInsensitiveChar c = do
char (toLower c) <|> char (toUpper c)
return c
caseInsensitiveString :: String -> GenParser Char state String
caseInsensitiveString = sequence . map caseInsensitiveChar
parseM :: (MonadError m,Error (ErrorType m)) => GenParser t () a -> String -> [t] -> m a
parseM p s = either (throwError . strMsg . show) return . parse p s