Rodrigo Mesquita pushed to branch wip/romes/exec-break-has-resume at Glasgow Haskell Compiler / GHC

Commits:

6 changed files:

Changes:

  • compiler/GHC.hs
    ... ... @@ -203,8 +203,7 @@ module GHC (
    203 203
             Resume(..),
    
    204 204
             History(historyBreakpointId, historyEnclosingDecls),
    
    205 205
             GHC.getHistorySpan, getHistoryModule,
    
    206
    -        abandon, abandonAll,
    
    207
    -        getResumeContext,
    
    206
    +        abandon,
    
    208 207
             GHC.obtainTermFromId, GHC.obtainTermFromVal, reconstructType,
    
    209 208
             modInfoModBreaks,
    
    210 209
             ModBreaks(..), BreakTickIndex,
    

  • compiler/GHC/Runtime/Context.hs
    ... ... @@ -24,7 +24,7 @@ import GHC.Hs
    24 24
     import GHC.Driver.DynFlags
    
    25 25
     import {-# SOURCE #-} GHC.Driver.Plugins
    
    26 26
     
    
    27
    -import GHC.Runtime.Eval.Types ( IcGlobalRdrEnv(..), Resume )
    
    27
    +import GHC.Runtime.Eval.Types ( IcGlobalRdrEnv(..) )
    
    28 28
     
    
    29 29
     import GHC.Unit
    
    30 30
     import GHC.Unit.Env
    
    ... ... @@ -322,9 +322,6 @@ data InteractiveContext
    322 322
              ic_default :: DefaultEnv,
    
    323 323
                  -- ^ The current default classes and types, set by 'default' declarations
    
    324 324
     
    
    325
    -         ic_resume :: [Resume],
    
    326
    -             -- ^ The stack of breakpoint contexts
    
    327
    -
    
    328 325
              ic_monad      :: ExactRdrName,
    
    329 326
                  -- ^ The monad that GHCi is executing in
    
    330 327
     
    
    ... ... @@ -370,7 +367,6 @@ emptyInteractiveContext dflags
    370 367
            ic_monad      = ExactOcc ioTyConOcc, -- IO monad by default
    
    371 368
            ic_int_print  = ExactOcc printIdOcc,   -- System.IO.print by default
    
    372 369
            ic_default    = emptyDefaultEnv,
    
    373
    -       ic_resume     = [],
    
    374 370
            ic_cwd        = Nothing,
    
    375 371
            ic_plugins    = emptyPlugins
    
    376 372
            }
    

  • compiler/GHC/Runtime/Debugger/Breakpoints.hs
    ... ... @@ -266,32 +266,21 @@ mkBreakpointOccurrences = do
    266 266
     -- Getting current breakpoint information
    
    267 267
     --------------------------------------------------------------------------------
    
    268 268
     
    
    269
    -getCurrentBreakSpan :: GhcMonad m => m (Maybe SrcSpan)
    
    270
    -getCurrentBreakSpan = do
    
    269
    +getResumeBreakSpan :: GhcMonad m => Resume -> m SrcSpan
    
    270
    +getResumeBreakSpan r = do
    
    271 271
       hug <- hsc_HUG <$> getSession
    
    272
    -  resumes <- getResumeContext
    
    273
    -  case resumes of
    
    274
    -    [] -> return Nothing
    
    275
    -    (r:_) -> do
    
    276
    -        let ix = resumeHistoryIx r
    
    277
    -        if ix == 0
    
    278
    -           then return (Just (resumeSpan r))
    
    279
    -           else do
    
    280
    -                let hist = resumeHistory r !! (ix-1)
    
    281
    -                pan <- liftIO $ getHistorySpan hug hist
    
    282
    -                return (Just pan)
    
    272
    +  case resumeHistoryIx r of
    
    273
    +    0  -> return (resumeSpan r)
    
    274
    +    ix -> liftIO $ getHistorySpan hug (resumeHistory r !! (ix-1))
    
    283 275
     
    
    284
    -getCurrentBreakModule :: GhcMonad m => m (Maybe Module)
    
    285
    -getCurrentBreakModule = do
    
    286
    -  resumes <- getResumeContext
    
    276
    +getResumeBreakModule :: GhcMonad m => Resume -> m (Maybe Module)
    
    277
    +getResumeBreakModule r = do
    
    287 278
       hug <- hsc_HUG <$> getSession
    
    288
    -  liftIO $ case resumes of
    
    289
    -    [] -> pure Nothing
    
    290
    -    (r:_) -> case resumeHistoryIx r of
    
    291
    -      0  -> case resumeBreakpointId r of
    
    292
    -        Nothing -> pure Nothing
    
    293
    -        Just ibi -> do
    
    294
    -          brks <- readIModBreaks hug ibi
    
    295
    -          return $ Just $ getBreakSourceMod ibi brks
    
    296
    -      ix ->
    
    297
    -          Just <$> getHistoryModule hug (resumeHistory r !! (ix-1))
    279
    +  liftIO $ case resumeHistoryIx r of
    
    280
    +    0  -> case resumeBreakpointId r of
    
    281
    +      Nothing -> pure Nothing
    
    282
    +      Just ibi -> do
    
    283
    +        brks <- readIModBreaks hug ibi
    
    284
    +        return $ Just $ getBreakSourceMod ibi brks
    
    285
    +    ix ->
    
    286
    +        Just <$> getHistoryModule hug (resumeHistory r !! (ix-1))

  • compiler/GHC/Runtime/Eval.hs
    ... ... @@ -14,8 +14,7 @@ module GHC.Runtime.Eval (
    14 14
             execStmt, execStmt', ExecOptions(..), execOptions, ExecResult(..), resumeExec,
    
    15 15
             runDecls, runDeclsWithLocation, runParsedDecls,
    
    16 16
             parseImportDecl, SingleStep(..),
    
    17
    -        abandon, abandonAll,
    
    18
    -        getResumeContext,
    
    17
    +        abandon,
    
    19 18
             getHistorySpan,
    
    20 19
             getModBreaks, readIModBreaks, readIModModBreaks,
    
    21 20
             getHistoryModule,
    
    ... ... @@ -140,9 +139,6 @@ import GHCi.BreakArray (BreakArray)
    140 139
     -- -----------------------------------------------------------------------------
    
    141 140
     -- running a statement interactively
    
    142 141
     
    
    143
    -getResumeContext :: GhcMonad m => m [Resume]
    
    144
    -getResumeContext = withSession (return . ic_resume . hsc_IC)
    
    145
    -
    
    146 142
     mkHistory :: HUG.HomeUnitGraph -> ForeignHValue -> InternalBreakpointId -> IO History
    
    147 143
     mkHistory hug hval ibi = History hval ibi <$> findEnclosingDecls hug ibi
    
    148 144
     
    
    ... ... @@ -341,9 +337,8 @@ handleRunStatus step expr bindings final_ids status history0 = do
    341 337
               , resumeCCS = ccs
    
    342 338
               , resumeHistoryIx = 0
    
    343 339
               }
    
    344
    -        hsc_env2 = pushResume hsc_env1 resume
    
    345 340
     
    
    346
    -      setSession hsc_env2
    
    341
    +      setSession hsc_env1
    
    347 342
           return (ExecBreak break_ids Nothing resume)
    
    348 343
     
    
    349 344
         -- EvalBreak (Just ...) case: the interpreter stopped at a breakpoint
    
    ... ... @@ -388,8 +383,7 @@ handleRunStatus step expr bindings final_ids status history0 = do
    388 383
                 , resumeCCS = ccs
    
    389 384
                 , resumeHistoryIx = 0
    
    390 385
                 }
    
    391
    -          hsc_env2 = pushResume hsc_env1 resume
    
    392
    -        setSession hsc_env2
    
    386
    +        setSession hsc_env1
    
    393 387
             return (ExecBreak break_ids (Just ibi) resume)
    
    394 388
           else do
    
    395 389
             -- resume with the same step type
    
    ... ... @@ -409,10 +403,6 @@ handleRunStatus step expr bindings final_ids status history0 = do
    409 403
     --
    
    410 404
     -- The interactive things in scope are restored to the things available at the
    
    411 405
     -- time this paused thread hit the breakpoint.
    
    412
    ---
    
    413
    --- This 'Resume' is not popped off the interactive `ic_resume` breakpoint
    
    414
    --- stack, since there's no way to tell which of the breakpoints in the stack is
    
    415
    --- the one we're resuming.
    
    416 406
     resumeExec :: GhcMonad m
    
    417 407
                => SingleStep
    
    418 408
                -> Maybe Int
    
    ... ... @@ -495,58 +485,49 @@ getBreakArray interp InternalBreakpointId{ibi_info_mod} imbs = do
    495 485
               ( ld_st'
    
    496 486
               , ba
    
    497 487
               )
    
    498
    -back :: GhcMonad m => Int -> m ([Id], Int, SrcSpan)
    
    488
    +
    
    489
    +back :: GhcMonad m => Int -> Resume -> m (Resume, [Id], SrcSpan)
    
    499 490
     back n = moveHist (+n)
    
    500 491
     
    
    501
    -forward :: GhcMonad m => Int -> m ([Id], Int, SrcSpan)
    
    492
    +forward :: GhcMonad m => Int -> Resume -> m (Resume, [Id], SrcSpan)
    
    502 493
     forward n = moveHist (subtract n)
    
    503 494
     
    
    504
    -moveHist :: GhcMonad m => (Int -> Int) -> m ([Id], Int, SrcSpan)
    
    505
    -moveHist fn = do
    
    495
    +moveHist :: GhcMonad m => (Int -> Int) -> Resume -> m (Resume, [Id], SrcSpan)
    
    496
    +moveHist fn r = do
    
    506 497
       hsc_env <- getSession
    
    507
    -  case ic_resume (hsc_IC hsc_env) of
    
    508
    -     [] -> liftIO $
    
    509
    -           throwGhcExceptionIO (ProgramError "not stopped at a breakpoint")
    
    510
    -     (r:rs) -> do
    
    511
    -        let ix = resumeHistoryIx r
    
    512
    -            history = resumeHistory r
    
    513
    -            new_ix = fn ix
    
    514
    -        --
    
    515
    -        when (history `lengthLessThan` new_ix) $ liftIO $
    
    516
    -           throwGhcExceptionIO (ProgramError "no more logged breakpoints")
    
    517
    -        when (new_ix < 0) $ liftIO $
    
    518
    -           throwGhcExceptionIO (ProgramError "already at the beginning of the history")
    
    519
    -
    
    520
    -        let
    
    521
    -          update_ic apStack mb_info = do
    
    522
    -            span <- case mb_info of
    
    523
    -                      Nothing  -> return $ mkGeneralSrcSpan (fsLit "<unknown>")
    
    524
    -                      Just ibi -> liftIO $ do
    
    525
    -                        let hug = hsc_HUG hsc_env
    
    526
    -                        brks <- readIModBreaks hug ibi
    
    527
    -                        getBreakLoc (readIModModBreaks hug) ibi brks
    
    528
    -            (hsc_env1, final_ids) <-
    
    529
    -              liftIO $ bindLocalsAtBreakpoint hsc_env apStack span mb_info
    
    530
    -            let ic = hsc_IC hsc_env1
    
    531
    -                r' = r { resumeHistoryIx = new_ix }
    
    532
    -                ic' = ic { ic_resume = r':rs }
    
    533
    -
    
    534
    -            setSession hsc_env1{ hsc_IC = ic' }
    
    535
    -
    
    536
    -            return (final_ids, new_ix, span)
    
    537
    -
    
    538
    -        -- careful: we want apStack to be the AP_STACK itself, not a thunk
    
    539
    -        -- around it, hence the cases are carefully constructed below to
    
    540
    -        -- make this the case.  ToDo: this is v. fragile, do something better.
    
    541
    -        if new_ix == 0
    
    542
    -           then case r of
    
    543
    -                   Resume { resumeApStack = apStack,
    
    544
    -                            resumeBreakpointId = mb_brkpt } ->
    
    545
    -                          update_ic apStack mb_brkpt
    
    546
    -           else case history !! (new_ix - 1) of
    
    547
    -                   History{..} ->
    
    548
    -                     update_ic historyApStack (Just historyBreakpointId)
    
    498
    +  let ix = resumeHistoryIx r
    
    499
    +      history = resumeHistory r
    
    500
    +      new_ix = fn ix
    
    501
    +  --
    
    502
    +  when (history `lengthLessThan` new_ix) $ liftIO $
    
    503
    +     throwGhcExceptionIO (ProgramError "no more logged breakpoints")
    
    504
    +  when (new_ix < 0) $ liftIO $
    
    505
    +     throwGhcExceptionIO (ProgramError "already at the beginning of the history")
    
    549 506
     
    
    507
    +  let
    
    508
    +    update_ic apStack mb_info = do
    
    509
    +      span <- case mb_info of
    
    510
    +                Nothing  -> return $ mkGeneralSrcSpan (fsLit "<unknown>")
    
    511
    +                Just ibi -> liftIO $ do
    
    512
    +                  let hug = hsc_HUG hsc_env
    
    513
    +                  brks <- readIModBreaks hug ibi
    
    514
    +                  getBreakLoc (readIModModBreaks hug) ibi brks
    
    515
    +      (hsc_env1, final_ids) <-
    
    516
    +        liftIO $ bindLocalsAtBreakpoint hsc_env apStack span mb_info
    
    517
    +      setSession hsc_env1
    
    518
    +      return (r { resumeHistoryIx = new_ix }, final_ids, span)
    
    519
    +
    
    520
    +  -- careful: we want apStack to be the AP_STACK itself, not a thunk
    
    521
    +  -- around it, hence the cases are carefully constructed below to
    
    522
    +  -- make this the case.  ToDo: this is v. fragile, do something better.
    
    523
    +  if new_ix == 0
    
    524
    +     then case r of
    
    525
    +             Resume { resumeApStack = apStack,
    
    526
    +                      resumeBreakpointId = mb_brkpt } ->
    
    527
    +                    update_ic apStack mb_brkpt
    
    528
    +     else case history !! (new_ix - 1) of
    
    529
    +             History{..} ->
    
    530
    +               update_ic historyApStack (Just historyBreakpointId)
    
    550 531
     
    
    551 532
     -- -----------------------------------------------------------------------------
    
    552 533
     -- After stopping at a breakpoint, add free variables to the environment
    
    ... ... @@ -718,12 +699,6 @@ rttiEnvironment hsc_env@HscEnv{hsc_IC=ic} = do
    718 699
                      let ic' = substInteractiveContext ic subst
    
    719 700
                      return (hsc_env{hsc_IC=ic'}, subst `composeTCvSubst` last_subst)
    
    720 701
     
    
    721
    -pushResume :: HscEnv -> Resume -> HscEnv
    
    722
    -pushResume hsc_env resume = hsc_env { hsc_IC = ictxt1 }
    
    723
    -  where
    
    724
    -        ictxt0 = hsc_IC hsc_env
    
    725
    -        ictxt1 = ictxt0 { ic_resume = resume : ic_resume ictxt0 }
    
    726
    -
    
    727 702
     
    
    728 703
       {-
    
    729 704
       Note [Syncing breakpoint info]
    
    ... ... @@ -756,31 +731,10 @@ pushResume hsc_env resume = hsc_env { hsc_IC = ictxt1 }
    756 731
     -- -----------------------------------------------------------------------------
    
    757 732
     -- Abandoning a resume context
    
    758 733
     
    
    759
    -abandon :: GhcMonad m => m Bool
    
    760
    -abandon = do
    
    761
    -   hsc_env <- getSession
    
    762
    -   let ic = hsc_IC hsc_env
    
    763
    -       resume = ic_resume ic
    
    764
    -       interp = hscInterp hsc_env
    
    765
    -   case resume of
    
    766
    -      []    -> return False
    
    767
    -      r:rs  -> do
    
    768
    -         setSession hsc_env{ hsc_IC = ic { ic_resume = rs } }
    
    769
    -         liftIO $ abandonStmt interp (resumeContext r)
    
    770
    -         return True
    
    771
    -
    
    772
    -abandonAll :: GhcMonad m => m Bool
    
    773
    -abandonAll = do
    
    774
    -   hsc_env <- getSession
    
    775
    -   let ic = hsc_IC hsc_env
    
    776
    -       resume = ic_resume ic
    
    777
    -       interp = hscInterp hsc_env
    
    778
    -   case resume of
    
    779
    -      []  -> return False
    
    780
    -      rs  -> do
    
    781
    -         setSession hsc_env{ hsc_IC = ic { ic_resume = [] } }
    
    782
    -         liftIO $ mapM_ (abandonStmt interp. resumeContext) rs
    
    783
    -         return True
    
    734
    +abandon :: GhcMonad m => Resume -> m ()
    
    735
    +abandon r = do
    
    736
    +  interp <- hscInterp <$> getSession
    
    737
    +  liftIO $ abandonStmt interp (resumeContext r)
    
    784 738
     
    
    785 739
     -- -----------------------------------------------------------------------------
    
    786 740
     -- Bounded list, optimised for repeated cons
    

  • ghc/GHCi/UI.hs
    ... ... @@ -558,6 +558,7 @@ interactiveUI config baseDFlags srcs maybe_exprs = do
    558 558
                        line_number        = 0,
    
    559 559
                        break_ctr          = 0,
    
    560 560
                        breaks             = IntMap.empty,
    
    561
    +                   resume_stack       = [],
    
    561 562
                        tickarrays         = emptyModuleEnv,
    
    562 563
                        internalBreaks     = emptyModuleEnv,
    
    563 564
                        ghci_commands      = availableCommands config,
    
    ... ... @@ -1210,7 +1211,7 @@ getInfoForPrompt :: GhciMonad m => m (SDoc, [String], Int)
    1210 1211
     getInfoForPrompt = do
    
    1211 1212
       st <- getGHCiState
    
    1212 1213
       imports <- GHC.getContext
    
    1213
    -  resumes <- GHC.getResumeContext
    
    1214
    +  resumes <- getResumeContext
    
    1214 1215
     
    
    1215 1216
       context_bit <-
    
    1216 1217
             case resumes of
    
    ... ... @@ -1831,9 +1832,9 @@ isPrefixOptOf :: String -> String -> Bool
    1831 1832
     isPrefixOptOf s x = let (body, opt) = break (== '!') s
    
    1832 1833
                         in  (body `isPrefixOf` x) && (opt `isSuffixOf` x)
    
    1833 1834
     
    
    1834
    -getCallStackAtCurrentBreakpoint :: GHC.GhcMonad m => m (Maybe [String])
    
    1835
    +getCallStackAtCurrentBreakpoint :: GhciMonad m => m (Maybe [String])
    
    1835 1836
     getCallStackAtCurrentBreakpoint = do
    
    1836
    -  resumes <- GHC.getResumeContext
    
    1837
    +  resumes <- getResumeContext
    
    1837 1838
       case resumes of
    
    1838 1839
         [] -> return Nothing
    
    1839 1840
         (r:_) -> do
    
    ... ... @@ -2355,7 +2356,7 @@ loadModule' loadTargets files = do
    2355 2356
     
    
    2356 2357
       let load_module = do
    
    2357 2358
             -- unload first
    
    2358
    -        _ <- GHC.abandonAll
    
    2359
    +        abandonAll
    
    2359 2360
             clearCaches
    
    2360 2361
     
    
    2361 2362
             GHC.setTargets targets
    
    ... ... @@ -3931,9 +3932,9 @@ showBkptTable = do
    3931 3932
       st <- getGHCiState
    
    3932 3933
       printForUser $ prettyLocations (breaks st)
    
    3933 3934
     
    
    3934
    -showContext :: GHC.GhcMonad m => m ()
    
    3935
    +showContext :: GhciMonad m => m ()
    
    3935 3936
     showContext = do
    
    3936
    -   resumes <- GHC.getResumeContext
    
    3937
    +   resumes <- getResumeContext
    
    3937 3938
        docs <- mapM pp_resume (reverse resumes)
    
    3938 3939
        printForUser $ vcat docs
    
    3939 3940
       where
    
    ... ... @@ -4400,7 +4401,7 @@ doContinue' step mbCnt= do
    4400 4401
     
    
    4401 4402
     abandonCmd :: GhciMonad m => String -> m ()
    
    4402 4403
     abandonCmd = noArgs $ withSandboxOnly ":abandon" $ do
    
    4403
    -  b <- GHC.abandon -- the prompt will change to indicate the new context
    
    4404
    +  b <- abandon -- the prompt will change to indicate the new context
    
    4404 4405
       when (not b) $ liftIO $ putStrLn "There is no computation running."
    
    4405 4406
     
    
    4406 4407
     deleteCmd :: GhciMonad m => String -> m ()
    
    ... ... @@ -4477,14 +4478,14 @@ enaDisaAllBreaks enaDisa = do
    4477 4478
         st <- getGHCiState
    
    4478 4479
         mapM_ (enaDisaAssoc enaDisa) $ IntMap.assocs $ breaks st
    
    4479 4480
     
    
    4480
    -historyCmd :: GHC.GhcMonad m => String -> m ()
    
    4481
    +historyCmd :: GhciMonad m => String -> m ()
    
    4481 4482
     historyCmd arg
    
    4482 4483
       | null arg        = history 20
    
    4483 4484
       | all isDigit arg = history (read arg)
    
    4484 4485
       | otherwise       = liftIO $ putStrLn "Syntax:  :history [num]"
    
    4485 4486
       where
    
    4486 4487
       history num = do
    
    4487
    -    resumes <- GHC.getResumeContext
    
    4488
    +    resumes <- getResumeContext
    
    4488 4489
         case resumes of
    
    4489 4490
           [] -> liftIO $ putStrLn "Not stopped at a breakpoint"
    
    4490 4491
           (r:_) -> do
    
    ... ... @@ -4546,7 +4547,7 @@ backCmd arg
    4546 4547
       | otherwise       = liftIO $ putStrLn "Syntax:  :back [num]"
    
    4547 4548
       where
    
    4548 4549
       back num = withSandboxOnly ":back" $ do
    
    4549
    -      (ids, _, pan) <- GHC.back num
    
    4550
    +      (ids, _, pan) <- moveHist (GHC.back num)
    
    4550 4551
           printForUser $ text "Logged breakpoint at" <+> ppr pan
    
    4551 4552
           printTypeOfIds ids
    
    4552 4553
            -- run the command set with ":set stop <cmd>"
    
    ... ... @@ -4560,7 +4561,7 @@ forwardCmd arg
    4560 4561
       | otherwise       = liftIO $ putStrLn "Syntax:  :forward [num]"
    
    4561 4562
       where
    
    4562 4563
       forward num = withSandboxOnly ":forward" $ do
    
    4563
    -      (ids, ix, pan) <- GHC.forward num
    
    4564
    +      (ids, ix, pan) <- moveHist (GHC.forward num)
    
    4564 4565
           printForUser $ (if (ix == 0)
    
    4565 4566
                             then text "Stopped at"
    
    4566 4567
                             else text "Logged breakpoint at") <+> ppr pan
    
    ... ... @@ -4677,7 +4678,7 @@ The names of nested functions are stored in `ModBreaks.modBreaks_decls`.
    4677 4678
     -----------------------------------------------------------------------------
    
    4678 4679
     -- :where
    
    4679 4680
     
    
    4680
    -whereCmd :: GHC.GhcMonad m => String -> m ()
    
    4681
    +whereCmd :: GhciMonad m => String -> m ()
    
    4681 4682
     whereCmd = noArgs $ do
    
    4682 4683
       mstrs <- getCallStackAtCurrentBreakpoint
    
    4683 4684
       case mstrs of
    
    ... ... @@ -4696,7 +4697,7 @@ listCmd "" = do
    4696 4697
           Just (RealSrcSpan pan _) ->
    
    4697 4698
               listAround pan True
    
    4698 4699
           Just pan@_ ->
    
    4699
    -          do resumes <- GHC.getResumeContext
    
    4700
    +          do resumes <- getResumeContext
    
    4700 4701
                  case resumes of
    
    4701 4702
                      [] -> panic "No resumes"
    
    4702 4703
                      (r:_) ->
    

  • ghc/GHCi/UI/Monad.hs
    ... ... @@ -22,6 +22,8 @@ module GHCi.UI.Monad (
    22 22
             extractDynFlags, getDynFlags,
    
    23 23
     
    
    24 24
             runStmt, runDecls, runDecls', resume, recordBreak, revertCAFs,
    
    25
    +        getResumeContext, abandon, abandonAll, moveHist,
    
    26
    +        getCurrentBreakSpan, getCurrentBreakModule,
    
    25 27
             ActionStats(..), runAndPrintStats, runWithStats, printStats,
    
    26 28
     
    
    27 29
             prettyLocations,
    
    ... ... @@ -97,6 +99,9 @@ data GHCiState = GHCiState
    97 99
             line_number    :: !Int,         -- ^ input line
    
    98 100
             break_ctr      :: !Int,
    
    99 101
             breaks         :: !(IntMap.IntMap BreakLocation),
    
    102
    +        resume_stack   :: [GHC.Resume],
    
    103
    +            -- ^ The stack of 'Resume's for nested breakpoints hit (hitting a
    
    104
    +            -- breakpoint while evaluating an expression at another breakpoint)
    
    100 105
             tickarrays     :: ModuleEnv TickArray,
    
    101 106
                 -- ^ 'tickarrays' caches the 'TickArray' for loaded modules,
    
    102 107
                 -- so that we don't rebuild it each time the user sets
    
    ... ... @@ -380,7 +385,9 @@ runStmt stmt stmt_text step = do
    380 385
                       , GHC.execSingleStep = step
    
    381 386
                       , GHC.execWrap = \fhv -> EvalApp (EvalThis (evalWrapper st))
    
    382 387
                                                        (EvalThis fhv) }
    
    383
    -    Just <$> GHC.execStmt' stmt stmt_text opts
    
    388
    +    r <- GHC.execStmt' stmt stmt_text opts
    
    389
    +    pushResume r
    
    390
    +    return (Just r)
    
    384 391
     
    
    385 392
     runDecls :: GhciMonad m => String -> m (Maybe [GHC.TyThing])
    
    386 393
     runDecls decls = do
    
    ... ... @@ -413,12 +420,70 @@ resume step mbIgnoreCnt = do
    413 420
         withProgName (progname st) $
    
    414 421
         withArgs (args st) $
    
    415 422
           reflectGHCi x $ do
    
    416
    -        GHC.getResumeContext >>= \case
    
    417
    -          [] -> liftIO $
    
    418
    -                throwGhcExceptionIO (GHC.ProgramError "not stopped at a breakpoint")
    
    419
    -          (r:rs) -> do
    
    420
    -            modifySession $ \env -> env{hsc_IC = (hsc_IC env){ ic_resume = rs }}
    
    421
    -            GHC.resumeExec step mbIgnoreCnt r
    
    423
    +        r <- popResume >>= \case
    
    424
    +          Nothing -> liftIO $
    
    425
    +            throwGhcExceptionIO (GHC.ProgramError "not stopped at a breakpoint")
    
    426
    +          Just r -> return r
    
    427
    +        res <- GHC.resumeExec step mbIgnoreCnt r
    
    428
    +        pushResume res
    
    429
    +        return res
    
    430
    +
    
    431
    +-- -----------------------------------------------------------------------------
    
    432
    +-- Resume helpers
    
    433
    +
    
    434
    +pushResume :: GhciMonad m => GHC.ExecResult -> m ()
    
    435
    +pushResume GHC.ExecBreak{GHC.breakResume = r} =
    
    436
    +  modifyGHCiState $ \st -> st{ resume_stack = r : resume_stack st }
    
    437
    +pushResume _ = return ()
    
    438
    +
    
    439
    +popResume :: GhciMonad m => m (Maybe GHC.Resume)
    
    440
    +popResume = do
    
    441
    +  st <- getGHCiState
    
    442
    +  case resume_stack st of
    
    443
    +    []   -> return Nothing
    
    444
    +    r:rs -> do setGHCiState st{ resume_stack = rs }
    
    445
    +               return (Just r)
    
    446
    +
    
    447
    +abandon :: GhciMonad m => m Bool
    
    448
    +abandon = popResume >>= \case
    
    449
    +  Nothing -> return False
    
    450
    +  Just r  -> GHC.abandon r >> return True
    
    451
    +
    
    452
    +abandonAll :: GhciMonad m => m ()
    
    453
    +abandonAll = do
    
    454
    +  st <- getGHCiState
    
    455
    +  setGHCiState st{ resume_stack = [] }
    
    456
    +  mapM_ GHC.abandon (resume_stack st)
    
    457
    +
    
    458
    +moveHist :: GhciMonad m
    
    459
    +         => (GHC.Resume -> m (GHC.Resume, [GHC.Id], SrcSpan))
    
    460
    +         -> m ([GHC.Id], Int, SrcSpan)
    
    461
    +moveHist move = do
    
    462
    +  st <- getGHCiState
    
    463
    +  case resume_stack st of
    
    464
    +    [] -> liftIO $
    
    465
    +          throwGhcExceptionIO (GHC.ProgramError "not stopped at a breakpoint")
    
    466
    +    r:rs -> do
    
    467
    +      (r', ids, pan) <- move r
    
    468
    +      setGHCiState st{ resume_stack = r' : rs }
    
    469
    +      return (ids, GHC.resumeHistoryIx r', pan)
    
    470
    +
    
    471
    +getResumeContext :: GhciMonad m => m [GHC.Resume]
    
    472
    +getResumeContext = resume_stack <$> getGHCiState
    
    473
    +
    
    474
    +getCurrentBreakSpan :: GhciMonad m => m (Maybe SrcSpan)
    
    475
    +getCurrentBreakSpan = do
    
    476
    +  resumes <- getResumeContext
    
    477
    +  case resumes of
    
    478
    +    []  -> return Nothing
    
    479
    +    r:_ -> Just <$> getResumeBreakSpan r
    
    480
    +
    
    481
    +getCurrentBreakModule :: GhciMonad m => m (Maybe Module)
    
    482
    +getCurrentBreakModule = do
    
    483
    +  resumes <- getResumeContext
    
    484
    +  case resumes of
    
    485
    +    []  -> return Nothing
    
    486
    +    r:_ -> getResumeBreakModule r
    
    422 487
     
    
    423 488
     -- --------------------------------------------------------------------------
    
    424 489
     -- timing & statistics