```{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude #-}

-----------------------------------------------------------------------------
-- |
-- Copyright   :  (c) The University of Glasgow 2002
--
-- Maintainer  :  [email protected]
-- Stability   :  provisional
-- Portability :  non-portable (uses Text.ParserCombinators.ReadP)
--
-- This library defines parser combinators for precedence parsing.

-----------------------------------------------------------------------------

(

-- * Precedences
Prec,
minPrec,

-- * Precedence operations
lift,
prec,
step,
reset,

-- * Other operations
-- | All are based directly on their similarly-named 'ReadP' counterparts.
get,
look,
(+++),
(<++),
pfail,
choice,

-- * Converters
)
where

)

( get
, look
, (+++), (<++)
, pfail
)

import GHC.Num( Num(..) )
import GHC.Base

-- ---------------------------------------------------------------------------

-- | @since 2.01
fmap h (P f) = P (\n -> fmap h (f n))

-- | @since 4.6.0.0
pure x  = P (\_ -> pure x)
(<*>) = ap
liftA2 = liftM2

-- | @since 2.01
fail s    = P (\_ -> fail s)
P f >>= k = P (\n -> do a <- f n; let P f' = k a in f' n)

-- | @since 4.9.0.0
fail s    = P (\_ -> MonadFail.fail s)

-- | @since 2.01

-- | @since 4.6.0.0
empty = pfail
(<|>) = (+++)

-- precedences
type Prec = Int

minPrec :: Prec
minPrec = 0

-- ---------------------------------------------------------------------------

lift m = P (\_ -> m)

-- ^ Increases the precedence context by one.
step (P f) = P (\n -> f (n+1))

-- ^ Resets the precedence context to zero.
reset (P f) = P (\_ -> f minPrec)

-- ^ @(prec n p)@ checks whether the precedence context is
--   less than or equal to @[email protected], and
--
--   * if not, fails
--
--   * if so, parses @[email protected] in context @[email protected]
prec n (P f) = P (\c -> if c <= n then f n else ReadP.pfail)

-- ---------------------------------------------------------------------------
-- Derived operations

-- ^ Consumes and returns the next character.
--   Fails if there is no input left.

-- ^ Look-ahead: returns the part of the input that is left, without
--   consuming it.

-- ^ Symmetric choice.
P f1 +++ P f2 = P (\n -> f1 n ReadP.+++ f2 n)

-- ^ Local, exclusive, left-biased choice: If left parser
--   locally produces any result at all, then right parser is
--   not used.
P f1 <++ P f2 = P (\n -> f1 n ReadP.<++ f2 n)

-- ^ Always fails.

-- ^ Combines all parsers in the specified list.
choice ps = foldr (+++) pfail ps

-- ---------------------------------------------------------------------------