{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE LambdaCase            #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE TypeSynonymInstances  #-}

module Evaluation.Debug
    ( test_debug
    ) where

import PlutusCore.Evaluation.Machine.ExBudgetingDefaults
import PlutusCore.Pretty
import PlutusPrelude
import UntypedPlutusCore
import UntypedPlutusCore.Evaluation.Machine.SteppableCek.DebugDriver
import UntypedPlutusCore.Evaluation.Machine.SteppableCek.Internal

import Control.Monad.Reader
import Control.Monad.ST
import Control.Monad.Writer
import Data.ByteString.Lazy.Char8 qualified as BS
import Data.Text qualified as T
import Data.Void
import Prettyprinter
import Test.Tasty
import Test.Tasty.Golden
import UntypedPlutusCore.Evaluation.Machine.Cek

test_debug :: TestTree
test_debug :: TestTree
test_debug = [Char] -> [TestTree] -> TestTree
testGroup [Char]
"debug" ([TestTree] -> TestTree) -> [TestTree] -> TestTree
forall a b. (a -> b) -> a -> b
$
    (([Char], [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn)
 -> TestTree)
-> [([Char], [Cmd Breakpoints],
     NTerm DefaultUni DefaultFun EmptyAnn)]
-> [TestTree]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Char], [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn)
-> TestTree
goldenVsDebug [([Char], [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn)]
examples

-- i am not testing breakpoint functionality at the moment
type Breakpoints = Void
newtype EmptyAnn = EmptyAnn ()
    deriving newtype (NonEmpty EmptyAnn -> EmptyAnn
EmptyAnn -> EmptyAnn -> EmptyAnn
(EmptyAnn -> EmptyAnn -> EmptyAnn)
-> (NonEmpty EmptyAnn -> EmptyAnn)
-> (forall b. Integral b => b -> EmptyAnn -> EmptyAnn)
-> Semigroup EmptyAnn
forall b. Integral b => b -> EmptyAnn -> EmptyAnn
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: EmptyAnn -> EmptyAnn -> EmptyAnn
<> :: EmptyAnn -> EmptyAnn -> EmptyAnn
$csconcat :: NonEmpty EmptyAnn -> EmptyAnn
sconcat :: NonEmpty EmptyAnn -> EmptyAnn
$cstimes :: forall b. Integral b => b -> EmptyAnn -> EmptyAnn
stimes :: forall b. Integral b => b -> EmptyAnn -> EmptyAnn
Semigroup, Semigroup EmptyAnn
EmptyAnn
Semigroup EmptyAnn =>
EmptyAnn
-> (EmptyAnn -> EmptyAnn -> EmptyAnn)
-> ([EmptyAnn] -> EmptyAnn)
-> Monoid EmptyAnn
[EmptyAnn] -> EmptyAnn
EmptyAnn -> EmptyAnn -> EmptyAnn
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
$cmempty :: EmptyAnn
mempty :: EmptyAnn
$cmappend :: EmptyAnn -> EmptyAnn -> EmptyAnn
mappend :: EmptyAnn -> EmptyAnn -> EmptyAnn
$cmconcat :: [EmptyAnn] -> EmptyAnn
mconcat :: [EmptyAnn] -> EmptyAnn
Monoid)
instance Breakpointable EmptyAnn Breakpoints where
    hasBreakpoints :: EmptyAnn -> Breakpoints -> Bool
hasBreakpoints EmptyAnn
_ = Breakpoints -> Bool
forall a. Breakpoints -> a
absurd

examples :: [(String, [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn)]
examples :: [([Char], [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn)]
examples = [
             ([Char]
"ex1", Cmd Breakpoints -> [Cmd Breakpoints]
forall a. a -> [a]
repeat Cmd Breakpoints
forall bps. Cmd bps
Step, EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann.
ann -> Term name uni fun ann -> Term name uni fun ann
Delay EmptyAnn
forall a. Monoid a => a
mempty (NTerm DefaultUni DefaultFun EmptyAnn
 -> NTerm DefaultUni DefaultFun EmptyAnn)
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall a b. (a -> b) -> a -> b
$ EmptyAnn -> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann. ann -> Term name uni fun ann
Error EmptyAnn
forall a. Monoid a => a
mempty)
           , ([Char]
"ex2", Int -> Cmd Breakpoints -> [Cmd Breakpoints]
forall a. Int -> a -> [a]
replicate Int
4 Cmd Breakpoints
forall bps. Cmd bps
Step, EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann.
ann -> Term name uni fun ann -> Term name uni fun ann
Force EmptyAnn
forall a. Monoid a => a
mempty (NTerm DefaultUni DefaultFun EmptyAnn
 -> NTerm DefaultUni DefaultFun EmptyAnn)
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall a b. (a -> b) -> a -> b
$ EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann.
ann -> Term name uni fun ann -> Term name uni fun ann
Delay EmptyAnn
forall a. Monoid a => a
mempty (NTerm DefaultUni DefaultFun EmptyAnn
 -> NTerm DefaultUni DefaultFun EmptyAnn)
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall a b. (a -> b) -> a -> b
$ EmptyAnn -> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann. ann -> Term name uni fun ann
Error EmptyAnn
forall a. Monoid a => a
mempty)
           , ([Char]
"ex3", Int -> Cmd Breakpoints -> [Cmd Breakpoints]
forall a. Int -> a -> [a]
replicate Int
5 Cmd Breakpoints
forall bps. Cmd bps
Step, EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann.
ann -> Term name uni fun ann -> Term name uni fun ann
Force EmptyAnn
forall a. Monoid a => a
mempty (NTerm DefaultUni DefaultFun EmptyAnn
 -> NTerm DefaultUni DefaultFun EmptyAnn)
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall a b. (a -> b) -> a -> b
$ EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann.
ann -> Term name uni fun ann -> Term name uni fun ann
Delay EmptyAnn
forall a. Monoid a => a
mempty (NTerm DefaultUni DefaultFun EmptyAnn
 -> NTerm DefaultUni DefaultFun EmptyAnn)
-> NTerm DefaultUni DefaultFun EmptyAnn
-> NTerm DefaultUni DefaultFun EmptyAnn
forall a b. (a -> b) -> a -> b
$ EmptyAnn -> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann. ann -> Term name uni fun ann
Error EmptyAnn
forall a. Monoid a => a
mempty)
           , ([Char]
"ex4", Cmd Breakpoints -> [Cmd Breakpoints]
forall a. a -> [a]
repeat Cmd Breakpoints
forall bps. Cmd bps
Step, EmptyAnn -> NTerm DefaultUni DefaultFun EmptyAnn
forall name (uni :: * -> *) fun ann. ann -> Term name uni fun ann
Error EmptyAnn
forall a. Monoid a => a
mempty)
           ]

goldenVsDebug :: (TestName, [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn) -> TestTree
goldenVsDebug :: ([Char], [Cmd Breakpoints], NTerm DefaultUni DefaultFun EmptyAnn)
-> TestTree
goldenVsDebug ([Char]
name, [Cmd Breakpoints]
cmds, NTerm DefaultUni DefaultFun EmptyAnn
term) =
    [Char] -> [Char] -> IO ByteString -> TestTree
goldenVsString [Char]
name
    ([Char]
"untyped-plutus-core/test/Evaluation/Debug/" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
name [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".golden")
    (ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> IO ByteString) -> ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ [Char] -> ByteString
BS.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Cmd Breakpoints]
-> NTerm DefaultUni DefaultFun EmptyAnn -> [[Char]]
mock [Cmd Breakpoints]
cmds NTerm DefaultUni DefaultFun EmptyAnn
term)

-- A Mocking interpreter

mock :: [Cmd Breakpoints] -- ^ commands to feed
     -> NTerm DefaultUni DefaultFun EmptyAnn -- ^ term to debug
     -> [String] -- ^ mocking output
mock :: [Cmd Breakpoints]
-> NTerm DefaultUni DefaultFun EmptyAnn -> [[Char]]
mock [Cmd Breakpoints]
cmds NTerm DefaultUni DefaultFun EmptyAnn
t = (forall s. ST s [[Char]]) -> [[Char]]
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s [[Char]]) -> [[Char]])
-> (forall s. ST s [[Char]]) -> [[Char]]
forall a b. (a -> b) -> a -> b
$ CekM Any Any s [[Char]] -> ST s [[Char]]
forall (uni :: * -> *) fun s a. CekM uni fun s a -> ST s a
unCekM (CekM Any Any s [[Char]] -> ST s [[Char]])
-> CekM Any Any s [[Char]] -> ST s [[Char]]
forall a b. (a -> b) -> a -> b
$ do
    (CekTrans DefaultUni DefaultFun EmptyAnn s
cekTrans,ExBudgetInfo RestrictingSt DefaultUni DefaultFun s
_) <- MachineParameters
  CekMachineCosts
  DefaultFun
  (CekValue DefaultUni DefaultFun EmptyAnn)
-> ExBudgetMode RestrictingSt DefaultUni DefaultFun
-> EmitterMode DefaultUni DefaultFun
-> Slippage
-> CekM
     Any
     Any
     s
     (CekTrans DefaultUni DefaultFun EmptyAnn s,
      ExBudgetInfo RestrictingSt DefaultUni DefaultFun s)
forall cost (uni :: * -> *) fun ann (m :: * -> *) s.
(ThrowableBuiltins uni fun, PrimMonad m, s ~ PrimState m) =>
MachineParameters CekMachineCosts fun (CekValue uni fun ann)
-> ExBudgetMode cost uni fun
-> EmitterMode uni fun
-> Slippage
-> m (CekTrans uni fun ann s, ExBudgetInfo cost uni fun s)
mkCekTrans MachineParameters
  CekMachineCosts
  DefaultFun
  (CekValue DefaultUni DefaultFun EmptyAnn)
forall ann.
Typeable ann =>
MachineParameters
  CekMachineCosts DefaultFun (CekValue DefaultUni DefaultFun ann)
defaultCekParametersForTesting
                    ExBudgetMode RestrictingSt DefaultUni DefaultFun
forall (uni :: * -> *) fun.
ThrowableBuiltins uni fun =>
ExBudgetMode RestrictingSt uni fun
restrictingEnormous EmitterMode DefaultUni DefaultFun
forall (uni :: * -> *) fun. EmitterMode uni fun
noEmitter Slippage
defaultSlippage
    WriterT [[Char]] (CekM Any Any s) () -> CekM Any Any s [[Char]]
forall (m :: * -> *) w a. Monad m => WriterT w m a -> m w
execWriterT (WriterT [[Char]] (CekM Any Any s) () -> CekM Any Any s [[Char]])
-> WriterT [[Char]] (CekM Any Any s) () -> CekM Any Any s [[Char]]
forall a b. (a -> b) -> a -> b
$ (ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
 -> [Cmd Breakpoints] -> WriterT [[Char]] (CekM Any Any s) ())
-> [Cmd Breakpoints]
-> ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
-> WriterT [[Char]] (CekM Any Any s) ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
-> [Cmd Breakpoints] -> WriterT [[Char]] (CekM Any Any s) ()
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT [Cmd Breakpoints]
cmds (ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
 -> WriterT [[Char]] (CekM Any Any s) ())
-> ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
-> WriterT [[Char]] (CekM Any Any s) ()
forall a b. (a -> b) -> a -> b
$
        -- MAYBE: use cutoff or partialIterT to prevent runaway
        (DebugF
   DefaultUni
   DefaultFun
   EmptyAnn
   Breakpoints
   (ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ())
 -> ReaderT
      [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ())
-> Free (DebugF DefaultUni DefaultFun EmptyAnn Breakpoints) ()
-> ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, Monad m) =>
(f (m a) -> m a) -> Free f a -> m a
iterM (CekTrans DefaultUni DefaultFun EmptyAnn s
-> DebugF
     DefaultUni
     DefaultFun
     EmptyAnn
     Breakpoints
     (ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ())
-> ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
forall (uni :: * -> *) fun s (m :: * -> *).
(ThrowableBuiltins uni fun, MonadWriter [[Char]] m,
 MonadReader [Cmd Breakpoints] m, PrimMonad m, PrimState m ~ s) =>
CekTrans uni fun EmptyAnn s
-> DebugF uni fun EmptyAnn Breakpoints (m ()) -> m ()
handle CekTrans DefaultUni DefaultFun EmptyAnn s
cekTrans) (Free (DebugF DefaultUni DefaultFun EmptyAnn Breakpoints) ()
 -> ReaderT
      [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ())
-> Free (DebugF DefaultUni DefaultFun EmptyAnn Breakpoints) ()
-> ReaderT [Cmd Breakpoints] (WriterT [[Char]] (CekM Any Any s)) ()
forall a b. (a -> b) -> a -> b
$ NTerm DefaultUni DefaultFun EmptyAnn
-> Free (DebugF DefaultUni DefaultFun EmptyAnn Breakpoints) ()
forall (uni :: * -> *) fun ann bps (m :: * -> *).
(Breakpointable ann bps, MonadFree (DebugF uni fun ann bps) m) =>
NTerm uni fun ann -> m ()
runDriverT NTerm DefaultUni DefaultFun EmptyAnn
t

-- Interpretation of the mocker
-------------------------------

handle :: forall uni fun s m.
         ( ThrowableBuiltins uni fun
         , MonadWriter [String] m, MonadReader [Cmd Breakpoints] m
         , PrimMonad m, PrimState m ~ s
         )
       => CekTrans uni fun EmptyAnn s
       -> DebugF uni fun EmptyAnn Breakpoints (m ()) -> m ()
handle :: forall (uni :: * -> *) fun s (m :: * -> *).
(ThrowableBuiltins uni fun, MonadWriter [[Char]] m,
 MonadReader [Cmd Breakpoints] m, PrimMonad m, PrimState m ~ s) =>
CekTrans uni fun EmptyAnn s
-> DebugF uni fun EmptyAnn Breakpoints (m ()) -> m ()
handle CekTrans uni fun EmptyAnn s
cekTrans = \case
    StepF CekState uni fun EmptyAnn
prevState CekState uni fun EmptyAnn -> m ()
k -> do
        Either
  (CekEvaluationException NamedDeBruijn uni fun)
  (CekState uni fun EmptyAnn)
eNewState <- CekM
  uni
  fun
  s
  (Either
     (CekEvaluationException NamedDeBruijn uni fun)
     (CekState uni fun EmptyAnn))
-> m (Either
        (CekEvaluationException NamedDeBruijn uni fun)
        (CekState uni fun EmptyAnn))
forall (m :: * -> *) s (uni :: * -> *) fun a.
(PrimMonad m, PrimState m ~ s) =>
CekM uni fun s a -> m a
liftCek (CekM
   uni
   fun
   s
   (Either
      (CekEvaluationException NamedDeBruijn uni fun)
      (CekState uni fun EmptyAnn))
 -> m (Either
         (CekEvaluationException NamedDeBruijn uni fun)
         (CekState uni fun EmptyAnn)))
-> CekM
     uni
     fun
     s
     (Either
        (CekEvaluationException NamedDeBruijn uni fun)
        (CekState uni fun EmptyAnn))
-> m (Either
        (CekEvaluationException NamedDeBruijn uni fun)
        (CekState uni fun EmptyAnn))
forall a b. (a -> b) -> a -> b
$ CekM uni fun s (CekState uni fun EmptyAnn)
-> CekM
     uni
     fun
     s
     (Either
        (CekEvaluationException NamedDeBruijn uni fun)
        (CekState uni fun EmptyAnn))
forall e (m :: * -> *) a. MonadError e m => m a -> m (Either e a)
tryError (CekM uni fun s (CekState uni fun EmptyAnn)
 -> CekM
      uni
      fun
      s
      (Either
         (CekEvaluationException NamedDeBruijn uni fun)
         (CekState uni fun EmptyAnn)))
-> CekM uni fun s (CekState uni fun EmptyAnn)
-> CekM
     uni
     fun
     s
     (Either
        (CekEvaluationException NamedDeBruijn uni fun)
        (CekState uni fun EmptyAnn))
forall a b. (a -> b) -> a -> b
$ CekTrans uni fun EmptyAnn s
cekTrans CekState uni fun EmptyAnn
prevState
        case Either
  (CekEvaluationException NamedDeBruijn uni fun)
  (CekState uni fun EmptyAnn)
eNewState of
            Right CekState uni fun EmptyAnn
newState -> do
                [[Char]] -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [Doc Any -> [Char]
forall a. Show a => a -> [Char]
show (Doc Any -> [Char]) -> Doc Any -> [Char]
forall a b. (a -> b) -> a -> b
$ Doc Any
"OldState:" Doc Any -> Doc Any -> Doc Any
forall ann. Doc ann -> Doc ann -> Doc ann
<+> CekState uni fun EmptyAnn -> Doc Any
forall a ann. Pretty a => a -> Doc ann
forall ann. CekState uni fun EmptyAnn -> Doc ann
pretty CekState uni fun EmptyAnn
prevState
                           Doc Any -> Doc Any -> Doc Any
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc Any
"NewState:" Doc Any -> Doc Any -> Doc Any
forall ann. Doc ann -> Doc ann -> Doc ann
<+> CekState uni fun EmptyAnn -> Doc Any
forall a ann. Pretty a => a -> Doc ann
forall ann. CekState uni fun EmptyAnn -> Doc ann
pretty CekState uni fun EmptyAnn
newState]
                CekState uni fun EmptyAnn -> m ()
k CekState uni fun EmptyAnn
newState
            Left CekEvaluationException NamedDeBruijn uni fun
e -> [[Char]] -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [Doc Any -> [Char]
forall a. Show a => a -> [Char]
show (Doc Any -> [Char]) -> Doc Any -> [Char]
forall a b. (a -> b) -> a -> b
$ Doc Any
"OldState:" Doc Any -> Doc Any -> Doc Any
forall ann. Doc ann -> Doc ann -> Doc ann
<+> CekState uni fun EmptyAnn -> Doc Any
forall a ann. Pretty a => a -> Doc ann
forall ann. CekState uni fun EmptyAnn -> Doc ann
pretty CekState uni fun EmptyAnn
prevState
                                Doc Any -> Doc Any -> Doc Any
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc Any
"NewState is Error:" Doc Any -> Doc Any -> Doc Any
forall ann. Doc ann -> Doc ann -> Doc ann
<+> CekEvaluationException NamedDeBruijn uni fun -> Doc Any
forall a ann. Show a => a -> Doc ann
viaShow CekEvaluationException NamedDeBruijn uni fun
e]
                     -- no kontinuation, exit
    InputF Cmd Breakpoints -> m ()
k          -> (Cmd Breakpoints -> m ()) -> m ()
handleInput Cmd Breakpoints -> m ()
k
    DriverLogF Text
text m ()
k       -> [Char] -> m ()
handleLog (Text -> [Char]
T.unpack Text
text) m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> m ()
k
    UpdateClientF CekState uni fun EmptyAnn
_ m ()
k -> m ()
k -- ignore
  where
    handleInput :: (Cmd Breakpoints -> m ()) -> m ()
    handleInput :: (Cmd Breakpoints -> m ()) -> m ()
handleInput Cmd Breakpoints -> m ()
k = do
        [Cmd Breakpoints]
cmds <- m [Cmd Breakpoints]
forall r (m :: * -> *). MonadReader r m => m r
ask
        case [Cmd Breakpoints]
cmds of
            [] ->
                [[Char]] -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [[Char]
"Early run out of commands"]
            (Cmd Breakpoints
cmd:[Cmd Breakpoints]
cmds') ->
                ([Cmd Breakpoints] -> [Cmd Breakpoints]) -> m () -> m ()
forall a. ([Cmd Breakpoints] -> [Cmd Breakpoints]) -> m a -> m a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local ([Cmd Breakpoints] -> [Cmd Breakpoints] -> [Cmd Breakpoints]
forall a b. a -> b -> a
const [Cmd Breakpoints]
cmds') (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
                    -- continue by feeding the next command to continuation
                    Cmd Breakpoints -> m ()
k Cmd Breakpoints
cmd

    handleLog :: String -> m ()
    handleLog :: [Char] -> m ()
handleLog = [[Char]] -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([[Char]] -> m ()) -> ([Char] -> [[Char]]) -> [Char] -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure