bookhound-0.1.0.0: src/ParserCombinators.hs
{-# LANGUAGE FlexibleInstances, IncoherentInstances, PostfixOperators #-}
module ParserCombinators where
import Parser (Parser, char, isMatch, check, anyOf, allOf, except)
import Utils.Foldable (hasSome, hasMany)
import Utils.String (ToString(..))
import Utils.Applicative (extract)
import Data.Maybe (listToMaybe, maybeToList)
import Data.List (isInfixOf)
class IsMatch a where
is :: a -> Parser a
isNot :: a -> Parser a
oneOf :: [a] -> Parser a
noneOf :: [a] -> Parser a
inverse :: Parser a -> Parser a
oneOf xs = anyOf $ is <$> xs
noneOf xs = allOf $ isNot <$> xs
instance IsMatch Char where
is = isMatch (==) char
isNot = isMatch (/=) char
inverse = except char
instance IsMatch String where
is = traverse is
isNot = traverse isNot
inverse = except (char |*)
instance IsMatch Integer where
is n = read <$> (is . show) n
isNot n = read <$> (isNot . show) n
inverse p = read <$> inverse (show <$> p)
instance IsMatch Int where
is n = read <$> (is . show) n
isNot n = read <$> (isNot . show) n
inverse p = read <$> inverse (show <$> p)
instance IsMatch Double where
is n = read <$> (is . show) n
isNot n = read <$> (isNot . show) n
inverse p = read <$> inverse (show <$> p)
-- Condition combinators
satisfies :: Parser a -> (a -> Bool) -> Parser a
satisfies parser cond = check "satisfies" cond parser
contains :: Eq a => Parser [a] -> [a] -> Parser [a]
contains p str = check "contains" (isInfixOf str) p
notContains :: Eq a => Parser [a] -> [a] -> Parser [a]
notContains p str = check "notContains" (isInfixOf str) p
-- Frequency combinators
times :: Parser a -> Integer -> Parser [a]
times parser n = sequence $ parser <$ [1 .. n]
maybeTimes :: Parser a -> Parser (Maybe a)
maybeTimes = (listToMaybe <$>) . check "maybeTimes" (not . hasMany) . anyTimes
anyTimes :: Parser a -> Parser [a]
anyTimes parser = (parser >>= \x -> (x :) <$> anyTimes parser) <|> pure []
someTimes :: Parser a -> Parser [a]
someTimes = check "someTimes" hasSome . anyTimes
manyTimes :: Parser a -> Parser [a]
manyTimes = check "manyTimes" hasMany . anyTimes
-- Within combinators
within :: Parser a -> Parser b -> Parser b
within p = extract p p
maybeWithin :: Parser a -> Parser b -> Parser b
maybeWithin p = within (p |?)
withinBoth :: Parser a -> Parser b -> Parser c -> Parser c
withinBoth = extract
maybeWithinBoth :: Parser a -> Parser b -> Parser c -> Parser c
maybeWithinBoth p1 p2 = extract (p1 |?) (p2 |?)
-- Parser Binary Operators
(<|>) :: Parser a -> Parser a -> Parser a
(<|>) p1 p2 = anyOf [p1, p2]
(<&>) :: Parser a -> Parser a -> Parser a
(<&>) p1 p2 = allOf [p1, p2]
(<#>) :: Parser a -> Integer -> Parser [a]
(<#>) = times
(>>>) :: (ToString a, ToString b) => Parser a -> Parser b -> Parser String
(>>>) p1 p2 = p1 >>= (\x -> (x ++) <$> (toString <$> p2)) . toString
-- Parser Unary Operators
(|?) :: Parser a -> Parser (Maybe a)
(|?) = maybeTimes
(|*) :: Parser a -> Parser [a]
(|*) = anyTimes
(|+) :: Parser a -> Parser [a]
(|+) = someTimes
(|++) :: Parser a -> Parser [a]
(|++) = manyTimes