gigaparsec-0.2.2.0: src/Text/Gigaparsec/Registers.hs
{-# LANGUAGE Trustworthy #-}
module Text.Gigaparsec.Registers (
Reg,
make, unsafeMake,
get, gets,
put, puts,
modify,
local, localWith,
rollback
) where
import Text.Gigaparsec (Parsec, (<|>), empty)
import Text.Gigaparsec.Internal.RT (Reg, newReg, readReg, writeReg)
import Text.Gigaparsec.Internal qualified as Internal (Parsec(..))
unsafeMake :: (forall r. Reg r a -> Parsec b) -> Parsec b
unsafeMake = make (error "reference used but not set")
_make :: Parsec a -> (forall r. Reg r a -> Parsec b) -> Parsec b
_make p f = p >>= \x -> make x f
make :: a -> (forall r. Reg r a -> Parsec b) -> Parsec b
make x f = Internal.Parsec $ \st good bad ->
newReg x $ \reg ->
let Internal.Parsec p = f reg
in p st good bad
get :: Reg r a -> Parsec a
get reg = Internal.Parsec $ \st good _ ->
do x <- readReg reg
good x st
-- parsley provides multiple overloadings...
_gets :: Reg r a -> Parsec (a -> b) -> Parsec b
_gets reg pf = pf <*> get reg
gets :: Reg r a -> (a -> b) -> Parsec b
gets reg f = f <$> get reg
_put :: Reg r a -> Parsec a -> Parsec ()
_put reg px = px >>= put reg
put :: Reg r a -> a -> Parsec ()
put reg x = Internal.Parsec $ \st good _ ->
do writeReg reg x
good () st
puts :: Reg r b -> (a -> b) -> Parsec a -> Parsec ()
puts reg f px = _put reg (f <$> px)
_modify :: Reg r a -> Parsec (a -> a) -> Parsec ()
_modify reg pf = _put reg (_gets reg pf)
modify :: Reg r a -> (a -> a) -> Parsec ()
modify reg f = _put reg (gets reg f)
local :: Reg r a -> (a -> a) -> Parsec b -> Parsec b
local reg f p = do x <- get reg
put reg (f x)
p <* put reg x
localWith :: Reg r a -> a -> Parsec b -> Parsec b
localWith reg x = local reg (const x)
_localWith :: Reg r a -> Parsec a -> Parsec b -> Parsec b
_localWith reg px q = px >>= flip (localWith reg) q
rollback :: Reg r a -> Parsec a -> Parsec a
rollback reg p = get reg >>= \x -> p <|> (put reg x *> empty)
-- TODO: for combinators