parsley-1.0.0.3: src/ghc/Parsley/Alternative.hs
{-# 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