content: {-# LANGUAGE PatternSynonyms #-}
  {-|
  Module      : Parsley.Alterative
  Description : The @Alternative@ combinators
  License     : BSD-3-Clause
  Maintainer  : Jamie Willis
  Stability   : stable
  
  This modules contains the @Alternative@ combinators that would normally be found in
  @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 (due to a lack
  of @Applicative@ constraint).
  
  @since 0.1.0.0
  -}
  module Parsley.Alternative (
      (<|>), empty,
      (<+>), option, optionally, optional, choice, maybeP, manyTill
    ) where
  
  import Prelude hiding           (pure, (<$>))
  import Parsley.Applicative      (pure, (<$>), ($>), (<:>))
  import Parsley.Defunctionalized (Defunc(EMPTY), pattern UNIT)
  import Parsley.Internal         (makeQ, Parser)
  import Parsley.ParserOps        (ParserOps)
  
  import qualified Parsley.Internal as Internal ((<|>), empty)
  
  {-|
  This combinator always fails.
  
  @since 0.1.0.0
  -}
  empty :: Parser a
  empty = Internal.empty
  
  {-|
  This combinator implements branching within a parser. It is left-biased, so that if the first branch
  succeeds, the second will not be attempted. In accordance with @parsec@ semantics, if the first
  branch failed having consumed input the second branch cannot be taken. (see `Parsley.Combinator.try`)
  
  @since 0.1.0.0
  -}
  infixr 3 <|>
  (<|>) :: Parser a -> Parser a -> Parser a
  (<|>) = (Internal.<|>)
  
  {-|
  This combinator is similar to @(`<|>`)@, except it allows both branches to differ in type by
  producing a co-product as a result.
  
  @since 0.1.0.0
  -}
  infixl 3 <+>
  (<+>) :: Parser a -> Parser b -> Parser (Either a b)
  p <+> q = makeQ Left [||Left||] <$> p <|> makeQ Right [||Right||] <$> q
  
  {-|
  @option x p@ first tries to parse @p@ and, if it fails without consuming input, will return
  @x@ as a result.
  
  @since 0.1.0.0
  -}
  option :: ParserOps rep => rep a -> Parser a -> Parser a
  option x p = p <|> pure x
  
  {-|
  @optionally p x@ will try to parse @p@ and will always return @x@. If @p@ fails having consumed
  input, then this combinator will fail.
  
  @since 0.1.0.0
  -}
  optionally :: ParserOps rep => Parser a -> rep b -> Parser b
  optionally p x = option x (p $> x)
  
  {-|
  Attempts to parse a given parser, and will always return @()@. (See `optionally`)
  
  @since 0.1.0.0
  -}
  optional :: Parser a -> Parser ()
  optional = flip optionally UNIT
  
  {-|
  Tries to parse each of the given parsers in turn until one of them succeeds using @(`<|>`)@. If
  given the empty list, it will fail unconditionally.
  
  @since 0.1.0.0
  -}
  choice :: [Parser a] -> Parser a
  choice = foldr (<|>) empty
  
  {-|
  Tries to parse a given parser, returning its result in @Just@ if it succeeds and @Nothing@ if it
  fails having not consumed input.
  
  @since 0.1.0.0
  -}
  maybeP :: Parser a -> Parser (Maybe a)
  maybeP p = option (makeQ Nothing [||Nothing||]) (makeQ Just [||Just||] <$> p)
  
  {-|
  The combinator @someTill p end@ will try and parse @p@ as many times as possible so long as @end@
  cannot be successfully parsed. It will return the results from the successful parses of @p@.
  
  @since 0.1.0.0
  -}
  manyTill :: Parser a -> Parser b -> Parser [a]
  manyTill p end = let go = end $> EMPTY <|> p <:> go in go
  