{-# 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 :: forall a. Parser a
empty = forall a. Parser a
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
<|> :: forall a. Parser a -> Parser a -> Parser a
(<|>) = forall a. 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)
Parser a
p <+> :: forall a b. Parser a -> Parser b -> Parser (Either a b)
<+> Parser b
q = forall (q :: Type -> Type) a. Quapplicative q => a -> Code a -> q a
makeQ forall a b. a -> Either a b
Left [||Left||] forall (rep :: Type -> Type) a b.
ParserOps rep =>
rep (a -> b) -> Parser a -> Parser b
<$> Parser a
p forall a. Parser a -> Parser a -> Parser a
<|> forall (q :: Type -> Type) a. Quapplicative q => a -> Code a -> q a
makeQ forall a b. b -> Either a b
Right [||Right||] forall (rep :: Type -> Type) a b.
ParserOps rep =>
rep (a -> b) -> Parser a -> Parser b
<$> Parser b
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 :: forall (rep :: Type -> Type) a.
ParserOps rep =>
rep a -> Parser a -> Parser a
option rep a
x Parser a
p = Parser a
p forall a. Parser a -> Parser a -> Parser a
<|> forall (rep :: Type -> Type) a. ParserOps rep => rep a -> Parser a
pure rep a
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 :: forall (rep :: Type -> Type) a b.
ParserOps rep =>
Parser a -> rep b -> Parser b
optionally Parser a
p rep b
x = forall (rep :: Type -> Type) a.
ParserOps rep =>
rep a -> Parser a -> Parser a
option rep b
x (Parser a
p forall (rep :: Type -> Type) a b.
ParserOps rep =>
Parser a -> rep b -> Parser b
$> rep b
x)

{-|
Attempts to parse a given parser, and will always return @()@. (See `optionally`)

@since 0.1.0.0
-}
optional :: Parser a -> Parser ()
optional :: forall a. Parser a -> Parser ()
optional = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (rep :: Type -> Type) a b.
ParserOps rep =>
Parser a -> rep b -> Parser b
optionally Defunc ()
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 :: forall a. [Parser a] -> Parser a
choice = forall (t :: Type -> Type) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall a. Parser a -> Parser a -> Parser a
(<|>) forall a. Parser a
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 :: forall a. Parser a -> Parser (Maybe a)
maybeP Parser a
p = forall (rep :: Type -> Type) a.
ParserOps rep =>
rep a -> Parser a -> Parser a
option (forall (q :: Type -> Type) a. Quapplicative q => a -> Code a -> q a
makeQ forall a. Maybe a
Nothing [||Nothing||]) (forall (q :: Type -> Type) a. Quapplicative q => a -> Code a -> q a
makeQ forall a. a -> Maybe a
Just [||Just||] forall (rep :: Type -> Type) a b.
ParserOps rep =>
rep (a -> b) -> Parser a -> Parser b
<$> Parser a
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 :: forall a b. Parser a -> Parser b -> Parser [a]
manyTill Parser a
p Parser b
end = let go :: Parser [a]
go = Parser b
end forall (rep :: Type -> Type) a b.
ParserOps rep =>
Parser a -> rep b -> Parser b
$> forall a1. Defunc [a1]
EMPTY forall a. Parser a -> Parser a -> Parser a
<|> Parser a
p forall a. Parser a -> Parser [a] -> Parser [a]
<:> Parser [a]
go in Parser [a]
go