parcom-lib-0.1.0.0: Text/Parcom/Combinators.hs
module Text.Parcom.Combinators
( choice, namedChoice
, before, between
, many, many1, manySepBy
, times
, skip
)
where
import Text.Parcom.Core
import Text.Parcom.Internal
-- | Walk a list of options, return the first one that succeeds.
choice :: (Stream s t) => [Parcom s t a] -> Parcom s t a
choice xs = foldl (<|>) empty xs <?> "I tried to make a choice, but couldn't"
-- | Like @choice@, but each choice tagged with a human-readable name for
-- better error reporting.
namedChoice :: (Stream s t) => [(String, Parcom s t a)] -> Parcom s t a
namedChoice xs = choice (map snd xs) <?> (formatOptionList . map fst) xs
-- | Match two consecutive parser, return the first parser's result iff both
-- succeed.
before :: (Stream s t) => Parcom s t a -> Parcom s t b -> Parcom s t a
before p q = do { v <- p; q; return v }
-- | Match three consecutive parsers, return the middle parser's result iff
-- all three match. Parsers are given in the order inner, left, right.
between :: (Stream s t) => Parcom s t a -> Parcom s t l -> Parcom s t r -> Parcom s t a
between p l r = do { l; v <- p; r; return v }
-- | Match zero or more occurrences of a parser
many :: (Stream s t) => Parcom s t a -> Parcom s t [a]
many p =
handle p f m
where
f e = return []
m x = do
xs <- many p
return (x:xs)
-- | Match one or more occurrences of a parser
many1 :: (Stream s t) => Parcom s t a -> Parcom s t [a]
many1 p = do
xs <- many p
if null xs
then fail "Expected at least one item"
else return xs
-- | Given an item parser and a separator parser, keep parsing until the
-- separator or the item fails.
manySepBy :: (Stream s t) => Parcom s t a -> Parcom s t b -> Parcom s t [a]
manySepBy p s = go
where
go = do
-- try an item
handle p f m
where
-- item does not parse: return empty list (no matches)
f e = return []
-- item does parse: keep the item, try the separator.
m x = handle s
-- separator does not parse: return the one item we have
(\e -> return [x])
-- separator does parse: recurse and prepend our item
(\_ -> go >>= \xs -> return (x:xs))
-- | Run the given parser n times, returning all the results as a list.
times :: (Stream s t) => Int -> Parcom s t a -> Parcom s t [a]
times 0 p = return []
times n p = do
x <- p
xs <- times (n - 1) p
return (x:xs)
-- | Ignore the result of a parser.
skip :: Parcom s t a -> Parcom s t ()
skip p = p >> return ()