module Parsley.ParserOps (module Parsley.ParserOps) where

import Prelude hiding (pure)
import Parsley.Internal (Parser, WQ, Defunc(BLACK))

import qualified Parsley.Internal as Internal (pure, satisfy, conditional)

{-|
This typeclass is used to allow abstraction of the representation of user-level functions.
See the instances for information on what these representations are. This may be required
as a constraint on custom built combinators that make use of one of the minimal required methods
of this class.

@since 0.1.0.0
-}
class ParserOps rep where
  {-|
  Lift a value into the parser world without consuming input or having any other effect.

  @since 0.1.0.0
  -}
  pure :: rep a -> Parser a

  {-|
  Attempts to read a single character matching the provided predicate. If it succeeds, the
  character will be returned and consumed, otherwise the parser will fail having consumed no input.

  @since 0.1.0.0
  -}
  satisfy :: rep (Char -> Bool) -- ^ The predicate that a character must satisfy to be parsed
          -> Parser Char        -- ^ A parser that matches a single character matching the predicate

  {-|
  @conditional fqs p def@ first parses @p@, then it will try each of the predicates in @fqs@ in turn
  until one of them returns @True@. The corresponding parser for the first predicate that succeeded
  is then executes, or if none of the predicates succeeded then the @def@ parser is executed.

  @since 0.1.0.0
  -}
  conditional :: [(rep (a -> Bool), Parser b)] -- ^ A list of predicates and their outcomes
              -> Parser a                      -- ^ A parser whose result is used to choose an outcome
              -> Parser b                      -- ^ A parser who will be executed if no predicates succeed
              -> Parser b

{-|
This is the default representation used for user-level functions and values: plain old code.

@since 0.1.0.0
-}
instance ParserOps WQ where
  pure :: WQ a -> Parser a
pure = Defunc a -> Parser a
forall (rep :: Type -> Type) a. ParserOps rep => rep a -> Parser a
pure (Defunc a -> Parser a) -> (WQ a -> Defunc a) -> WQ a -> Parser a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WQ a -> Defunc a
forall a. WQ a -> Defunc a
BLACK
  satisfy :: WQ (Char -> Bool) -> Parser Char
satisfy = Defunc (Char -> Bool) -> Parser Char
forall (rep :: Type -> Type).
ParserOps rep =>
rep (Char -> Bool) -> Parser Char
satisfy (Defunc (Char -> Bool) -> Parser Char)
-> (WQ (Char -> Bool) -> Defunc (Char -> Bool))
-> WQ (Char -> Bool)
-> Parser Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WQ (Char -> Bool) -> Defunc (Char -> Bool)
forall a. WQ a -> Defunc a
BLACK
  conditional :: [(WQ (a -> Bool), Parser b)] -> Parser a -> Parser b -> Parser b
conditional = [(Defunc (a -> Bool), Parser b)]
-> Parser a -> Parser b -> Parser b
forall (rep :: Type -> Type) a b.
ParserOps rep =>
[(rep (a -> Bool), Parser b)] -> Parser a -> Parser b -> Parser b
conditional ([(Defunc (a -> Bool), Parser b)]
 -> Parser a -> Parser b -> Parser b)
-> ([(WQ (a -> Bool), Parser b)]
    -> [(Defunc (a -> Bool), Parser b)])
-> [(WQ (a -> Bool), Parser b)]
-> Parser a
-> Parser b
-> Parser b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((WQ (a -> Bool), Parser b) -> (Defunc (a -> Bool), Parser b))
-> [(WQ (a -> Bool), Parser b)] -> [(Defunc (a -> Bool), Parser b)]
forall a b. (a -> b) -> [a] -> [b]
map (\(WQ (a -> Bool)
f, Parser b
t) -> (WQ (a -> Bool) -> Defunc (a -> Bool)
forall a. WQ a -> Defunc a
BLACK WQ (a -> Bool)
f, Parser b
t))

{-|
This is used to allow defunctionalised versions of many standard Haskell functions to be used
directly as an argument to relevant combinators.

@since 0.1.0.0
-}
instance {-# INCOHERENT #-} x ~ Defunc => ParserOps x where
  pure :: x a -> Parser a
pure = x a -> Parser a
forall (rep :: Type -> Type) a. ParserOps rep => rep a -> Parser a
Internal.pure
  satisfy :: x (Char -> Bool) -> Parser Char
satisfy = x (Char -> Bool) -> Parser Char
forall (rep :: Type -> Type).
ParserOps rep =>
rep (Char -> Bool) -> Parser Char
Internal.satisfy
  conditional :: [(x (a -> Bool), Parser b)] -> Parser a -> Parser b -> Parser b
conditional = [(x (a -> Bool), Parser b)] -> Parser a -> Parser b -> Parser b
forall (rep :: Type -> Type) a b.
ParserOps rep =>
[(rep (a -> Bool), Parser b)] -> Parser a -> Parser b -> Parser b
Internal.conditional