    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Text.ParserCombinators.Parsec.Combinator
    -- Copyright   :  (c) Daan Leijen 1999-2001
    -- License     :  BSD-style (see the file libraries/parsec/LICENSE)
    --
    -- Maintainer  :  daan@cs.uu.nl
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- Commonly used generic combinators
    --
    -----------------------------------------------------------------------------

    module Text.ParserCombinators.Parsec.Combinator
                            ( choice
                            , count
                            , between
                            , option, optionMaybe, optional
                            , skipMany1
                            , many1
                            , sepBy, sepBy1
                            , endBy, endBy1
                            , sepEndBy, sepEndBy1
                            , chainl, chainl1
                            , chainr, chainr1
                            , eof, notFollowedBy

                            -- tricky combinators
                            , manyTill, lookAhead, anyToken
                            ) where

    import Control.Monad
    import Text.ParserCombinators.Parsec.Prim

    ----------------------------------------------------------------
    --
    ----------------------------------------------------------------
    choice :: [GenParser tok st a] -> GenParser tok st a
    choice ps           = foldr (<|>) mzero ps

    option :: a -> GenParser tok st a -> GenParser tok st a
    option x p          = p <|> return x

    optionMaybe :: GenParser tok st a -> GenParser tok st (Maybe a)
    optionMaybe p       = option Nothing (liftM Just p)

    optional :: GenParser tok st a -> GenParser tok st ()
    optional p          = do{ p; return ()} <|> return ()

    between :: GenParser tok st open -> GenParser tok st close
                -> GenParser tok st a -> GenParser tok st a
    between open close p
                        = do{ open; x <- p; close; return x }

    skipMany1 :: GenParser tok st a -> GenParser tok st ()
    skipMany1 p         = do{ p; skipMany p }
    {-
    skipMany p          = scan
                        where
                          scan  = do{ p; scan } <|> return ()
    -}

    many1 :: GenParser tok st a -> GenParser tok st [a]
    many1 p             = do{ x <- p; xs <- many p; return (x:xs) }
    {-
    many p              = scan id
                        where
                          scan f    = do{ x <- p
                                        ; scan (\tail -> f (x:tail))
                                        }
                                    <|> return (f [])
    -}

    sepBy1,sepBy :: GenParser tok st a -> GenParser tok st sep -> GenParser tok st [a]
    sepBy p sep         = sepBy1 p sep <|> return []
    sepBy1 p sep        = do{ x <- p
                            ; xs <- many (sep >> p)
                            ; return (x:xs)
                            }

    sepEndBy1, sepEndBy :: GenParser tok st a -> GenParser tok st sep -> GenParser tok st [a]
    sepEndBy1 p sep     = do{ x <- p
                            ; do{ sep
                                ; xs <- sepEndBy p sep
                                ; return (x:xs)
                                }
                              <|> return [x]
                            }

    sepEndBy p sep      = sepEndBy1 p sep <|> return []

    endBy1,endBy :: GenParser tok st a -> GenParser tok st sep -> GenParser tok st [a]
    endBy1 p sep        = many1 (do{ x <- p; sep; return x })
    endBy p sep         = many (do{ x <- p; sep; return x })

    count :: Int -> GenParser tok st a -> GenParser tok st [a]
    count n p           | n <= 0    = return []
                        | otherwise = sequence (replicate n p)

    chainr,chainl :: GenParser tok st a -> GenParser tok st (a -> a -> a) -> a -> GenParser tok st a
    chainr p op x       = chainr1 p op <|> return x
    chainl p op x       = chainl1 p op <|> return x

    chainr1,chainl1 :: GenParser tok st a -> GenParser tok st (a -> a -> a) -> GenParser tok st a
    chainl1 p op        = do{ x <- p; rest x }
                        where
                          rest x    = do{ f <- op
                                        ; y <- p
                                        ; rest (f x y)
                                        }
                                    <|> return x

    chainr1 p op        = scan
                        where
                          scan      = do{ x <- p; rest x }

                          rest x    = do{ f <- op
                                        ; y <- scan
                                        ; return (f x y)
                                        }
                                    <|> return x

    -----------------------------------------------------------
    -- Tricky combinators
    -----------------------------------------------------------
    anyToken :: Show tok => GenParser tok st tok
    anyToken            = tokenPrim show (\pos tok toks -> pos) Just

    eof :: Show tok => GenParser tok st ()
    eof                 = notFollowedBy anyToken <?> "end of input"

    notFollowedBy :: Show tok => GenParser tok st tok -> GenParser tok st ()
    notFollowedBy p     = try (do{ c <- p; unexpected (show [c]) }
                               <|> return ()
                              )

    manyTill :: GenParser tok st a -> GenParser tok st end -> GenParser tok st [a]
    manyTill p end      = scan
                        where
                          scan  = do{ end; return [] }
                                <|>
                                  do{ x <- p; xs <- scan; return (x:xs) }

    lookAhead :: GenParser tok st a -> GenParser tok st a
    lookAhead p         = do{ state <- getParserState
                            ; x <- p
                            ; setParserState state
                            ; return x
                            }