content: {-# LANGUAGE PatternSynonyms, CPP #-}
  {-|
  Module      : Parsley.Applicative
  Description : The @Applicative@ combinators
  License     : BSD-3-Clause
  Maintainer  : Jamie Willis
  Stability   : stable
  
  This modules contains all of the @Applicative@ combinators that would normally be found in
  @Data.Functor@ or @Control.Applicative@. However, since Parsley makes use of staging, the signatures
  of these combinators do not correctly match the signatures of those in base Haskell.
  
  @since 0.1.0.0
  -}
  module Parsley.Applicative (
      pure, (<*>), (*>), (<*),
      fmap, (<$>), void, (<$), ($>), (<&>), constp,
      unit, (<~>), (<~), (~>),
      liftA2, liftA3,
      (<:>), (<**>),
      sequence, traverse, repeat,
      between,
      (>>)
    ) where
  
  import Prelude hiding           (pure, (<*>), (*>), (<*), (>>), (<$>), fmap, (<$), traverse, sequence, repeat
  #if __GLASGOW_HASKELL__ >= 906
    , liftA2
  #endif
    )
  import Parsley.Defunctionalized (Defunc(CONS, CONST, ID, EMPTY), pattern FLIP_H, pattern UNIT)
  import Parsley.Internal         (makeQ, Parser)
  import Parsley.ParserOps        (ParserOps, pure)
  
  import qualified Parsley.Internal as Internal ((<*>), (*>), (<*))
  
  -- Applicative Operations
  {-|
  Sequential application of one parser's result to another's. The parsers must both succeed, one after
  the other to combine their results. If either parser fails then the combinator will fail.
  
  @since 0.1.0.0
  -}
  infixl 4 <*>
  (<*>) :: Parser (a -> b) -> Parser a -> Parser b
  (<*>) = (Internal.<*>)
  
  {-|
  Sequence two parsers, keeping the result of the second and discarding the result of the first.
  
  @since 0.1.0.0
  -}
  infixl 4 <*
  (<*) :: Parser a -> Parser b -> Parser a
  (<*) = (Internal.<*)
  
  {-|
  Sequence two parsers, keeping the result of the first and discarding the result of the second.
  
  @since 0.1.0.0
  -}
  infixl 4 *>
  (*>) :: Parser a -> Parser b -> Parser b
  (*>) = (Internal.*>)
  
  -- Functor Operations
  {-|
  Maps a function over the result of a parser.
  
  @since 0.1.0.0
  -}
  fmap :: ParserOps rep => rep (a -> b) -> Parser a -> Parser b
  fmap f = (pure f <*>)
  
  {-|
  Alias of `fmap`.
  
  @since 0.1.0.0
  -}
  infixl 4 <$>
  (<$>) :: ParserOps rep => rep (a -> b) -> Parser a -> Parser b
  (<$>) = fmap
  
  {-|
  This combinator \"forgets\" the result of a parser, and replaces it with @()@.
  
  @since 0.1.0.0
  -}
  void :: Parser a -> Parser ()
  void p = p $> UNIT
  
  {-|
  This combinator \"forgets\" the result of a parser, and replaces it the given value.
  
  @since 0.1.0.0
  -}
  infixl 4 <$
  (<$) :: ParserOps rep => rep b -> Parser a -> Parser b
  x <$ p = p *> pure x
  
  {-|
  This combinator \"forgets\" the result of a parser, and replaces it the given value.
  
  @since 0.1.0.0
  -}
  infixl 4 $>
  ($>) :: ParserOps rep => Parser a -> rep b -> Parser b
  ($>) = flip (<$)
  
  {-|
  Maps a function over the result of a parser.
  
  @since 0.1.0.0
  -}
  infixl 4 <&>
  (<&>) :: ParserOps rep => Parser a -> rep (a -> b) -> Parser b
  (<&>) = flip fmap
  
  -- | @since 0.1.0.0
  constp :: Parser a -> Parser (b -> a)
  constp = (CONST <$>)
  
  -- Alias Operations
  {-|
  Alias of @(`*>`)@
  
  @since 0.1.0.0
  -}
  infixl 1 >>
  (>>) :: Parser a -> Parser b -> Parser b
  (>>) = (*>)
  
  -- Monoidal Operations
  {-|
  This parser always returns @()@ without consuming input.
  
  @since 0.1.0.0
  -}
  unit :: Parser ()
  unit = pure UNIT
  
  {-|
  Sequential zipping of one parser's result with another's. The parsers must both succeed, one after
  the other to pair their results. If either parser fails then the combinator will fail.
  
  @since 0.1.0.0
  -}
  infixl 4 <~>
  (<~>) :: Parser a -> Parser b -> Parser (a, b)
  (<~>) = liftA2 (makeQ (,) [||(,)||])
  
  {-|
  Alias of @(`<*`)@
  
  @since 0.1.0.0
  -}
  infixl 4 <~
  (<~) :: Parser a -> Parser b -> Parser a
  (<~) = (<*)
  
  {-|
  Alias of @(`*>`)@
  
  @since 0.1.0.0
  -}
  infixl 4 ~>
  (~>) :: Parser a -> Parser b -> Parser b
  (~>) = (*>)
  
  -- Lift Operations
  {-|
  Sequential combination of two parsers results. The results are combined using the given function.
  
  @since 0.1.0.0
  -}
  liftA2 :: ParserOps rep => rep (a -> b -> c) -> Parser a -> Parser b -> Parser c
  liftA2 f p q = f <$> p <*> q
  
  {-|
  Sequential combination of three parsers results. The results are combined using the given function.
  
  @since 0.1.0.0
  -}
  liftA3 :: ParserOps rep => rep (a -> b -> c -> d) -> Parser a -> Parser b -> Parser c -> Parser d
  liftA3 f p q r = f <$> p <*> q <*> r
  
  {-|
  Sequential consing of one parser's result with another's. The parsers must both succeed, one after
  the other to combine their results. If either parser fails then the combinator will fail.
  
  @since 0.1.0.0
  -}
  infixl 4 <:>
  (<:>) :: Parser a -> Parser [a] -> Parser [a]
  (<:>) = liftA2 CONS
  
  {-|
  A variant of @(`<*>`)@ with the arguments reversed.
  
  @since 0.1.0.0
  -}
  infixl 4 <**>
  (<**>) :: Parser a -> Parser (a -> b) -> Parser b
  (<**>) = liftA2 (FLIP_H ID)
  
  -- Auxillary functions
  {-|
  Given a list of parsers, `sequence` will parse each in turn and collect all their results into a
  list. All the parsers in the list must succeed.
  
  @since 0.1.0.0
  -}
  sequence :: [Parser a] -> Parser [a]
  sequence = foldr (<:>) (pure EMPTY)
  
  {-|
  Like `sequence`, but the parsers to sequence are generated from seed values using a given generator
  function.
  
  @since 0.1.0.0
  -}
  traverse :: (a -> Parser b) -> [a] -> Parser [b]
  traverse f = sequence . map f
  
  {-|
  The combinator @repeat n p@ will attempt to parse @p@ exactly @n@ times. That is not to say that
  the parser must fail on the @n+1@th try, but there must be @n@ successes for the combinator to
  succeed. All the results generated from @p@ will be collected into a list.
  
  @since 0.1.0.0
  -}
  repeat :: Int -> Parser a -> Parser [a]
  repeat n = sequence . replicate n
  
  {-|
  The combinator @between open close p@ will first parse @open@ then @p@ and then @close@, yielding
  the result given by @p@.
  
  @since 0.1.0.0
  -}
  between :: Parser o -> Parser c -> Parser a -> Parser a
  between open close p = open *> p <* close
  