Commit f1309012 authored by bbr's avatar bbr
Browse files

further advancement toward general debugging

- makefile cleans now oracle path
- completed call for stricths from kicsi
- added orc directory to input of ghc
- removed to/from data from prelude
- include file for strict prelude added
  similar files needed for other libraries
- let expressions again correctly printed in pretty printer
- revived the underscore function in strict steps
  and added improvements by holger
- added type signature in Wrapper
- thousends of small changes in stricths to make prelude fit
  and include external definitions
parent bcbc4d33
......@@ -54,13 +54,14 @@ libs: $(BIN)kics runtime
.PHONY: clean
clean:
rm -f *.o *.hi $(LIB)*.o $(LIB)*.hi $(SRC)*.o $(SRC)*.hi test/*.o test/*.hi
rm -f *.o *.hi $(LIB)*.o $(LIB)*.hi $(ORACLE)*.o $(ORACLE)*.hi $(SRC)*.o $(SRC)*.hi test/*.o test/*.hi
.PHONY: mrproper
mrproper: clean
rm -f $(SRC)InstallDir.hs
rm -f $(SRC)AutoGenerated*.hs
rm -f $(LIB)Curry*.hs $(LIB)Data*.hs $(LIB)Instances*.hs $(LIB)*.fcy $(LIB)*.fint\
$(ORACLE)Curry*.hs $(ORACLE)Data*.hs $(ORACLE)Instances*.hs $(ORACLE)*.fcy $(ORACLE)*.fint\
test/Curry*.hs test/Data*.hs test/Instances*.hs test/*.fcy test/*.fint
......
......@@ -171,7 +171,16 @@ readPMode s = readPM (words (map toLower s))
ghcCall opts =
callnorm (ghc opts++makeGhc (make opts)
++" -i"++installDir++"/src:"++libpath opts++" "++verboseGhc (verbose opts))
++" -i"++installDir++"/src:"
++installDir++"/src/oracle/:"
++libpath opts++" "++verboseGhc (verbose opts))
stricthsCall opts =
callnorm ("stricths --hs "
++ ("-s"++mainModule opts++".steps ")
++ (if make opts then "-m " else "")
++ (if force opts then "-f " else "")
++ filename opts)
verboseGhc True = ""
verboseGhc False = " -v0 "
......
......@@ -229,10 +229,11 @@ requestExpr state opts line = do
let ls = loadedFiles state
safeSystem (verbose opts) ("rm -f request Request.fcy "++reqMod ++".o ")
genReqModule (loadedFiles state) line
startCompilation (opts {executable=True,filename="Request",
let compileOpts = (opts{executable=True,filename="Request",
mainFunc="expression",
mainModule = if null ls then "Prelude" else head ls,
make=False})
make=False})
startCompilation compileOpts
let call = timing state (requestCall state opts)
if eval opts
then return ()
......@@ -240,7 +241,14 @@ requestExpr state opts line = do
if verbose opts || not (eval opts)
then safeIO (putStrLn ("starting evaluation of "++line))
else return ()
safeSystem (verbose opts) call)
safeSystem (verbose opts) call
if not (debug opts)
then return ()
else do
safeSystem (verbose opts) (stricthsCall compileOpts{make=True})
safeSystem (verbose opts) (ghcCall opts{make=True} ++ " StrictRequest")
safeSystem (verbose opts) (ghcCall opts{make=False} ++ " StrictRequest -e expression")
)
interactive state opts
......
......@@ -320,7 +320,7 @@ searchTr x state = transVal (nfCTC (nfCTC (\ x _ -> x)) x state)
transBranching [x] = transVal x
transBranching xs@(_:_:_) = C_Or (fromHaskellList (map transVal xs))
{-
toData :: Curry a => a -> Result C_Data
toData _ st = prim_error (toCurry "toData not implemented") st --ctcStore True (toC_Term True) Nothing
......@@ -336,6 +336,7 @@ cmap f (x :< xs) = f x :< cmap f xs
fromData :: Curry a => C_Data -> Result a
fromData _ st = prim_error (toCurry "fromData not implemented") st --fromC_Term
-}
prepApply :: (BaseCurry a,BaseCurry b) =>
((b -> Result a) -> b -> Result a) -> b -> (Prim (b -> Result a)) -> Result a
......
......@@ -903,7 +903,7 @@ data SearchTree a
getSearchTree :: a -> IO (SearchTree a)
getSearchTree external
{-
--- Basic operation for generic programming
--- type Data represents arbitrary data types
--- with the strings containing the names of
......@@ -933,7 +933,7 @@ toNumData external
--- show, read, compare and (==).
--- See compare above for a simple example.
--- Other operations can be found in Module Generic
-}
--- depth first search
allValuesD :: SearchTree a -> [a]
......
------------------------------------------------------
-- include for debugging into Prelude
------------------------------------------------------
import qualified Prelude (error, (==), (*), (+), div,
abs, mod, compare, negate,
Ordering(..),map,Bool(..),Int(..))
import StrictSteps
import qualified Char
infixr 0 $!
infixr 0 $!!
infixr 0 $#
infixr 0 $##
($!),($!!),($#),($##) :: StrictCurry b => (a -> Step b) -> a -> Step b
f $! x = f x
f $!! x = f x
f $# x = f x
f $## x = incSteps (f x)
type String' = List Char'
instance (Eq a,Show a) => StrictCurry (Maybe a) where
underscore = Nothing
showCons Nothing = consUnderscore
showCons (Just a) = consTerm (Prelude.show a) []
instance Show (IO a) where
show x = "IO"
instance Eq (IO a) where
_==_ = Prelude.error ""
prim_error :: StrictCurry a => String' -> Step a
prim_error x = return' underscore
prim_failed :: StrictCurry a => Step a
prim_failed = return' underscore
prim_ord :: Char' -> Step Int'
prim_ord (Just c) = incSteps (return' (intToInt' (Char.ord c)))
prim_chr :: Int' -> Step Char'
prim_chr i = return' (Just (Char.chr (int'ToInt i)))
(===) :: StrictCurry a => a -> a -> Step Bool'
x === y = return' (boolToBool' (x Prelude.== y))
(==) :: StrictCurry a => a -> a -> Step Bool'
x == y = return' (boolToBool' (x Prelude.== y))
(&) :: (StrictCurry a,StrictCurry b) => a -> b -> Step b
_ & y = return' y
andBreadth = Prelude.error ""
prim_bind = Prelude.error ""
--prim_return :: StrictCurry a => a -> Step a
prim_return = Prelude.error "" --return'
prim_putChar = Prelude.error "" --return' ()
prim_readFile = Prelude.error ""
prim_writeFile _ = Prelude.error "" --return ()
prim_appendFile _ = Prelude.error "" --return ()
catchFail = Prelude.error ""
prim_show :: StrictCurry a => a -> Step String'
prim_show a = return' (listToList' (Prelude.map Just (Prelude.show a)))
getSearchTree x = Prelude.error ""
prim_getChar = Prelude.error ""
apply :: (StrictCurry a,StrictCurry b) => (a -> b) -> a -> b
apply f x = f x
cond= Prelude.error ""
commit= Prelude.error ""
(=:<=)= Prelude.error ""
int'ToInt :: Int' -> Prelude.Int
int'ToInt Zero = 0
int'ToInt (Pos i) = natToInt i
int'ToInt (Neg i) = Prelude.negate (natToInt i)
intToInt' :: Prelude.Int -> Int'
intToInt' n = case Prelude.compare n 0 of
Prelude.LT -> Neg (intToNat (Prelude.abs n))
Prelude.EQ -> Zero
Prelude.GT -> Pos (intToNat (Prelude.abs n))
natToInt :: Nat -> Prelude.Int
natToInt (I bs) = 2 Prelude.* natToInt bs Prelude.+ 1
natToInt (O bs) = 2 Prelude.* natToInt bs
natToInt IHi = 1
intToNat :: Prelude.Int -> Nat
intToNat n = case Prelude.mod n 2 of
1 -> if m Prelude.== 0 then IHi else I (intToNat m)
0 -> O (intToNat m)
where m = Prelude.div n 2
bool'ToBool :: Bool' -> Prelude.Bool
bool'ToBool x0 = case x0 of False' -> Prelude.False; True' -> Prelude.True
boolToBool' :: Prelude.Bool -> Bool'
boolToBool' x0 = case x0 of Prelude.False -> False'; Prelude.True -> True'
maybe'ToMaybe :: (StrictCurry x0) => (Maybe' x0) -> (Maybe x0)
maybe'ToMaybe x0 = case x0 of Nothing' -> Nothing; Just' x1 -> Just x1
maybeToMaybe' :: (StrictCurry x0) => (Maybe x0) -> (Maybe' x0)
maybeToMaybe' x0 = case x0 of Nothing -> Nothing'; Just x1 -> Just' x1
listToList' :: [a] -> List a
listToList' [] = List
listToList' (x:xs) = Cons x (listToList' xs)
list'ToList :: List a -> [a]
list'ToList List = []
list'ToList (Cons x xs) = x : list'ToList xs
------------------------------------------------------------------------------------------
-- end of include
------------------------------------------------------------------------------------------
\ No newline at end of file
......@@ -9,12 +9,13 @@ import StyledText
import List (nub)
prelude = "Prelude"
strict = "StrictSteps"
arrow = operator (text "->")
bind = operator (text ">>>=")
bar = operator (char '|')
dcolon = operator (text "::")
deriving = text "deriving Show"
deriving = text "deriving (Eq,Show)"
isInfixName :: QName -> Bool
isInfixName (_,n) = all (`elem` infixIDs) n
......@@ -25,23 +26,17 @@ infixIDs = "~!@#$%^&*+-=<>?./|\\:"
isTupleName :: QName -> Bool
isTupleName (_,name) = elem (take 2 name) ["()","(,"]
showStyledProg :: Bool -> Prog -> String
showStyledProg isHs = pretty 78 . progDoc isHs . updProgExps elimApp
showStyledProg :: String -> Prog -> String
showStyledProg include = pretty 178 . progDoc include . updProgExps elimApp
showProg :: Bool -> Prog -> String
showProg isHs = plainText . showStyledProg isHs
showProg :: String -> Prog -> String
showProg include = plainText . showStyledProg include
printStyledProg :: Bool -> String -> IO ()
printStyledProg isHs f = readFlatCurry f >>= printStyledText . showStyledProg isHs
printStyledProg :: String -> IO ()
printStyledProg f = readFlatCurry f >>= printStyledText . showStyledProg ""
printProg :: Bool -> String -> IO ()
printProg isHs f = readFlatCurry f >>= putStrLn . showProg isHs
-- viewStyledProg :: WidgetRef -> Prog -> GuiPort -> IO ()
-- viewStyledProg ref prog = setStyledText ref (showStyledProg prog)
--viewProg :: Bool -> WidgetRef -> Prog -> GuiPort -> IO ()
--viewProg isHs ref prog = setValue ref (showProg isHs prog)
printProg :: String -> IO ()
printProg f = readFlatCurry f >>= putStrLn . showProg ""
keyword, consname :: String -> Doc
keyword = magentaDoc . text
......@@ -49,7 +44,8 @@ consname = greenDoc . text
operator, literal, marked :: Doc -> Doc
operator = blueDoc
literal = cyanDoc
literal d = parens (text "Just" <+> space <+> parens (cyanDoc d))
string = cyanDoc
marked = bgYellowDoc . boldDoc
block :: Doc -> Doc
......@@ -60,12 +56,7 @@ def name params body = block (name <> paramDoc <$> body)
where
paramDoc = if null params then empty
else space <> align (fillSep (map varDoc params))
{-
fillMulti :: (Doc -> Doc) -> (Doc -> Doc) -> [Doc] -> Doc
fillMulti _ _ [] = empty
fillMulti x y (d:ds)
= align (fillSep ((x d) : map (group . (linebreak<>) . y) ds))
-}
app :: Doc -> [Doc] -> Doc
app d ds = if null ds then d
else block (fillEncloseSep empty empty space (d:ds))
......@@ -108,11 +99,11 @@ maybeParens False = id
d1 <$>> d2 = d1 <$> line <> d2
progDoc :: Bool -> Prog -> Doc
progDoc isHs prog@(Prog name imps types funcs ops)
progDoc :: String -> Prog -> Doc
progDoc include prog@(Prog name imps types funcs ops)
= moduleHeaderDoc name (exportedNames prog) <$>>
impsDoc imps <$>> opsDoc ops <$>>
typesDoc isHs name types <$>>
impsDoc imps <+> text include <$>> opsDoc ops <$>>
typesDoc name types <$>>
funcsDoc name funcs
exportedNames :: Prog -> [Doc]
......@@ -126,8 +117,8 @@ exportedNames (Prog _ _ types funcs _)
in identifier False (typeName tdecl) <> if null ecs then empty else text "(..)"
moduleHeaderDoc :: String -> [Doc] -> Doc
moduleHeaderDoc name exports
= keyword "module" <+> consname name <+> exportsDoc exports <+>
moduleHeaderDoc name _ --exports
= keyword "module" <+> consname name <+>
keyword "where"
exportsDoc :: [Doc] -> Doc
......@@ -149,23 +140,22 @@ opDoc (Op (_,name) fix prec)
fixDoc InfixrOp = keyword "r"
inf = if all (`elem` infixIDs) name then id else bquotes
typesDoc :: Bool -> String -> [TypeDecl] -> Doc
typesDoc isHs mod = vcat . map (typeDoc isHs mod)
typesDoc :: String -> [TypeDecl] -> Doc
typesDoc mod = vcat . map (typeDoc mod)
typeDoc :: Bool -- generate instance declarations for Haskell?
-> String -> TypeDecl -> Doc
typeDoc True mod (Type name _ params cs)
typeDoc ::String -> TypeDecl -> Doc
typeDoc mod (Type name _ params cs)
= def (keyword "data" <+> identifier False name) params (consDeclsDoc mod cs <+> deriving) <$$>
(keyword "instance" <+> text "StrictCurry" <+> (if length params > 0 then parens else id)
(qname False name <+> hsep (map varDoc params)) <+> keyword "where") <$>
(text " " <+> keyword "underscore" <+> equals <+> (text (snd name ++ "Underscore"))) <$>
(keyword "instance" <+> classContextDoc params
<+> text "StrictCurry" <+> (if length params > 0 then parens else id)
(identifier False name <+> hsep (map varDoc params)) <+> keyword "where") <$>
(text " " <+> keyword "underscore" <+> equals <+> (text (snd (consName (head cs))))) <$>
(text " " <+> keyword "showCons" <+> equals <+> (text ("showCons" ++ snd name)))
typeDoc False mod (Type name _ params cs)
= def (keyword "data" <+> identifier False name) params (consDeclsDoc mod cs)
typeDoc _ mod (TypeSyn name _ params syn)
typeDoc mod (TypeSyn name _ params syn)
= def (keyword "type" <+> identifier False name) params
(operator equals <+> typeExprDoc mod False syn)
......@@ -186,11 +176,11 @@ typeExprDoc :: String -> Bool -> TypeExpr -> Doc
typeExprDoc _ _ (TVar n) = varDoc n
typeExprDoc mod br (TCons name args)
| null args = qname False name
| null args = identifier False name
| name == (prelude,"[]") = brackets (typeExprDoc mod False (head args))
| isTupleName name = tupled (map (typeExprDoc mod False) args)
| otherwise
= par br $ app (qname False name) (map (typeExprDoc mod True) args)
= par br $ app (identifier False name) (map (typeExprDoc mod True) args)
typeExprDoc mod br typ@(FuncType _ _)
= par br $ fillEncloseSep empty empty (space<>arrow<>space)
......@@ -211,11 +201,13 @@ funcDoc mod (Func name _ _ typ rule)
funcTypeDeclDoc :: String -> QName -> TypeExpr -> Doc
funcTypeDeclDoc mod name typ
= let vars = nub $ allVarsInTypeExpr typ
inst = if null vars
then empty
else tupled (map ((text "StrictCurry" <+>) . varDoc) vars) <+> operator (text "=>") in
inst = classContextDoc vars in
def (identifier True name) [] (funcTypeDoc inst mod (argTypes typ) (resultType typ))
classContextDoc :: [Int] -> Doc
classContextDoc [] = empty
classContextDoc vars@(_:_) = tupled (map ((text "StrictCurry" <+>) . varDoc) vars) <+> operator (text "=>")
funcTypeDoc :: Doc -> String -> [TypeExpr] -> TypeExpr -> Doc
funcTypeDoc inst mod args res
= fillEncloseSep ((dcolon <+> inst)<>space) empty (arrow<>space)
......@@ -234,7 +226,7 @@ expDoc mod br exp =
maybe (maybe (expDoc2 mod br exp)
(\l -> list (map (expDoc mod False) l))
(toList exp))
(\s -> if null s then consname "[]" else literal (dquotes (text s)))
(\s -> if null s then consname "[]" else string (dquotes (text s)))
(toString exp)
expDoc2 _ _ (Var n) = varDoc n
......@@ -243,6 +235,14 @@ expDoc2 _ _ (Lit l) = litDoc l
expDoc2 mod br (Comb ct name args)
| ct == FuncCall && name == (prelude,"apply")
= par br $ app (expDoc mod True (args!!0)) [expDoc mod True (args!!1)]
| name == (strict,">>>=") && length args == 3
= case args of
[e1,Var i,e2] -> align $ fillEncloseSep lbr rbr empty
[expDoc mod True e1
,space <> qname' False False name <> space
,keyword "\\" <> varDoc i <> space <> keyword "->" <> space <>
expDoc mod True e2]
_ -> error "unforseen use of (>>>=)"
| ct == ConsCall && isTupleName name
= tupled (map (expDoc mod False) args)
| isInfixName name && length args == 2
......@@ -252,15 +252,15 @@ expDoc2 mod br (Comb ct name args)
,expDoc mod True (args!!1)]
| otherwise
= par (not (null args) && br) $
app (qname (isFunCT ct) name) (map (expDoc mod True) args)
app ((if ct==ConsCall then identifier else qname) (isFunCT ct) name) (map (expDoc mod True) args)
where
(lbr,rbr) = if br then (lparen,rparen) else (empty,empty)
expDoc2 mod br (Let bs e)
= par br $ hang 1 $
letBindsDoc mod bs <$>
expDoc mod False e
keyword "let" <+> letBindsDoc mod bs <$>
keyword "in" <+> expDoc mod False e
expDoc2 mod br (Free vs e)
-- | null vs = marked (expDoc mod br e)
......@@ -288,23 +288,21 @@ caseTypeDoc Flex = empty
patternDoc :: Pattern -> Doc
patternDoc (Pattern name args)
| null args = qname False name
| null args = identifier False name
| isTupleName name = tupled (map varDoc args)
| isInfixName name && length args == 2
= varDoc (args!!0) <> operator (text (snd name)) <> varDoc (args!!1)
{-| name == (prelude,":")
= varDoc (args!!0) <> operator colon <> varDoc (args!!1)-}
| otherwise = qname False name <+> hsep (map varDoc args)
| otherwise = identifier False name <+> hsep (map varDoc args)
patternDoc (LPattern l) = litDoc l
letBindsDoc :: String -> [(Int,Expr)] -> Doc
letBindsDoc mod = align . compose (combine (linesep " ")) . map (letBindDoc mod)
letBindsDoc mod = layout . map (letBindDoc mod)
letBindDoc :: String -> (Int,Expr) -> Doc
letBindDoc mod (n,e) =
expDoc mod False e <+>
bind <+> backslash <+> varDoc n <+> arrow
letBindDoc mod (n,e) = varDoc n <+> operator equals <+> expDoc mod False e
litDoc :: Literal -> Doc
litDoc (Intc n) = literal (int n)
......
module StrictSteps(Oracle, Step, (>>>=), return',
StrictCurry, showCons, underscore,
StrictCurry(..),
traceFunCall, traceProgram, traceWithStepfile,
ConstructorTerm, consTerm, consUnderscore,
failed
failed, incSteps
) where
import Prelude hiding (($!))
import Control.Monad.Error
import Control.Monad.State
import Data.IORef
import System.Exit
import System.IO
import System.IO.Unsafe
hello= " ____ ____ _____ \n\
\( _ \\ (_ _) ( _ ) Believe\n\
......@@ -96,17 +96,21 @@ instance Show ConstructorTerm where
erweitert werden konnten, umgehen kann (z.B. Funktionen).
-}
class StrictCurry a where
class (Show a,Eq a) => StrictCurry a where
underscore :: a
showCons :: a -> ConstructorTerm
showCons x = consTerm (show x) []
-- Default-Implementierung
underscore = error "I stumbled over an underscore"
showCons _ = ConsUnderscore
-----------------------------------
-- ... but it safes a lot of work
-----------------------------------
instance StrictCurry (a -> b) where
showCons _ = ConsUnderscore
instance Show (a -> b) where
show _ = "FUNCTION"
instance Eq (a -> b) where
f == g = True
{-
......@@ -228,10 +232,11 @@ data BugReport = BugReport
BugReport soll von der Monadentransformation
ErrorT verwendet werden, um Fehler zu melden.
-}
instance Error BugReport where
noMsg = BugReport
{ lhs = ConsUnderscore,
rhs = ConsUnderscore }
instance Error (Maybe a) where
noMsg = Nothing --BugReport
-- { lhs = ConsUnderscore,
-- rhs = ConsUnderscore }
{-
Ein Berechnungsschritt ordnet einem Debugger-Zustand
......@@ -248,7 +253,7 @@ instance Error BugReport where
-}
type DebugMonad a = StateT DebuggerState (ErrorT BugReport IO) a
type DebugMonad a = StateT DebuggerState (ErrorT (Maybe BugReport) IO) a
type Step a = StepMode -> DebugMonad a
......@@ -274,15 +279,17 @@ a >>>= b = \ mode -> do
b a' mode
return' :: StrictCurry a => a -> Step a
return' :: a -> Step a
return' x = \ _ -> return x
incSteps :: StrictCurry a => Step a -> Step a
incSteps x = return' (x>>>=return') >>>= \ _ -> x
evalIfNeeded :: StrictCurry a => Step a -> Step a
evalIfNeeded a mode
= do state <- get
let (orc, needed) = popBoolStack (oracle state)
put $ state {oracle = orc}
put (state {oracle = orc})
(if needed then
a mode
else
......@@ -307,9 +314,6 @@ evalIfNeeded a mode
traceWithStepfile :: StrictCurry a => String -> Step a -> IO ()
traceWithStepfile name program = do
hSetBuffering stdout NoBuffering
hSetBuffering stdin NoBuffering
-- hSetEcho stdin False -- this breaks ghci :-(
oracle <- loadStepfile name
let (l',_ ) = popBoolStack oracle
traceProgram (traceFunCall "main" [] program) l'
......@@ -320,7 +324,7 @@ traceWithStepfile name program = do
-}
loadStepfile :: String -> IO BoolStack
loadStepfile name
= let filename = name ++ ".steps"
= let filename = name
in do file <- readFile filename
case reads file of
[(l,_)] -> return l
......@@ -334,9 +338,13 @@ loadStepfile name
bis alle Funktionsaufrufe bewertet sind oder ein Bug
gefunden wurde.
-}
traceProgram :: StrictCurry a => Step a -> Oracle -> IO ()
traceProgram :: Step a -> Oracle -> IO ()
traceProgram program oracle
= do banner
= do hSetBuffering stdout NoBuffering
hSetBuffering stdin NoBuffering
echomode <- hGetEcho stdin
hSetEcho stdin False
banner
dmode <- newIORef (DisplayMode False True)
let state = DebuggerState
{oracle = oracle,
......@@ -344,6 +352,7 @@ traceProgram program oracle
skipped = emptyBoolStack,
unrated = allTrue }
bug <- runErrorT $ evalStateT (traceLoop program) state
hSetEcho stdin True
report bug
......@@ -352,7 +361,7 @@ traceProgram program oracle
darin alle Funktionsaufrufe bewertet sind oder ein
fehlerhafter Aufruf gefunden wurde.
-}
traceLoop :: StrictCurry a => Step a -> DebugMonad a
traceLoop :: Step a -> DebugMonad a
traceLoop program
= do state <- get
put $ state { skipped = emptyBoolStack }
......@@ -393,7 +402,7 @@ traceFunCall fname args expr StepInteractive
r <- expr StepBackground
inspectResult r ss
inspectResult result startState
= do liftIO $ showStep fcall (showCons result)
= do liftIO $ showStep fcall (Just (showCons result))
showMenu (irMenu result startState)
irMenu result startState
= [('c', ("correct",
......@@ -406,8 +415,8 @@ traceFunCall fname args expr StepInteractive
('w', ("wrong",
do put startState
traceLoop expr
throwError BugReport { lhs = fcall,
rhs = showCons result })),
throwError (Just BugReport { lhs = fcall,
rhs = showCons result }))),
('s', ("skip",
do return result)),
('v', ("toggle verbosity",
......@@ -417,13 +426,13 @@ traceFunCall fname args expr StepInteractive
do modifyDisplayMode toggleInspectMode
inspectResult result startState)),
('q', ("quit",
liftIO $ exitWith ExitSuccess)),
throwError Nothing)),
(' ', ("step into",