From 3240dc3b54438e55cdbc7d449aeaaad705bbb653 Mon Sep 17 00:00:00 2001 From: Pepe Iborra Date: Mon, 27 Aug 2007 18:09:49 +0000 Subject: [PATCH] :stepover ---> :steplocal, :stepmodule :stepover is declared a failed experiment. :steplocal steps only on ticks contained in the current top level declaration. :stepmodule steps only on ticks contained on the current module. The current top level declaration and module are with respect to the breakpoint we are stopped on. The main reason for the failure of :stepover (apart from lacking a lexical call stack of course) is that it fails to detect when the expression being evaluated is "complete", i.e. there are no ticks left in it. My assumption of the rightmost tick as the "last one", signaling that the expression is completely evaluated, is not true at all under laziness. This assumption was key in the implementation of :stepover. --- compiler/ghci/InteractiveUI.hs | 62 +++++++++++++++++----------------------- docs/users_guide/ghci.xml | 6 ++-- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/compiler/ghci/InteractiveUI.hs b/compiler/ghci/InteractiveUI.hs index bea11bf..4bc8c54 100644 --- a/compiler/ghci/InteractiveUI.hs +++ b/compiler/ghci/InteractiveUI.hs @@ -130,7 +130,8 @@ builtin_commands = [ ("show", keepGoing showCmd, False, completeNone), ("sprint", keepGoing sprintCmd, False, completeIdentifier), ("step", keepGoing stepCmd, False, completeIdentifier), - ("stepover", keepGoing stepOverCmd, False, completeIdentifier), + ("steplocal", keepGoing stepLocalCmd, False, completeIdentifier), + ("stepmodule",keepGoing stepModuleCmd, False, completeIdentifier), ("type", keepGoing typeOfExpr, False, completeIdentifier), ("trace", keepGoing traceCmd, False, completeIdentifier), ("undef", keepGoing undefineMacro, False, completeMacro), @@ -186,7 +187,8 @@ helpText = " :sprint [ ...] simplifed version of :print\n" ++ " :step single-step after stopping at a breakpoint\n"++ " :step single-step into \n"++ - " :stepover single-step without following function applications\n"++ + " :steplocal single-step restricted to the current top level decl.\n"++ + " :stepmodule single-step restricted to the current module\n"++ " :trace trace after stopping at a breakpoint\n"++ " :trace trace into (remembers breakpoints for :history)\n"++ @@ -566,7 +568,7 @@ runStmt stmt step --afterRunStmt :: GHC.RunResult -> GHCi Bool -- False <=> the statement failed to compile afterRunStmt _ (GHC.RunException e) = throw e -afterRunStmt pred run_result = do +afterRunStmt step_here run_result = do session <- getSession resumes <- io $ GHC.getResumeContext session case run_result of @@ -575,7 +577,7 @@ afterRunStmt pred run_result = do when show_types $ printTypeOfNames session names GHC.RunBreak _ names mb_info | isNothing mb_info || - pred (GHC.resumeSpan $ head resumes) -> do + step_here (GHC.resumeSpan $ head resumes) -> do printForUser $ ptext SLIT("Stopped at") <+> ppr (GHC.resumeSpan $ head resumes) -- printTypeOfNames session names @@ -586,7 +588,7 @@ afterRunStmt pred run_result = do enqueueCommands [stop st] return () | otherwise -> io(GHC.resume session GHC.SingleStep) >>= - afterRunStmt pred >> return () + afterRunStmt step_here >> return () _ -> return () flushInterpBuffers @@ -1567,43 +1569,31 @@ stepCmd :: String -> GHCi () stepCmd [] = doContinue (const True) GHC.SingleStep stepCmd expression = do runStmt expression GHC.SingleStep; return () -stepOverCmd [] = do +stepLocalCmd :: String -> GHCi () +stepLocalCmd [] = do mb_span <- getCurrentBreakSpan case mb_span of Nothing -> stepCmd [] Just loc -> do Just mod <- getCurrentBreakModule - parent <- enclosingTickSpan mod loc - allTicksRightmost <- (sortBy rightmost . map snd) `fmap` - ticksIn mod parent - let lastTick = null allTicksRightmost || - head allTicksRightmost == loc - if not lastTick - then doContinue (`isSubspanOf` parent) GHC.SingleStep - else doContinue (const True) GHC.SingleStep - -stepOverCmd expression = stepCmd expression - -{- - So, the only tricky part in stepOver is detecting that we have - arrived to the last tick in an expression, in which case we must - step normally to the next tick. - What we do is: - 1. Retrieve the enclosing expression block (with a tick) - 2. Retrieve all the ticks there and sort them out by 'rightness' - 3. See if the current tick turned out the first one in the list --} - ---ticksIn :: Module -> SrcSpan -> GHCi [Tick] -ticksIn mod src = do - ticks <- getTickArray mod - let lines = [srcSpanStartLine src .. srcSpanEndLine src] - return [ t | line <- lines - , t@(_,span) <- ticks ! line - , srcSpanStart src <= srcSpanStart span - , srcSpanEnd src >= srcSpanEnd span - ] + current_toplevel_decl <- enclosingTickSpan mod loc + doContinue (`isSubspanOf` current_toplevel_decl) GHC.SingleStep + +stepLocalCmd expression = stepCmd expression + +stepModuleCmd :: String -> GHCi () +stepModuleCmd [] = do + mb_span <- getCurrentBreakSpan + case mb_span of + Nothing -> stepCmd [] + Just loc -> do + Just span <- getCurrentBreakSpan + let f some_span = optSrcSpanFileName span == optSrcSpanFileName some_span + doContinue f GHC.SingleStep + +stepModuleCmd expression = stepCmd expression +-- | Returns the span of the largest tick containing the srcspan given enclosingTickSpan :: Module -> SrcSpan -> GHCi SrcSpan enclosingTickSpan mod src = do ticks <- getTickArray mod diff --git a/docs/users_guide/ghci.xml b/docs/users_guide/ghci.xml index a8ebbd7..69078d5 100644 --- a/docs/users_guide/ghci.xml +++ b/docs/users_guide/ghci.xml @@ -1109,8 +1109,10 @@ right :: [a] bug. GHCi offers two variants of stepping. Use :step to enable all the breakpoints in the program, and execute until the next breakpoint is - reached. Use :stepover to step over function - applications, which of course are executed all the same. + reached. Use :steplocal to limit the set + of enabled breakpoints to those in the current top level function. + Similarly, use :stepmodule to single step only on + breakpoints contained in the current module. For example: -- 1.7.10.4