packages feed

ghci-dap 0.0.22.0 → 0.0.23.0

raw patch · 19 files changed

+7317/−7284 lines, 19 files

Files

Changelog.md view
@@ -1,3 +1,7 @@+20240630 ghci-dap-0.0.23.0+  * [INFO] support ghc-9.10.1.++ 20231203 ghci-dap-0.0.22.0   * [INFO] support ghc-9.8.1. 
README.md view
@@ -20,4 +20,4 @@ # Limitation Currently this project is an __experimental__ design and implementation. -* Supported ghc-9.8, ghc-9.6+* Supported ghc-9.10, ghc-9.8
+ app-ghc-9.10/GHCMain.hs view
@@ -0,0 +1,1149 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NondecreasingIndentation #-}+{-# LANGUAGE TupleSections #-}+{-# OPTIONS -fno-warn-incomplete-patterns -optc-DNON_POSIX_SOURCE #-}++-----------------------------------------------------------------------------+--+-- GHC Driver program+--+-- (c) The University of Glasgow 2005+--+-----------------------------------------------------------------------------++module GHCMain (ghcMain) where    -- DAP Modified++-- The official GHC API+import qualified GHC+import GHC              (parseTargetFiles,  Ghc, GhcMonad(..),+                          LoadHowMuch(..) )++import GHC.Driver.Backend+import GHC.Driver.CmdLine+import GHC.Driver.Env+import GHC.Driver.Errors+import GHC.Driver.Errors.Types+import GHC.Driver.Phases+import GHC.Driver.Session+import GHC.Driver.Ppr+import GHC.Driver.Pipeline  ( oneShot, compileFile )+import GHC.Driver.MakeFile  ( doMkDependHS )+import GHC.Driver.Backpack  ( doBackpack )+import GHC.Driver.Plugins+import GHC.Driver.Config.Logger (initLogFlags)+import GHC.Driver.Config.Diagnostic++import GHC.Platform+import GHC.Platform.Ways+import GHC.Platform.Host++#if defined(HAVE_INTERNAL_INTERPRETER)+import GHCi.UI              ( interactiveUI, ghciWelcomeMsg, GhciSettings )  -- DAP Modified+#endif++import GHC.Runtime.Loader   ( loadFrontendPlugin, initializeSessionPlugins )++import GHC.Unit.Env+import GHC.Unit (UnitId, homeUnitDepends)+import GHC.Unit.Home.ModInfo (emptyHomePackageTable)+import GHC.Unit.Module ( ModuleName, mkModuleName )+import GHC.Unit.Module.ModIface+import GHC.Unit.State  ( pprUnits, pprUnitsSimple )+import GHC.Unit.Finder ( findImportedModule, FindResult(..) )+import qualified GHC.Unit.State as State+import GHC.Unit.Types  ( IsBootInterface(..) )++import GHC.Types.Basic     ( failed )+import GHC.Types.SrcLoc+import GHC.Types.SourceError+import GHC.Types.Unique.Supply+import GHC.Types.PkgQual++import GHC.Utils.Error+import GHC.Utils.Misc+import GHC.Utils.Panic+import GHC.Utils.Outputable as Outputable+import GHC.Utils.Monad       ( liftIO, mapMaybeM )+import GHC.Utils.Binary        ( openBinMem, put_ )+import GHC.Utils.Logger++import GHC.Settings.Config+import GHC.Settings.Constants+import GHC.Settings.IO++import GHC.HandleEncoding+import GHC.Data.FastString+import GHC.SysTools.BaseDir++import GHC.Iface.Load+import GHC.Iface.Recomp.Binary ( fingerprintBinMem )++import GHC.Tc.Utils.Monad      ( initIfaceCheck )+import GHC.Iface.Errors.Ppr++-- Standard Haskell libraries+import System.IO+import System.Environment+import System.Exit+import System.FilePath+import Control.Monad+import Control.Monad.Trans.Class+import Control.Monad.Trans.Except (throwE, runExceptT)+import Data.Char+import Data.List ( isPrefixOf, partition, intercalate, (\\) )+import qualified Data.Set as Set+import qualified Data.Map as Map+import Data.Maybe+import Prelude+import GHC.ResponseFile (expandResponse)+import Data.Bifunctor+import GHC.Data.Graph.Directed+import qualified Data.List.NonEmpty as NE++-- DAP add+import qualified GHC.Paths+++-----------------------------------------------------------------------------+-- ToDo:++-- time commands when run with -v+-- user ways+-- Win32 support: proper signal handling+-- reading the package configuration file is too slow+-- -K<size>++-----------------------------------------------------------------------------+-- GHC's command-line interface++ghcMain :: GhciSettings -> IO ()    -- DAP Modified+ghcMain setting = do                -- DAP Modified+   hSetBuffering stdout LineBuffering+   hSetBuffering stderr LineBuffering++   configureHandleEncoding+   GHC.defaultErrorHandler defaultFatalMessager defaultFlushOut $ do+    -- 1. extract the -B flag from the args+    argv0 <- getArgs++    let (minusB_args, argv1) = partition ("-B" `isPrefixOf`) argv0+        mbMinusB | null minusB_args = Just GHC.Paths.libdir       -- DAP Modified+                 | otherwise = Just (drop 2 (last minusB_args))++    let argv2 = map (mkGeneralLocated "on the commandline") argv1++    -- 2. Parse the "mode" flags (--make, --interactive etc.)+    (mode, units, argv3, flagWarnings) <- parseModeFlags argv2++    -- If all we want to do is something like showing the version number+    -- then do it now, before we start a GHC session etc. This makes+    -- getting basic information much more resilient.++    -- In particular, if we wait until later before giving the version+    -- number then bootstrapping gets confused, as it tries to find out+    -- what version of GHC it's using before package.conf exists, so+    -- starting the session fails.+    case mode of+        Left preStartupMode ->+            do case preStartupMode of+                   ShowSupportedExtensions   -> showSupportedExtensions mbMinusB+                   ShowVersion               -> showVersion+                   ShowNumVersion            -> putStrLn cProjectVersion+                   ShowOptions isInteractive -> showOptions isInteractive+        Right postStartupMode ->+            -- start our GHC session+            GHC.runGhc mbMinusB $ do++            dflags <- GHC.getSessionDynFlags++            case postStartupMode of+                Left preLoadMode ->+                    liftIO $ do+                        case preLoadMode of+                            ShowInfo               -> showInfo dflags+                            ShowGhcUsage           -> showGhcUsage  dflags+                            ShowGhciUsage          -> showGhciUsage dflags+                            PrintWithDynFlags f    -> putStrLn (f dflags)+                Right postLoadMode ->+                    main' setting postLoadMode units dflags argv3 flagWarnings          -- DAP Modified++main' :: GhciSettings -> PostLoadMode -> [String] -> DynFlags -> [Located String] -> [Warn]   -- DAP Modified+      -> Ghc ()+main' setting postLoadMode units dflags0 args flagWarnings = do                         -- DAP Modified+  let args' = case postLoadMode of+                DoRun -> takeWhile (\arg -> unLoc arg /= "--") args+                _     -> args++  -- set the default GhcMode, backend and GhcLink.  The backend+  -- can be further adjusted on a module by module basis, using only+  -- the -fllvm and -fasm flags.  If the default backend is not+  -- LLVM or NCG, -fllvm and -fasm have no effect.+  let dflt_backend = backend dflags0+      (mode, bcknd, link)+         = case postLoadMode of+               DoInteractive   -> (CompManager, interpreterBackend,  LinkInMemory)+               DoEval _        -> (CompManager, interpreterBackend,  LinkInMemory)+               DoRun           -> (CompManager, interpreterBackend,  LinkInMemory)+               DoMake          -> (CompManager, dflt_backend, LinkBinary)+               DoBackpack      -> (CompManager, dflt_backend, LinkBinary)+               DoMkDependHS    -> (MkDepend,    dflt_backend, LinkBinary)+               DoAbiHash       -> (OneShot,     dflt_backend, LinkBinary)+               _               -> (OneShot,     dflt_backend, LinkBinary)++  let dflags1 = dflags0{ ghcMode   = mode,+                         backend   = bcknd,+                         ghcLink   = link,+                         verbosity = case postLoadMode of+                                         DoEval _ -> 0+                                         DoRun    -> 0+                                         _other   -> 1+                        }++      -- turn on -fimplicit-import-qualified for GHCi now, so that it+      -- can be overridden from the command-line+      -- XXX: this should really be in the interactive DynFlags, but+      -- we don't set that until later in interactiveUI+      -- We also set -fignore-optim-changes and -fignore-hpc-changes,+      -- which are program-level options. Again, this doesn't really+      -- feel like the right place to handle this, but we don't have+      -- a great story for the moment.+      dflags2  | DoInteractive <- postLoadMode = def_ghci_flags+               | DoEval _      <- postLoadMode = def_ghci_flags+               | DoRun         <- postLoadMode = def_ghci_flags+               | otherwise                     = dflags1+        where def_ghci_flags = dflags1 `gopt_set` Opt_ImplicitImportQualified+                                       `gopt_set` Opt_IgnoreOptimChanges+                                       `gopt_set` Opt_IgnoreHpcChanges+                                       -- Setting this by default has the nice effect that+                                       -- -fno-code and --interactive falls back to interpreter rather than+                                       -- object code but has little other effect unless you are also using+                                       -- fat interface files.+                                       `gopt_set` Opt_UseBytecodeRatherThanObjects+                                       -- By default enable the debugger by inserting breakpoints+                                       `gopt_set` Opt_InsertBreakpoints++  logger1 <- getLogger+  let logger2 = setLogFlags logger1 (initLogFlags dflags2)++        -- The rest of the arguments are "dynamic"+        -- Leftover ones are presumably files+  (dflags3, fileish_args, dynamicFlagWarnings) <-+      GHC.parseDynamicFlags logger2 dflags2 args'++  let dflags4 = if backendNeedsFullWays bcknd &&+                   not (gopt Opt_ExternalInterpreter dflags3)+                then+                    let platform = targetPlatform dflags3+                        dflags3a = dflags3 { targetWays_ = hostFullWays }+                        dflags3b = foldl gopt_set dflags3a+                                 $ concatMap (wayGeneralFlags platform)+                                             hostFullWays+                        dflags3c = foldl gopt_unset dflags3b+                                 $ concatMap (wayUnsetGeneralFlags platform)+                                             hostFullWays+                    in dflags3c+                else+                    dflags3++  let logger4 = setLogFlags logger2 (initLogFlags dflags4)++  GHC.prettyPrintGhcErrors logger4 $ do++  let diag_opts = initDiagOpts dflags4+  let flagWarnings' = GhcDriverMessage <$> mconcat [warnsToMessages diag_opts flagWarnings, dynamicFlagWarnings]++  handleSourceError (\e -> do+       GHC.printException e+       liftIO $ exitWith (ExitFailure 1)) $ do+         liftIO $ printOrThrowDiagnostics logger4 (initPrintConfig dflags4) diag_opts flagWarnings'++  liftIO $ showBanner postLoadMode dflags4++  let (dflags5, srcs, objs) = parseTargetFiles dflags4 (map unLoc fileish_args)++  -- we've finished manipulating the DynFlags, update the session+  _ <- GHC.setSessionDynFlags dflags5+  dflags6 <- GHC.getSessionDynFlags++  -- Must do this before loading plugins+  liftIO $ initUniqSupply (initialUnique dflags6) (uniqueIncrement dflags6)++  -- Initialise plugins here because the plugin author might already expect this+  -- subsequent call to `getLogger` to be affected by a plugin.+  initializeSessionPlugins+  hsc_env <- getSession+  logger <- getLogger+++        ---------------- Display configuration -----------+  case verbosity dflags6 of+    v | v == 4 -> liftIO $ dumpUnitsSimple hsc_env+      | v >= 5 -> liftIO $ dumpUnits       hsc_env+      | otherwise -> return ()++        ---------------- Final sanity checking -----------+  liftIO $ checkOptions postLoadMode dflags6 srcs objs units++  ---------------- Do the business -----------+  handleSourceError (\e -> do+       GHC.printException e+       liftIO $ exitWith (ExitFailure 1)) $ do+    case postLoadMode of+       ShowInterface f        -> liftIO $ showIface logger+                                                    (hsc_dflags hsc_env)+                                                    (hsc_units  hsc_env)+                                                    (hsc_NC     hsc_env)+                                                    f+       DoMake                 -> doMake units srcs+       DoMkDependHS           -> doMkDependHS (map fst srcs)+       StopBefore p           -> liftIO (oneShot hsc_env p srcs)+       DoInteractive          -> ghciUI setting units srcs Nothing                       -- DAP Modified+       DoEval exprs           -> ghciUI setting units srcs $ Just $ reverse exprs        -- DAP Modified+       DoRun                  -> doRun setting units srcs args                           -- DAP Modified+       DoAbiHash              -> abiHash (map fst srcs)+       ShowPackages           -> liftIO $ showUnits hsc_env+       DoFrontend f           -> doFrontend f srcs+       DoBackpack             -> doBackpack (map fst srcs)++  liftIO $ dumpFinalStats logger++doRun :: GhciSettings -> [String] -> [(FilePath, Maybe Phase)] -> [Located String] -> Ghc ()    -- DAP Modified+doRun setting units srcs args = do+    dflags <- getDynFlags+    let mainFun = fromMaybe "main" (mainFunIs dflags)+    ghciUI setting units srcs (Just ["System.Environment.withArgs " ++ show args' ++ " (Control.Monad.void " ++ mainFun ++ ")"])  -- DAP Modified+  where+    args' = drop 1 $ dropWhile (/= "--") $ map unLoc args++ghciUI :: GhciSettings -> [String] -> [(FilePath, Maybe Phase)] -> Maybe [String] -> Ghc ()    -- DAP Modified+#if !defined(HAVE_INTERNAL_INTERPRETER)+ghciUI _ _ _ _ =        -- DAP Modified+  throwGhcException (CmdLineError "not built for interactive use")+#else+ghciUI st units srcs maybe_expr = do               -- DAP Modified+  hs_srcs <- case NE.nonEmpty units of+    Just ne_units -> do+      initMulti ne_units+    Nothing -> do+      case srcs of+        [] -> return []+        _  -> do+          s <- initMake srcs+          return $ map (uncurry (,Nothing,)) s+  interactiveUI st hs_srcs maybe_expr             -- DAP Modified+#endif+++-- -----------------------------------------------------------------------------+-- Option sanity checks++-- | Ensure sanity of options.+--+-- Throws 'UsageError' or 'CmdLineError' if not.+checkOptions :: PostLoadMode -> DynFlags -> [(String,Maybe Phase)] -> [String] -> [String] -> IO ()+     -- Final sanity checking before kicking off a compilation (pipeline).+checkOptions mode dflags srcs objs units = do+     -- Complain about any unknown flags+   let unknown_opts = [ f | (f@('-':_), _) <- srcs ]+   when (notNull unknown_opts) (unknownFlagsErr unknown_opts)++   when (not (Set.null (rtsWays (ways dflags)))+         && isInterpretiveMode mode) $+        hPutStrLn stderr ("Warning: -debug, -threaded and -ticky are ignored by GHCi")++        -- -prof and --interactive are not a good combination+   when ((fullWays (ways dflags) /= hostFullWays)+         && isInterpretiveMode mode+         && not (gopt Opt_ExternalInterpreter dflags)) $+      do throwGhcException (UsageError+              "-fexternal-interpreter is required when using --interactive with a non-standard way (-prof, -static, or -dynamic).")+        -- -ohi sanity check+   if (isJust (outputHi dflags) &&+      (isCompManagerMode mode || srcs `lengthExceeds` 1))+        then throwGhcException (UsageError "-ohi can only be used when compiling a single source file")+        else do++   if (isJust (dynOutputHi dflags) &&+      (isCompManagerMode mode || srcs `lengthExceeds` 1))+     then throwGhcException (UsageError "-dynohi can only be used when compiling a single source file")+     else do++        -- -o sanity checking+   if (srcs `lengthExceeds` 1 && isJust (outputFile dflags)+         && not (isLinkMode mode))+        then throwGhcException (UsageError "can't apply -o to multiple source files")+        else do++   let not_linking = not (isLinkMode mode) || isNoLink (ghcLink dflags)++   when (not_linking && not (null objs)) $+        hPutStrLn stderr ("Warning: the following files would be used as linker inputs, but linking is not being done: " ++ unwords objs)++        -- Check that there are some input files+        -- (except in the interactive case)+   if null srcs && (null objs || not_linking) && needsInputsMode mode && null units+        then throwGhcException (UsageError "no input files" )+        else do++   case mode of+      StopBefore StopC | not (backendGeneratesHc (backend dflags))+        -> throwGhcException $ UsageError $+           "the option -C is only available with an unregisterised GHC"+      StopBefore StopAs | ghcLink dflags == NoLink+        -> throwGhcException $ UsageError $+           "the options -S and -fno-code are incompatible. Please omit -S"++      _ -> return ()++     -- Verify that output files point somewhere sensible.+   verifyOutputFiles dflags++-- Compiler output options++-- Called to verify that the output files point somewhere valid.+--+-- The assumption is that the directory portion of these output+-- options will have to exist by the time 'verifyOutputFiles'+-- is invoked.+--+-- We create the directories for -odir, -hidir, -outputdir etc. ourselves if+-- they don't exist, so don't check for those here (#2278).+verifyOutputFiles :: DynFlags -> IO ()+verifyOutputFiles dflags = do+  let ofile = outputFile dflags+  when (isJust ofile) $ do+     let fn = fromJust ofile+     flg <- doesDirNameExist fn+     when (not flg) (nonExistentDir "-o" fn)+  let ohi = outputHi dflags+  when (isJust ohi) $ do+     let hi = fromJust ohi+     flg <- doesDirNameExist hi+     when (not flg) (nonExistentDir "-ohi" hi)+ where+   nonExistentDir flg dir =+     throwGhcException (CmdLineError ("error: directory portion of " +++                             show dir ++ " does not exist (used with " +++                             show flg ++ " option.)"))++-----------------------------------------------------------------------------+-- GHC modes of operation++type Mode = Either PreStartupMode PostStartupMode+type PostStartupMode = Either PreLoadMode PostLoadMode++data PreStartupMode+  = ShowVersion                          -- ghc -V/--version+  | ShowNumVersion                       -- ghc --numeric-version+  | ShowSupportedExtensions              -- ghc --supported-extensions+  | ShowOptions Bool {- isInteractive -} -- ghc --show-options++showVersionMode, showNumVersionMode, showSupportedExtensionsMode, showOptionsMode :: Mode+showVersionMode             = mkPreStartupMode ShowVersion+showNumVersionMode          = mkPreStartupMode ShowNumVersion+showSupportedExtensionsMode = mkPreStartupMode ShowSupportedExtensions+showOptionsMode             = mkPreStartupMode (ShowOptions False)++mkPreStartupMode :: PreStartupMode -> Mode+mkPreStartupMode = Left++isShowVersionMode :: Mode -> Bool+isShowVersionMode (Left ShowVersion) = True+isShowVersionMode _ = False++isShowNumVersionMode :: Mode -> Bool+isShowNumVersionMode (Left ShowNumVersion) = True+isShowNumVersionMode _ = False++data PreLoadMode+  = ShowGhcUsage                           -- ghc -?+  | ShowGhciUsage                          -- ghci -?+  | ShowInfo                               -- ghc --info+  | PrintWithDynFlags (DynFlags -> String) -- ghc --print-foo++showGhcUsageMode, showGhciUsageMode, showInfoMode :: Mode+showGhcUsageMode = mkPreLoadMode ShowGhcUsage+showGhciUsageMode = mkPreLoadMode ShowGhciUsage+showInfoMode = mkPreLoadMode ShowInfo++printSetting :: String -> Mode+printSetting k = mkPreLoadMode (PrintWithDynFlags f)+    where f dflags = fromMaybe (panic ("Setting not found: " ++ show k))+                   $ lookup k (compilerInfo dflags)++mkPreLoadMode :: PreLoadMode -> Mode+mkPreLoadMode = Right . Left++isShowGhcUsageMode :: Mode -> Bool+isShowGhcUsageMode (Right (Left ShowGhcUsage)) = True+isShowGhcUsageMode _ = False++isShowGhciUsageMode :: Mode -> Bool+isShowGhciUsageMode (Right (Left ShowGhciUsage)) = True+isShowGhciUsageMode _ = False++data PostLoadMode+  = ShowInterface FilePath  -- ghc --show-iface+  | DoMkDependHS            -- ghc -M+  | StopBefore StopPhase    -- ghc -E | -C | -S+                            -- StopBefore StopLn is the default+  | DoMake                  -- ghc --make+  | DoBackpack              -- ghc --backpack foo.bkp+  | DoInteractive           -- ghc --interactive+  | DoEval [String]         -- ghc -e foo -e bar => DoEval ["bar", "foo"]+  | DoRun                   -- ghc --run+  | DoAbiHash               -- ghc --abi-hash+  | ShowPackages            -- ghc --show-packages+  | DoFrontend ModuleName   -- ghc --frontend Plugin.Module++doMkDependHSMode, doMakeMode, doInteractiveMode, doRunMode,+  doAbiHashMode, showUnitsMode :: Mode+doMkDependHSMode = mkPostLoadMode DoMkDependHS+doMakeMode = mkPostLoadMode DoMake+doInteractiveMode = mkPostLoadMode DoInteractive+doRunMode = mkPostLoadMode DoRun+doAbiHashMode = mkPostLoadMode DoAbiHash+showUnitsMode = mkPostLoadMode ShowPackages++showInterfaceMode :: FilePath -> Mode+showInterfaceMode fp = mkPostLoadMode (ShowInterface fp)++stopBeforeMode :: StopPhase -> Mode+stopBeforeMode phase = mkPostLoadMode (StopBefore phase)++doEvalMode :: String -> Mode+doEvalMode str = mkPostLoadMode (DoEval [str])++doFrontendMode :: String -> Mode+doFrontendMode str = mkPostLoadMode (DoFrontend (mkModuleName str))++doBackpackMode :: Mode+doBackpackMode = mkPostLoadMode DoBackpack++mkPostLoadMode :: PostLoadMode -> Mode+mkPostLoadMode = Right . Right++isDoInteractiveMode :: Mode -> Bool+isDoInteractiveMode (Right (Right DoInteractive)) = True+isDoInteractiveMode _ = False++isStopLnMode :: Mode -> Bool+isStopLnMode (Right (Right (StopBefore NoStop))) = True+isStopLnMode _ = False++isDoMakeMode :: Mode -> Bool+isDoMakeMode (Right (Right DoMake)) = True+isDoMakeMode _ = False++isDoEvalMode :: Mode -> Bool+isDoEvalMode (Right (Right (DoEval _))) = True+isDoEvalMode _ = False++#if defined(HAVE_INTERNAL_INTERPRETER)+isInteractiveMode :: PostLoadMode -> Bool+isInteractiveMode DoInteractive = True+isInteractiveMode _             = False+#endif++-- isInterpretiveMode: byte-code compiler involved+isInterpretiveMode :: PostLoadMode -> Bool+isInterpretiveMode DoInteractive = True+isInterpretiveMode (DoEval _)    = True+isInterpretiveMode _             = False++needsInputsMode :: PostLoadMode -> Bool+needsInputsMode DoMkDependHS    = True+needsInputsMode (StopBefore _)  = True+needsInputsMode DoMake          = True+needsInputsMode _               = False++-- True if we are going to attempt to link in this mode.+-- (we might not actually link, depending on the GhcLink flag)+isLinkMode :: PostLoadMode -> Bool+isLinkMode (StopBefore NoStop) = True+isLinkMode DoMake              = True+isLinkMode DoRun               = True+isLinkMode DoInteractive       = True+isLinkMode (DoEval _)          = True+isLinkMode _                   = False++isCompManagerMode :: PostLoadMode -> Bool+isCompManagerMode DoRun         = True+isCompManagerMode DoMake        = True+isCompManagerMode DoInteractive = True+isCompManagerMode (DoEval _)    = True+isCompManagerMode _             = False++-- -----------------------------------------------------------------------------+-- Parsing the mode flag++parseModeFlags :: [Located String]+               -> IO (Mode, [String],+                      [Located String],+                      [Warn])+parseModeFlags args = do+  ((leftover, errs1, warns), (mModeFlag, units, errs2, flags')) <-+        processCmdLineP mode_flags (Nothing, [], [], []) args+  let mode = case mModeFlag of+             Nothing     -> doMakeMode+             Just (m, _) -> m++  -- See Note [Handling errors when parsing command-line flags]+  unless (null errs1 && null errs2) $ throwGhcException $ errorsToGhcException $+      map (("on the commandline", )) $ map (unLoc . errMsg) errs1 ++ errs2++  return (mode, units, flags' ++ leftover, warns)++type ModeM = CmdLineP (Maybe (Mode, String), [String], [String], [Located String])+  -- mode flags sometimes give rise to new DynFlags (eg. -C, see below)+  -- so we collect the new ones and return them.++mode_flags :: [Flag ModeM]+mode_flags =+  [  ------- help / version ----------------------------------------------+    defFlag "?"                     (PassFlag (setMode showGhcUsageMode))+  , defFlag "-help"                 (PassFlag (setMode showGhcUsageMode))+  , defFlag "V"                     (PassFlag (setMode showVersionMode))+  , defFlag "-version"              (PassFlag (setMode showVersionMode))+  , defFlag "-numeric-version"      (PassFlag (setMode showNumVersionMode))+  , defFlag "-info"                 (PassFlag (setMode showInfoMode))+  , defFlag "-show-options"         (PassFlag (setMode showOptionsMode))+  , defFlag "-supported-languages"  (PassFlag (setMode showSupportedExtensionsMode))+  , defFlag "-supported-extensions" (PassFlag (setMode showSupportedExtensionsMode))+  , defFlag "-show-packages"        (PassFlag (setMode showUnitsMode))+  ] +++  [ defFlag k'                      (PassFlag (setMode (printSetting k)))+  | k <- ["Project version",+          "Project Git commit id",+          "Booter version",+          "Stage",+          "Build platform",+          "Host platform",+          "Target platform",+          "Have interpreter",+          "Object splitting supported",+          "Have native code generator",+          "Support SMP",+          "Unregisterised",+          "Tables next to code",+          "RTS ways",+          "Leading underscore",+          "Debug on",+          "LibDir",+          "Global Package DB",+          "C compiler flags",+          "C compiler link flags"+          ],+    let k' = "-print-" ++ map (replaceSpace . toLower) k+        replaceSpace ' ' = '-'+        replaceSpace c   = c+  ] +++      ------- interfaces ----------------------------------------------------+  [ defFlag "-show-iface"  (HasArg (\f -> setMode (showInterfaceMode f)+                                               "--show-iface"))++      ------- primary modes ------------------------------------------------+  , defFlag "c"            (PassFlag (\f -> do setMode (stopBeforeMode NoStop) f+                                               addFlag "-no-link" f))+  , defFlag "M"            (PassFlag (setMode doMkDependHSMode))+  , defFlag "E"            (PassFlag (setMode (stopBeforeMode StopPreprocess )))+  , defFlag "C"            (PassFlag (setMode (stopBeforeMode StopC)))+  , defFlag "S"            (PassFlag (setMode (stopBeforeMode StopAs)))+  , defFlag "-run"         (PassFlag (setMode doRunMode))+  , defFlag "-make"        (PassFlag (setMode doMakeMode))+  , defFlag "unit"         (SepArg   (\s -> addUnit s "-unit"))+  , defFlag "-backpack"    (PassFlag (setMode doBackpackMode))+  , defFlag "-interactive" (PassFlag (setMode doInteractiveMode))+  , defFlag "-abi-hash"    (PassFlag (setMode doAbiHashMode))+  , defFlag "e"            (SepArg   (\s -> setMode (doEvalMode s) "-e"))+  , defFlag "-frontend"    (SepArg   (\s -> setMode (doFrontendMode s) "-frontend"))+  ]++addUnit :: String -> String -> EwM ModeM ()+addUnit unit_str _arg = liftEwM $ do+  (mModeFlag, units, errs, flags') <- getCmdLineState+  putCmdLineState (mModeFlag, unit_str:units, errs, flags')++setMode :: Mode -> String -> EwM ModeM ()+setMode newMode newFlag = liftEwM $ do+    (mModeFlag, units, errs, flags') <- getCmdLineState+    let (modeFlag', errs') =+            case mModeFlag of+            Nothing -> ((newMode, newFlag), errs)+            Just (oldMode, oldFlag) ->+                case (oldMode, newMode) of+                    -- -c/--make are allowed together, and mean --make -no-link+                    _ |  isStopLnMode oldMode && isDoMakeMode newMode+                      || isStopLnMode newMode && isDoMakeMode oldMode ->+                      ((doMakeMode, "--make"), [])++                    -- If we have both --help and --interactive then we+                    -- want showGhciUsage+                    _ | isShowGhcUsageMode oldMode &&+                        isDoInteractiveMode newMode ->+                            ((showGhciUsageMode, oldFlag), [])+                      | isShowGhcUsageMode newMode &&+                        isDoInteractiveMode oldMode ->+                            ((showGhciUsageMode, newFlag), [])++                    -- If we have both -e and --interactive then -e always wins+                    _ | isDoEvalMode oldMode &&+                        isDoInteractiveMode newMode ->+                            ((oldMode, oldFlag), [])+                      | isDoEvalMode newMode &&+                        isDoInteractiveMode oldMode ->+                            ((newMode, newFlag), [])++                    -- Otherwise, --help/--version/--numeric-version always win+                      | isDominantFlag oldMode -> ((oldMode, oldFlag), [])+                      | isDominantFlag newMode -> ((newMode, newFlag), [])+                    -- We need to accumulate eval flags like "-e foo -e bar"+                    (Right (Right (DoEval esOld)),+                     Right (Right (DoEval [eNew]))) ->+                        ((Right (Right (DoEval (eNew : esOld))), oldFlag),+                         errs)+                    -- Saying e.g. --interactive --interactive is OK+                    _ | oldFlag == newFlag -> ((oldMode, oldFlag), errs)++                    -- --interactive and --show-options are used together+                    (Right (Right DoInteractive), Left (ShowOptions _)) ->+                      ((Left (ShowOptions True),+                        "--interactive --show-options"), errs)+                    (Left (ShowOptions _), (Right (Right DoInteractive))) ->+                      ((Left (ShowOptions True),+                        "--show-options --interactive"), errs)+                    -- Otherwise, complain+                    _ -> let err = flagMismatchErr oldFlag newFlag+                         in ((oldMode, oldFlag), err : errs)+    putCmdLineState (Just modeFlag', units, errs', flags')+  where isDominantFlag f = isShowGhcUsageMode   f ||+                           isShowGhciUsageMode  f ||+                           isShowVersionMode    f ||+                           isShowNumVersionMode f++flagMismatchErr :: String -> String -> String+flagMismatchErr oldFlag newFlag+    = "cannot use `" ++ oldFlag ++  "' with `" ++ newFlag ++ "'"++addFlag :: String -> String -> EwM ModeM ()+addFlag s flag = liftEwM $ do+  (m, units, e, flags') <- getCmdLineState+  putCmdLineState (m, units, e, mkGeneralLocated loc s : flags')+    where loc = "addFlag by " ++ flag ++ " on the commandline"++-- ----------------------------------------------------------------------------+-- Run --make mode++doMake :: [String] -> [(String, Maybe Phase)] -> Ghc ()+doMake units targets = do+  hs_srcs <- case NE.nonEmpty units of+    Just ne_units -> do+      initMulti ne_units+    Nothing -> do+      s <- initMake targets+      return $ map (uncurry (,Nothing,)) s+  case hs_srcs of+    [] -> return ()+    _  -> do+      targets' <- mapM (\(src, uid, phase) -> GHC.guessTarget src uid phase) hs_srcs+      GHC.setTargets targets'+      ok_flag <- GHC.load LoadAllTargets+      when (failed ok_flag) (liftIO $ exitWith (ExitFailure 1))++initMake :: [(String,Maybe Phase)] -> Ghc [(String, Maybe Phase)]+initMake srcs  = do+    let (hs_srcs, non_hs_srcs) = partition isHaskellishTarget srcs++    hsc_env <- GHC.getSession++    -- if we have no haskell sources from which to do a dependency+    -- analysis, then just do one-shot compilation and/or linking.+    -- This means that "ghc Foo.o Bar.o -o baz" links the program as+    -- we expect.+    if (null hs_srcs)+       then liftIO (oneShot hsc_env NoStop srcs) >> return []+       else do++    o_files <- mapMaybeM (\x -> liftIO $ compileFile hsc_env NoStop x)+                 non_hs_srcs+    dflags <- GHC.getSessionDynFlags+    let dflags' = dflags { ldInputs = map (FileOption "") o_files+                                      ++ ldInputs dflags }+    _ <- GHC.setSessionDynFlags dflags'+    return hs_srcs++-- Strip out any ["+RTS", ..., "-RTS"] sequences in the command string list.+removeRTS :: [String] -> [String]+removeRTS ("+RTS" : xs)  =+  case dropWhile (/= "-RTS") xs of+    [] -> []+    (_ : ys) -> removeRTS ys+removeRTS (y:ys)         = y : removeRTS ys+removeRTS []             = []++initMulti :: NE.NonEmpty String -> Ghc ([(String, Maybe UnitId, Maybe Phase)])+initMulti unitArgsFiles  = do+  hsc_env <- GHC.getSession+  let logger = hsc_logger hsc_env+  initial_dflags <- GHC.getSessionDynFlags++  dynFlagsAndSrcs <- forM unitArgsFiles $ \f -> do+    when (verbosity initial_dflags > 2) (liftIO $ print f)+    args <- liftIO $ expandResponse [f]+    (dflags2, fileish_args, warns) <- parseDynamicFlagsCmdLine initial_dflags (map (mkGeneralLocated f) (removeRTS args))+    handleSourceError (\e -> do+       GHC.printException e+       liftIO $ exitWith (ExitFailure 1)) $ do+         liftIO $ printOrThrowDiagnostics logger (initPrintConfig dflags2) (initDiagOpts dflags2) (GhcDriverMessage <$> warns)++    let (dflags3, srcs, objs) = parseTargetFiles dflags2 (map unLoc fileish_args)+        dflags4 = offsetDynFlags dflags3++    let (hs_srcs, non_hs_srcs) = partition isHaskellishTarget srcs++    -- This is dubious as the whole unit environment won't be set-up correctly, but+    -- that doesn't matter for what we use it for (linking and oneShot)+    let dubious_hsc_env = hscSetFlags dflags4 hsc_env+    -- if we have no haskell sources from which to do a dependency+    -- analysis, then just do one-shot compilation and/or linking.+    -- This means that "ghc Foo.o Bar.o -o baz" links the program as+    -- we expect.+    if (null hs_srcs)+       then liftIO (oneShot dubious_hsc_env NoStop srcs) >> return (dflags4, [])+       else do++    o_files <- mapMaybeM (\x -> liftIO $ compileFile dubious_hsc_env NoStop x)+                 non_hs_srcs+    let dflags5 = dflags4 { ldInputs = map (FileOption "") o_files+                                      ++ ldInputs dflags4 }++    liftIO $ checkOptions DoMake dflags5 srcs objs []++    pure (dflags5, hs_srcs)++  let+    unitDflags = NE.map fst dynFlagsAndSrcs+    srcs = NE.map (\(dflags, lsrcs) -> map (uncurry (,Just $ homeUnitId_ dflags,)) lsrcs) dynFlagsAndSrcs+    (hs_srcs, _non_hs_srcs) = unzip (map (partition (\(file, _uid, phase) -> isHaskellishTarget (file, phase))) (NE.toList srcs))++  checkDuplicateUnits initial_dflags (NE.toList (NE.zip unitArgsFiles unitDflags))++  let (initial_home_graph, mainUnitId) = createUnitEnvFromFlags unitDflags+      home_units = unitEnv_keys initial_home_graph++  home_unit_graph <- forM initial_home_graph $ \homeUnitEnv -> do+    let cached_unit_dbs = homeUnitEnv_unit_dbs homeUnitEnv+        hue_flags = homeUnitEnv_dflags homeUnitEnv+        dflags = homeUnitEnv_dflags homeUnitEnv+    (dbs,unit_state,home_unit,mconstants) <- liftIO $ State.initUnits logger hue_flags cached_unit_dbs home_units++    updated_dflags <- liftIO $ updatePlatformConstants dflags mconstants+    pure $ HomeUnitEnv+      { homeUnitEnv_units = unit_state+      , homeUnitEnv_unit_dbs = Just dbs+      , homeUnitEnv_dflags = updated_dflags+      , homeUnitEnv_hpt = emptyHomePackageTable+      , homeUnitEnv_home_unit = Just home_unit+      }++  checkUnitCycles initial_dflags home_unit_graph++  let dflags = homeUnitEnv_dflags $ unitEnv_lookup mainUnitId home_unit_graph+  unitEnv <- assertUnitEnvInvariant <$> (liftIO $ initUnitEnv mainUnitId home_unit_graph (ghcNameVersion dflags) (targetPlatform dflags))+  let final_hsc_env = hsc_env { hsc_unit_env = unitEnv }++  GHC.setSession final_hsc_env++  -- if we have no haskell sources from which to do a dependency+  -- analysis, then just do one-shot compilation and/or linking.+  -- This means that "ghc Foo.o Bar.o -o baz" links the program as+  -- we expect.+  if (null hs_srcs)+      then do+        liftIO $ hPutStrLn stderr $ "Multi Mode can not be used for one-shot mode."+        liftIO $ exitWith (ExitFailure 1)+      else do++{-+  o_files <- liftIO $ mapMaybeM+                (\(src, uid, mphase) ->+                  compileFile (hscSetActiveHomeUnit (ue_unitHomeUnit (fromJust uid) unitEnv) final_hsc_env) NoStop (src, mphase)+                )+                (concat non_hs_srcs)+                -}++  -- MP: This should probably modify dflags for each unit?+  --let dflags' = dflags { ldInputs = map (FileOption "") o_files+  --                                  ++ ldInputs dflags }+  return $ concat hs_srcs++-- | Check that we don't have multiple units with the same UnitId.++checkUnitCycles :: DynFlags -> UnitEnvGraph HomeUnitEnv -> Ghc ()+checkUnitCycles dflags graph = processSCCs sccs+  where+    mkNode :: (UnitId, HomeUnitEnv) -> Node UnitId UnitId+    mkNode (uid, hue) = DigraphNode uid uid (homeUnitDepends (homeUnitEnv_units hue))+    nodes = map mkNode (unitEnv_elts graph)++    sccs = stronglyConnCompFromEdgedVerticesOrd nodes++    processSCCs [] = return ()+    processSCCs (AcyclicSCC _: other_sccs) = processSCCs other_sccs+    processSCCs (CyclicSCC uids: _) = throwGhcException $ CmdLineError $ showSDoc dflags (cycle_err uids)+++    cycle_err uids =+      hang (text "Units form a dependency cycle:")+           2+           (one_err uids)++    one_err uids = vcat $+                    (map (\uid -> text "-" <+> ppr uid <+> text "depends on") start)+                    ++ [text "-" <+> ppr final]+      where+        start = init uids+        final = last uids++checkDuplicateUnits :: DynFlags -> [(FilePath, DynFlags)] -> Ghc ()+checkDuplicateUnits dflags flags =+  unless (null duplicate_ids)+         (throwGhcException $ CmdLineError $ showSDoc dflags multi_err)++  where+    uids = map (second homeUnitId_) flags+    deduplicated_uids = ordNubOn snd uids+    duplicate_ids = Set.fromList (map snd uids \\ map snd deduplicated_uids)++    duplicate_flags = filter (flip Set.member duplicate_ids . snd) uids++    one_err (fp, home_uid) = text "-" <+> ppr home_uid <+> text "defined in" <+> text fp++    multi_err =+      hang (text "Multiple units with the same unit-id:")+           2+           (vcat (map one_err duplicate_flags))+++offsetDynFlags :: DynFlags -> DynFlags+offsetDynFlags dflags =+  dflags { hiDir = c hiDir+         , objectDir  = c objectDir+         , stubDir = c stubDir+         , hieDir  = c hieDir+         , dumpDir = c dumpDir  }++  where+    c f = augment_maybe (f dflags)++    augment_maybe Nothing = Nothing+    augment_maybe (Just f) = Just (augment f)+    augment f | isRelative f, Just offset <- workingDirectory dflags = offset </> f+              | otherwise = f+++createUnitEnvFromFlags :: NE.NonEmpty DynFlags -> (HomeUnitGraph, UnitId)+createUnitEnvFromFlags unitDflags =+  let+    newInternalUnitEnv dflags = mkHomeUnitEnv dflags emptyHomePackageTable Nothing+    unitEnvList = NE.map (\dflags -> (homeUnitId_ dflags, newInternalUnitEnv dflags)) unitDflags+    activeUnit = fst $ NE.head unitEnvList+  in+    (unitEnv_new (Map.fromList (NE.toList (unitEnvList))), activeUnit)++-- ---------------------------------------------------------------------------+-- Various banners and verbosity output.++showBanner :: PostLoadMode -> DynFlags -> IO ()+showBanner _postLoadMode dflags = do+   let verb = verbosity dflags++#if defined(HAVE_INTERNAL_INTERPRETER)+   -- Show the GHCi banner+   when (isInteractiveMode _postLoadMode && verb >= 1) $ putStrLn ghciWelcomeMsg+#endif++   -- Display details of the configuration in verbose mode+   when (verb >= 2) $+    do hPutStr stderr "Glasgow Haskell Compiler, Version "+       hPutStr stderr cProjectVersion+       hPutStr stderr ", stage "+       hPutStr stderr cStage+       hPutStr stderr " booted by GHC version "+       hPutStrLn stderr cBooterVersion++-- We print out a Read-friendly string, but a prettier one than the+-- Show instance gives us+showInfo :: DynFlags -> IO ()+showInfo dflags = do+        let sq x = " [" ++ x ++ "\n ]"+        putStrLn $ sq $ intercalate "\n ," $ map show $ compilerInfo dflags++-- TODO use GHC.Utils.Error once that is disentangled from all the other GhcMonad stuff?+showSupportedExtensions :: Maybe String -> IO ()+showSupportedExtensions m_top_dir = do+  res <- runExceptT $ do+    top_dir <- lift (tryFindTopDir m_top_dir) >>= \case+      Nothing -> throwE $ SettingsError_MissingData "Could not find the top directory, missing -B flag"+      Just dir -> pure dir+    initSettings top_dir+  arch_os <- case res of+    Right s -> pure $ platformArchOS $ sTargetPlatform s+    Left (SettingsError_MissingData msg) -> do+      hPutStrLn stderr $ "WARNING: " ++ show msg+      hPutStrLn stderr $ "cannot know target platform so guessing target == host (native compiler)."+      pure hostPlatformArchOS+    Left (SettingsError_BadData msg) -> do+      hPutStrLn stderr msg+      exitWith $ ExitFailure 1+  mapM_ putStrLn $ supportedLanguagesAndExtensions arch_os++showVersion :: IO ()+showVersion = putStrLn (cProjectName ++ ", version " ++ cProjectVersion)++showOptions :: Bool -> IO ()+showOptions isInteractive = putStr (unlines availableOptions)+    where+      availableOptions = concat [+        flagsForCompletion isInteractive,+        map ('-':) (getFlagNames mode_flags)+        ]+      getFlagNames opts         = map flagName opts++showGhcUsage :: DynFlags -> IO ()+showGhcUsage = showUsage False++showGhciUsage :: DynFlags -> IO ()+showGhciUsage = showUsage True++showUsage :: Bool -> DynFlags -> IO ()+showUsage ghci dflags = do+  let usage_path = if ghci then ghciUsagePath dflags+                           else ghcUsagePath dflags+  usage <- readFile usage_path+  progName <- getProgName+  dump progName usage+  where+    dump progName xs = case xs of+      ""        -> return ()+      '$':'$':s -> putStr progName >> dump progName s+      c:s       -> putChar c >> dump progName s++dumpFinalStats :: Logger -> IO ()+dumpFinalStats logger = do+  when (logHasDumpFlag logger Opt_D_faststring_stats) $ dumpFastStringStats logger++  when (logHasDumpFlag logger Opt_D_dump_faststrings) $ do+    fss <- getFastStringTable+    let ppr_table         = fmap ppr_segment (fss `zip` [0..])+        ppr_segment (s,n) = hang (text "Segment" <+> int n) 2 (vcat (fmap ppr_bucket (s `zip` [0..])))+        ppr_bucket  (b,n) = hang (text "Bucket" <+> int n) 2 (vcat (fmap ftext b))+    putDumpFileMaybe logger Opt_D_dump_faststrings "FastStrings" FormatText (vcat ppr_table)++dumpFastStringStats :: Logger -> IO ()+dumpFastStringStats logger = do+  segments <- getFastStringTable+  hasZ <- getFastStringZEncCounter+  let buckets = concat segments+      bucketsPerSegment = map length segments+      entriesPerBucket = map length buckets+      entries = sum entriesPerBucket+      msg = text "FastString stats:" $$ nest 4 (vcat+        [ text "segments:         " <+> int (length segments)+        , text "buckets:          " <+> int (sum bucketsPerSegment)+        , text "entries:          " <+> int entries+        , text "largest segment:  " <+> int (maximum bucketsPerSegment)+        , text "smallest segment: " <+> int (minimum bucketsPerSegment)+        , text "longest bucket:   " <+> int (maximum entriesPerBucket)+        , text "has z-encoding:   " <+> (hasZ `pcntOf` entries)+        ])+        -- we usually get more "has z-encoding" than "z-encoded", because+        -- when we z-encode a string it might hash to the exact same string,+        -- which is not counted as "z-encoded".  Only strings whose+        -- Z-encoding is different from the original string are counted in+        -- the "z-encoded" total.+  putMsg logger msg+  where+   x `pcntOf` y = int ((x * 100) `quot` y) Outputable.<> char '%'++showUnits, dumpUnits, dumpUnitsSimple :: HscEnv -> IO ()+showUnits       hsc_env = putStrLn (showSDoc (hsc_dflags hsc_env) (pprUnits (hsc_units hsc_env)))+dumpUnits       hsc_env = putMsg (hsc_logger hsc_env) (pprUnits (hsc_units hsc_env))+dumpUnitsSimple hsc_env = putMsg (hsc_logger hsc_env) (pprUnitsSimple (hsc_units hsc_env))++-- -----------------------------------------------------------------------------+-- Frontend plugin support++doFrontend :: ModuleName -> [(String, Maybe Phase)] -> Ghc ()+doFrontend modname srcs = do+    hsc_env <- getSession+    (frontend_plugin, _pkgs, _deps) <- liftIO $ loadFrontendPlugin hsc_env modname -- TODO do these need to recorded?+    frontend frontend_plugin+      (reverse $ frontendPluginOpts (hsc_dflags hsc_env)) srcs++-- -----------------------------------------------------------------------------+-- ABI hash support++{-+        ghc --abi-hash Data.Foo System.Bar++Generates a combined hash of the ABI for modules Data.Foo and+System.Bar.  The modules must already be compiled, and appropriate -i+options may be necessary in order to find the .hi files.++This is used by Cabal for generating the ComponentId for a+package.  The ComponentId must change when the visible ABI of+the package changes, so during registration Cabal calls ghc --abi-hash+to get a hash of the package's ABI.+-}++-- | Print ABI hash of input modules.+--+-- The resulting hash is the MD5 of the GHC version used (#5328,+-- see 'hiVersion') and of the existing ABI hash from each module (see+-- 'mi_mod_hash').+abiHash :: [String] -- ^ List of module names+        -> Ghc ()+abiHash strs = do+  hsc_env <- getSession+  let dflags    = hsc_dflags hsc_env++  liftIO $ do++  let find_it str = do+         let modname = mkModuleName str+         r <- findImportedModule hsc_env modname NoPkgQual+         case r of+           Found _ m -> return m+           _error    ->+            let opts   = initIfaceMessageOpts dflags+                err_txt = missingInterfaceErrorDiagnostic opts+                        $ cannotFindModule hsc_env modname r+            in throwGhcException . CmdLineError $ showSDoc dflags err_txt++  mods <- mapM find_it strs++  let get_iface modl = loadUserInterface NotBoot (text "abiHash") modl+  ifaces <- initIfaceCheck (text "abiHash") hsc_env $ mapM get_iface mods++  bh <- openBinMem (3*1024) -- just less than a block+  put_ bh hiVersion+    -- package hashes change when the compiler version changes (for now)+    -- see #5328+  mapM_ (put_ bh . mi_mod_hash . mi_final_exts) ifaces+  f <- fingerprintBinMem bh++  putStrLn (showPpr dflags f)++-- -----------------------------------------------------------------------------+-- Util++unknownFlagsErr :: [String] -> a+unknownFlagsErr fs = throwGhcException $ UsageError $ concatMap oneError fs+  where+    oneError f =+        "unrecognised flag: " ++ f ++ "\n" +++        (case flagSuggestions (nubSort allNonDeprecatedFlags) f of+            [] -> ""+            suggs -> "did you mean one of:\n" ++ unlines (map ("  " ++) suggs))
+ app-ghc-9.10/GHCi/GhcApiCompat.hs view
@@ -0,0 +1,84 @@+module GHCi.GhcApiCompat (+    module GHC.Runtime.Heap.Inspect+  , module GHC.Unit+  , module GHC.Driver.Monad+  , module GHC.Unit.Module+  , module GHC.Utils.Outputable+  , module GHC.Utils.Exception+  , module GHC.Runtime.Debugger+  , module GHC.Data.FastString+  , module GHC.Runtime.Eval.Types+  , module GHC.Core.DataCon+  , module GHC.Types.TyThing.Ppr+  , module GHC.Driver.Session+  , module GHC.Types.Name.Reader+  , module GHC.Types.SourceError+  , module GHC.Driver.Ppr+  , module GHC.Types.TyThing+  , module GHC.Unit.Module.ModSummary+  , module GHC.Driver.Env.Types+  , module GHC.Runtime.Context+  , module GHC.Types.BreakInfo+  , module GHC.Types.FieldLabel+  , CMC.catch+  , pprTypeForUser+  , ic_rn_gbl_env+  , parseName+  , fls2fs+) where++import GHC.Runtime.Heap.Inspect+import GHC.Unit+import GHC.Driver.Monad+import GHC.Unit.Module+import GHC.Utils.Outputable+import GHC.Utils.Exception hiding (catch)+import GHC.Runtime.Debugger+import GHC.Data.FastString+import GHC.Runtime.Eval.Types+import GHC.Core.DataCon+import GHC.Types.TyThing.Ppr+import GHC.Driver.Session+import GHC.Types.Name.Reader+import GHC.Types.SourceError+import GHC.Driver.Ppr+import GHC.Types.TyThing+import GHC.Unit.Module.ModSummary+import GHC.Driver.Env.Types+import GHC.Runtime.Context+import GHC.Types.BreakInfo+import GHC.Core.TyCo.Ppr+import GHC.Core.Type+import GHC.Types.FieldLabel+import GHC.Plugins+import qualified Control.Monad.Catch as CMC+import qualified GHC.Runtime.Eval as E+import qualified Data.List.NonEmpty as N+import Language.Haskell.Syntax.Basic++-- |+--+--+pprTypeForUser :: Type -> SDoc+pprTypeForUser = pprSigmaType++-- |+--+--+ic_rn_gbl_env :: InteractiveContext -> GlobalRdrEnv+ic_rn_gbl_env = igre_env . ic_gre_cache++-- |+--+--+parseName :: GhcMonad m => String -> m [Name]+parseName s = do+  nel <- E.parseName s+  return $ N.toList nel+++-- |+--+--+fls2fs :: FieldLabelString -> FastString+fls2fs (FieldLabelString v) = v
+ app-ghc-9.10/GHCi/Leak.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE RecordWildCards, LambdaCase #-}+module GHCi.Leak+  ( LeakIndicators+  , getLeakIndicators+  , checkLeakIndicators+  ) where++import Control.Monad+import Data.Bits+import Foreign.Ptr (ptrToIntPtr, intPtrToPtr)+import GHC+import GHC.Ptr (Ptr (..))+import GHCi.Util+import GHC.Driver.Env+import GHC.Driver.Ppr+import GHC.Utils.Outputable+import GHC.Unit.Module.ModDetails+import GHC.Unit.Home.ModInfo+import GHC.Platform (target32Bit)+import GHC.Linker.Types+import Prelude+import System.Mem+import System.Mem.Weak+import GHC.Types.Unique.DFM+import Control.Exception++-- Checking for space leaks in GHCi. See #15111, and the+-- -fghci-leak-check flag.++data LeakIndicators = LeakIndicators [LeakModIndicators]++data LeakModIndicators = LeakModIndicators+  { leakMod :: Weak HomeModInfo+  , leakIface :: Weak ModIface+  , leakDetails :: Weak ModDetails+  , leakLinkable :: [Maybe (Weak Linkable)]+  }++-- | Grab weak references to some of the data structures representing+-- the currently loaded modules.+getLeakIndicators :: HscEnv -> IO LeakIndicators+getLeakIndicators hsc_env =+  fmap LeakIndicators $+    forM (eltsUDFM (hsc_HPT hsc_env)) $ \hmi@HomeModInfo{..} -> do+      leakMod <- mkWeakPtr hmi Nothing+      leakIface <- mkWeakPtr hm_iface Nothing+      leakDetails <- mkWeakPtr hm_details Nothing+      leakLinkable <-  mkWeakLinkables hm_linkable+      return $ LeakModIndicators{..}+  where+    mkWeakLinkables :: HomeModLinkable -> IO [Maybe (Weak Linkable)]+    mkWeakLinkables (HomeModLinkable mbc mo) =+      mapM (\ln -> traverse (flip mkWeakPtr Nothing <=< evaluate) ln) [mbc, mo]++-- | Look at the LeakIndicators collected by an earlier call to+-- `getLeakIndicators`, and print messasges if any of them are still+-- alive.+checkLeakIndicators :: DynFlags -> LeakIndicators -> IO ()+checkLeakIndicators dflags (LeakIndicators leakmods)  = do+  performGC+  forM_ leakmods $ \LeakModIndicators{..} -> do+    deRefWeak leakMod >>= \case+      Nothing -> return ()+      Just hmi ->+        report ("HomeModInfo for " +++          showSDoc dflags (ppr (mi_module (hm_iface hmi)))) (Just hmi)+    deRefWeak leakIface >>= \case+      Nothing -> return ()+      Just miface -> report ("ModIface:" ++ moduleNameString (moduleName (mi_module miface))) (Just miface)+    deRefWeak leakDetails >>= report "ModDetails"+    forM_ leakLinkable $ \l -> forM_ l $ \l' -> deRefWeak l' >>= report "Linkable"+ where+  report :: String -> Maybe a -> IO ()+  report _ Nothing = return ()+  report msg (Just a) = do+    addr <- anyToPtr a+    putStrLn ("-fghci-leak-check: " ++ msg ++ " is still alive at " +++              show (maskTagBits addr))++  tagBits+    | target32Bit (targetPlatform dflags) = 2+    | otherwise = 3++  maskTagBits :: Ptr a -> Ptr a+  maskTagBits p = intPtrToPtr (ptrToIntPtr p .&. complement (shiftL 1 tagBits - 1))
+ app-ghc-9.10/GHCi/UI.hs view
@@ -0,0 +1,4803 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE NondecreasingIndentation #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE TypeFamilies #-}++{-# OPTIONS -fno-warn-name-shadowing #-}+-- This module does a lot of it++-----------------------------------------------------------------------------+--+-- GHC Interactive User Interface+--+-- (c) The GHC Team 2005-2006+--+-----------------------------------------------------------------------------++module GHCi.UI (+        interactiveUI,+        GhciSettings(..),+        defaultGhciSettings,+        ghciCommands,+        ghciWelcomeMsg,+        -- DAP add.+        getLoadedModules,+        breakCmd,+        deleteCmd,+        backCmd,+        forwardCmd,+        historyCmd,+        traceCmd,+        stepCmd,+        stepLocalCmd,+        runStmt,+        toBreakIdAndLocation,+        forceCmd,+        setContext,+        keepGoing+    ) where++-- GHCi+import qualified GHCi.UI.Monad as GhciMonad ( args, runStmt, runDecls' )+import GHCi.UI.Monad hiding ( args, runStmt )+import GHCi.UI.Info+import GHCi.UI.Exception+import GHC.Runtime.Debugger++-- The GHC interface+import GHC.Runtime.Interpreter+import GHCi.RemoteTypes+import GHCi.BreakArray( breakOn, breakOff )+import GHC.ByteCode.Types+import GHC.Core.DataCon+import GHC.Core.ConLike+import GHC.Core.PatSyn+import GHC.Driver.Flags+import GHC.Driver.Errors+import GHC.Driver.Errors.Types+import GHC.Driver.Phases+import GHC.Driver.Session as DynFlags+import GHC.Driver.Ppr hiding (printForUser)+import GHC.Utils.Error hiding (traceCmd)+import GHC.Driver.Monad ( modifySession )+import GHC.Driver.Make ( newIfaceCache, ModIfaceCache(..) )+import GHC.Driver.Config.Parser (initParserOpts)+import GHC.Driver.Config.Diagnostic+import qualified GHC+import GHC ( LoadHowMuch(..), Target(..),  TargetId(..),+             Resume, SingleStep, Ghc,+             GetDocsFailure(..), pushLogHookM,+             getModuleGraph, handleSourceError, ms_mod )+import GHC.Driver.Main (hscParseModuleWithLocation, hscParseStmtWithLocation)+import GHC.Hs.ImpExp+import GHC.Hs+import GHC.Driver.Env+import GHC.Runtime.Context+import GHC.Types.TyThing+import GHC.Types.TyThing.Ppr+import GHC.Core.TyCo.Ppr+import GHC.Types.SafeHaskell ( getSafeMode )+import GHC.Types.SourceError ( SourceError )+import GHC.Types.Name+import GHC.Types.Var ( varType )+import GHC.Iface.Syntax ( showToHeader )+import GHC.Builtin.Names+import GHC.Builtin.Types( stringTyCon_RDR )+import GHC.Types.Name.Reader as RdrName ( getGRE_NameQualifier_maybes, getRdrName )+import GHC.Types.SrcLoc as SrcLoc+import qualified GHC.Parser.Lexer as Lexer+import GHC.Parser.Header ( toArgs )+import qualified GHC.Parser.Header as Header+import GHC.Types.PkgQual++import GHC.Unit+import GHC.Unit.Finder as Finder+import GHC.Unit.Module.Graph (filterToposortToModules)+import GHC.Unit.Module.ModSummary++import GHC.Data.StringBuffer+import GHC.Utils.Outputable+import GHC.Utils.Logger++-- Other random utilities+import GHC.Types.Basic hiding ( isTopLevel )+import GHC.Settings.Config+import GHC.Data.Graph.Directed+import GHC.Utils.Encoding+import GHC.Data.FastString+import qualified GHC.Linker.Loader as Loader+import GHC.Data.Maybe ( orElse, expectJust )+import GHC.Types.Name.Set+import GHC.Utils.Panic hiding ( showException, try )+import GHC.Utils.Misc+import qualified GHC.LanguageExtensions as LangExt+import GHC.Data.Bag (unitBag)+import qualified GHC.Data.Strict as Strict+import GHC.Types.Error++-- Haskell Libraries+import System.Console.Haskeline as Haskeline++import Control.Applicative hiding (empty)+import Control.DeepSeq (deepseq)+import Control.Monad as Monad+import Control.Monad.Catch as MC+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Control.Monad.Trans.Except++import Data.Array+import qualified Data.ByteString.Char8 as BS+import Data.Char+import Data.Function+import Data.IORef ( IORef, modifyIORef, newIORef, readIORef, writeIORef )+import Data.List ( elemIndices, find, intercalate, intersperse, minimumBy,+                   isPrefixOf, isSuffixOf, nub, partition, sort, sortBy, (\\) )+import qualified Data.List.NonEmpty as NE+import qualified Data.Set as S+import Data.Maybe+import qualified Data.Map as M+import Data.IntMap.Strict (IntMap)+import qualified Data.IntMap.Strict as IntMap+import Data.Time.LocalTime ( getZonedTime )+import Data.Time.Format ( formatTime, defaultTimeLocale )+import Data.Version ( showVersion )+import qualified Data.Semigroup as S+import Prelude hiding ((<>))++import GHC.Utils.Exception as Exception hiding (catch, mask, handle)+import Foreign hiding (void)+import GHC.Stack hiding (SrcLoc(..))+import GHC.Unit.Env+import GHC.Unit.Home.ModInfo++import System.Directory+import System.Environment+import System.Exit ( exitWith, ExitCode(..) )+import System.FilePath+import System.Info+import System.IO+import System.IO.Error+import System.IO.Unsafe ( unsafePerformIO )+import System.Process+import Text.Printf+import Text.Read ( readMaybe )+import Text.Read.Lex (isSymbolChar)++import Unsafe.Coerce++#if !defined(mingw32_HOST_OS)+import System.Posix hiding ( getEnv )+#else+import qualified System.Win32+#endif++import GHC.IO.Exception ( IOErrorType(InvalidArgument) )+import GHC.IO.Handle ( hFlushAll )+import GHC.TopHandler ( topHandler )++import GHCi.Leak+import qualified GHC.Unit.Module.Graph as GHC++------------------------------------------------------------------------------+-- DAP+------------------------------------------------------------------------------+import qualified GHCi.DAP.Type as DAP+import Control.Concurrent+++-----------------------------------------------------------------------------++data GhciSettings = GhciSettings {+        availableCommands :: [Command],+        shortHelpText     :: String,+        fullHelpText      :: String,+        defPrompt         :: PromptFunction,+        defPromptCont     :: PromptFunction,+        dapContextGhciSettings :: DAP.MVarDAPContext+    }++defaultGhciSettings :: DAP.MVarDAPContext -> GhciSettings+defaultGhciSettings dapCtx =+    GhciSettings {+        availableCommands = ghciCommands,+        shortHelpText     = defShortHelpText,+        defPrompt         = default_prompt,+        defPromptCont     = default_prompt_cont,+        fullHelpText      = defFullHelpText,+        dapContextGhciSettings = dapCtx+    }++ghciWelcomeMsg :: String+ghciWelcomeMsg = "GHCi, version " ++ cProjectVersion +++                 ": https://www.haskell.org/ghc/  :? for help"++ghciCommands :: [Command]+ghciCommands = map mkCmd [+  -- Hugs users are accustomed to :e, so make sure it doesn't overlap+  ("?",         keepGoing help,                 noCompletion),+  ("add",       keepGoingPaths addModule,       completeFilename),+  ("abandon",   keepGoing abandonCmd,           noCompletion),+  ("break",     keepGoing breakCmd,             completeBreakpoint),+  ("back",      keepGoing backCmd,              noCompletion),+  ("browse",    keepGoing' (browseCmd False),   completeModule),+  ("browse!",   keepGoing' (browseCmd True),    completeModule),+  ("cd",        keepGoingMulti' changeDirectory,     completeFilename),+  ("check",     keepGoing' checkModule,         completeHomeModule),+  ("continue",  keepGoing continueCmd,          noCompletion),+  ("cmd",       keepGoing cmdCmd,               completeExpression),+  ("def",       keepGoing (defineMacro False),  completeExpression),+  ("def!",      keepGoing (defineMacro True),   completeExpression),+  ("delete",    keepGoing deleteCmd,            noCompletion),+  ("disable",   keepGoing disableCmd,           noCompletion),+  ("doc",       keepGoing' docCmd,              completeIdentifier),+  ("edit",      keepGoingMulti' editFile,            completeFilename),+  ("enable",    keepGoing enableCmd,            noCompletion),+  ("force",     keepGoing forceCmd,             completeExpression),+  ("forward",   keepGoing forwardCmd,           noCompletion),+  ("help",      keepGoingMulti help,                 noCompletion),+  ("history",   keepGoingMulti historyCmd,           noCompletion),+  ("info",      keepGoingMulti' (info False),        completeIdentifier),+  ("info!",     keepGoingMulti' (info True),         completeIdentifier),+  ("issafe",    keepGoing' isSafeCmd,           completeModule),+  ("ignore",    keepGoing ignoreCmd,            noCompletion),+  ("kind",      keepGoingMulti' (kindOfType False),  completeIdentifier),+  ("kind!",     keepGoingMulti' (kindOfType True),   completeIdentifier),+  ("load",      keepGoingPaths loadModule_,     completeHomeModuleOrFile),+  ("load!",     keepGoingPaths loadModuleDefer, completeHomeModuleOrFile),+  ("list",      keepGoing' listCmd,             noCompletion),+  ("module",    keepGoing moduleCmd,            completeSetModule),+  ("main",      keepGoing runMain,              completeFilename),+  ("print",     keepGoing printCmd,             completeExpression),+  ("quit",      quit,                           noCompletion),+  ("reload",    keepGoingMulti' reloadModule,   noCompletion),+  ("reload!",   keepGoingMulti' reloadModuleDefer,   noCompletion),+  ("run",       keepGoing runRun,               completeFilename),+  ("script",    keepGoing' scriptCmd,           completeFilename),+  ("set",       keepGoingMulti setCmd,          completeSetOptions),+  ("seti",      keepGoingMulti setiCmd,         completeSeti),+  ("show",      keepGoingMulti' showCmd,        completeShowOptions),+  ("showi",     keepGoing showiCmd,             completeShowiOptions),+  ("sprint",    keepGoing sprintCmd,            completeExpression),+  ("step",      keepGoing stepCmd,              completeIdentifier),+  ("steplocal", keepGoing stepLocalCmd,         completeIdentifier),+  ("stepmodule",keepGoing stepModuleCmd,        completeIdentifier),+  ("type",      keepGoingMulti' typeOfExpr,          completeExpression),+  ("trace",     keepGoing traceCmd,             completeExpression),+  ("unadd",     keepGoingPaths unAddModule,     completeFilename),+  ("undef",     keepGoing undefineMacro,        completeMacro),+  ("unset",     keepGoing unsetOptions,         completeSetOptions),+  ("where",     keepGoing whereCmd,             noCompletion),+  ("instances", keepGoing' instancesCmd,        completeExpression)+  ] ++ map mkCmdHidden [ -- hidden commands+  ("all-types", keepGoing' allTypesCmd),+  ("complete",  keepGoing completeCmd),+  ("loc-at",    keepGoing' locAtCmd),+  ("type-at",   keepGoing' typeAtCmd),+  ("uses",      keepGoing' usesCmd)+  ]+ where+  mkCmd (n,a,c) = Command { cmdName = n+                          , cmdAction = a+                          , cmdHidden = False+                          , cmdCompletionFunc = c+                          }++  mkCmdHidden (n,a) = Command { cmdName = n+                              , cmdAction = a+                              , cmdHidden = True+                              , cmdCompletionFunc = noCompletion+                              }++-- We initialize readline (in the interactiveUI function) to use+-- word_break_chars as the default set of completion word break characters.+-- This can be overridden for a particular command (for example, filename+-- expansion shouldn't consider '/' to be a word break) by setting the third+-- entry in the Command tuple above.+--+-- NOTE: in order for us to override the default correctly, any custom entry+-- must be a SUBSET of word_break_chars.+word_break_chars :: String+word_break_chars = spaces ++ specials ++ symbols++word_break_chars_pred :: Char -> Bool+word_break_chars_pred '.' = False+word_break_chars_pred c = c `elem` (spaces ++ specials) || isSymbolChar c++symbols, specials, spaces :: String+symbols = "!#$%&*+/<=>?@\\^|-~"+specials = "(),;[]`{}"+spaces = " \t\n"++flagWordBreakChars :: String+flagWordBreakChars = " \t\n"+++showSDocForUser' :: GHC.GhcMonad m => SDoc -> m String+showSDocForUser' doc = do+    dflags <- getDynFlags+    unit_state <- hsc_units <$> GHC.getSession+    name_ppr_ctx <- GHC.getNamePprCtx+    pure $ showSDocForUser dflags unit_state name_ppr_ctx doc++showSDocForUserQualify :: GHC.GhcMonad m => SDoc -> m String+showSDocForUserQualify doc = do+    dflags <- getDynFlags+    unit_state <- hsc_units <$> GHC.getSession+    pure $ showSDocForUser dflags unit_state alwaysQualify doc+++keepGoing :: (String -> GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)+keepGoing a str = keepGoing' (lift . a) str++keepGoingMulti :: (String -> GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)+keepGoingMulti a str = keepGoingMulti' (lift . a) str++keepGoing' :: GhciMonad m => (a -> m ()) -> a -> m CmdExecOutcome+keepGoing' a str = do+  in_multi <- inMultiMode+  if in_multi+    then+      liftIO $ hPutStrLn stderr "Command is not supported (yet) in multi-mode"+    else+      a str+  return CmdSuccess++-- For commands which are actually support in multi-mode, initially just :reload+keepGoingMulti' :: GhciMonad m => (String -> m ()) -> String -> m CmdExecOutcome+keepGoingMulti' a str = a str >> return CmdSuccess++inMultiMode :: GhciMonad m => m Bool+inMultiMode = multiMode <$> getGHCiState++keepGoingPaths :: ([FilePath] -> InputT GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)+keepGoingPaths a str+ = do case toArgsNoLoc str of+          Left err -> liftIO $ hPutStrLn stderr err >> return CmdSuccess+          Right args -> keepGoing' a args++defShortHelpText :: String+defShortHelpText = "use :? for help.\n"++defFullHelpText :: String+defFullHelpText =+  " Commands available from the prompt:\n" +++  "\n" +++  "   <statement>                 evaluate/run <statement>\n" +++  "   :                           repeat last command\n" +++  "   :{\\n ..lines.. \\n:}\\n       multiline command\n" +++  "   :add [*]<module> ...        add module(s) to the current target set\n" +++  "   :browse[!] [[*]<mod>]       display the names defined by module <mod>\n" +++  "                               (!: more details; *: all top-level names)\n" +++  "   :cd <dir>                   change directory to <dir>\n" +++  "   :cmd <expr>                 run the commands returned by <expr>::IO String\n" +++  "   :complete <dom> [<rng>] <s> list completions for partial input string\n" +++  "   :def[!] <cmd> <expr>        define command :<cmd> (later defined command has\n" +++  "                               precedence, ::<cmd> is always a builtin command)\n" +++  "                               (!: redefine an existing command name)\n" +++  "   :doc <name>                 display docs for the given name (experimental)\n" +++  "   :edit <file>                edit file\n" +++  "   :edit                       edit last module\n" +++  "   :help, :?                   display this list of commands\n" +++  "   :info[!] [<name> ...]       display information about the given names\n" +++  "                               (!: do not filter instances)\n" +++  "   :instances <type>           display the class instances available for <type>\n" +++  "   :issafe [<mod>]             display safe haskell information of module <mod>\n" +++  "   :kind[!] <type>             show the kind of <type>\n" +++  "                               (!: also print the normalised type)\n" +++  "   :load[!] [*]<module> ...    load module(s) and their dependents\n" +++  "                               (!: defer type errors)\n" +++  "   :main [<arguments> ...]     run the main function with the given arguments\n" +++  "   :module [+/-] [*]<mod> ...  set the context for expression evaluation\n" +++  "   :quit                       exit GHCi\n" +++  "   :reload[!]                  reload the current module set\n" +++  "                               (!: defer type errors)\n" +++  "   :run function [<arguments> ...] run the function with the given arguments\n" +++  "   :script <file>              run the script <file>\n" +++  "   :type <expr>                show the type of <expr>\n" +++  "   :type +d <expr>             show the type of <expr>, defaulting type variables\n" +++  "   :unadd <module> ...         remove module(s) from the current target set\n" +++  "   :undef <cmd>                undefine user-defined command :<cmd>\n" +++  "   ::<cmd>                     run the builtin command\n" +++  "   :!<command>                 run the shell command <command>\n" +++  "\n" +++  " -- Commands for debugging:\n" +++  "\n" +++  "   :abandon                    at a breakpoint, abandon current computation\n" +++  "   :back [<n>]                 go back in the history N steps (after :trace)\n" +++  "   :break [<mod>] <l> [<col>]  set a breakpoint at the specified location\n" +++  "   :break <name>               set a breakpoint on the specified function\n" +++  "   :continue [<count>]         resume after a breakpoint [and set break ignore count]\n" +++  "   :delete <number> ...        delete the specified breakpoints\n" +++  "   :delete *                   delete all breakpoints\n" +++  "   :disable <number> ...       disable the specified breakpoints\n" +++  "   :disable *                  disable all breakpoints\n" +++  "   :enable <number> ...        enable the specified breakpoints\n" +++  "   :enable *                   enable all breakpoints\n" +++  "   :force <expr>               print <expr>, forcing unevaluated parts\n" +++  "   :forward [<n>]              go forward in the history N step s(after :back)\n" +++  "   :history [<n>]              after :trace, show the execution history\n" +++  "   :ignore <breaknum> <count>  for break <breaknum> set break ignore <count>\n" +++  "   :list                       show the source code around current breakpoint\n" +++  "   :list <identifier>          show the source code for <identifier>\n" +++  "   :list [<module>] <line>     show the source code around line number <line>\n" +++  "   :print [<name> ...]         show a value without forcing its computation\n" +++  "   :sprint [<name> ...]        simplified version of :print\n" +++  "   :step                       single-step after stopping at a breakpoint\n"+++  "   :step <expr>                single-step into <expr>\n"+++  "   :steplocal                  single-step within the current top-level binding\n"+++  "   :stepmodule                 single-step restricted to the current module\n"+++  "   :trace                      trace after stopping at a breakpoint\n"+++  "   :trace <expr>               evaluate <expr> with tracing on (see :history)\n"++++  "\n" +++  " -- Commands for changing settings:\n" +++  "\n" +++  "   :set <option> ...           set options\n" +++  "   :seti <option> ...          set options for interactive evaluation only\n" +++  "   :set local-config { source | ignore }\n" +++  "                               set whether to source .ghci in current dir\n" +++  "                               (loading untrusted config is a security issue)\n" +++  "   :set args <arg> ...         set the arguments returned by System.Environment.getArgs\n" +++  "   :set prog <progname>        set the value returned by System.Environment.getProgName\n" +++  "   :set prompt <prompt>        set the prompt used in GHCi\n" +++  "   :set prompt-cont <prompt>   set the continuation prompt used in GHCi\n" +++  "   :set prompt-function <expr> set the function to handle the prompt\n" +++  "   :set prompt-cont-function <expr>\n" +++  "                               set the function to handle the continuation prompt\n" +++  "   :set editor <cmd>           set the command used for :edit\n" +++  "   :set stop [<n>] <cmd>       set the command to run when a breakpoint is hit\n" +++  "   :unset <option> ...         unset options\n" +++  "\n" +++  "  Options for ':set' and ':unset':\n" +++  "\n" +++  "    +m            allow multiline commands\n" +++  "    +r            revert top-level expressions after each evaluation\n" +++  "    +s            print timing/memory stats after each evaluation\n" +++  "    +t            print type after evaluation\n" +++  "    +c            collect type/location info after loading modules\n" +++  "    -<flags>      most GHC command line flags can also be set here\n" +++  "                         (eg. -v2, -XFlexibleInstances, etc.)\n" +++  "                    for GHCi-specific flags, see User's Guide,\n"+++  "                    Flag reference, Interactive-mode options\n" +++  "\n" +++  " -- Commands for displaying information:\n" +++  "\n" +++  "   :show bindings              show the current bindings made at the prompt\n" +++  "   :show breaks                show the active breakpoints\n" +++  "   :show context               show the breakpoint context\n" +++  "   :show imports               show the current imports\n" +++  "   :show linker                show current linker state\n" +++  "   :show modules               show the currently loaded modules\n" +++  "   :show packages              show the currently active package flags\n" +++  "   :show paths                 show the currently active search paths\n" +++  "   :show language              show the currently active language flags\n" +++  "   :show targets               show the current set of targets\n" +++  "   :show <setting>             show value of <setting>, which is one of\n" +++  "                                  [args, prog, editor, stop]\n" +++  "   :showi language             show language flags for interactive evaluation\n" +++  "\n" +++  " The User's Guide has more information. An online copy can be found here:\n" +++  "\n" +++  "   https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html\n" +++  "\n"++findEditor :: IO String+findEditor = do+    getEnv "VISUAL" <|> getEnv "EDITOR" <|> defaultEditor+  where+    defaultEditor = do+#if defined(mingw32_HOST_OS)+      win <- System.Win32.getWindowsDirectory+      return (win </> "notepad.exe")+#else+      return ""+#endif++default_progname, default_stop :: String+default_progname = "<interactive>"+default_stop = ""++default_prompt, default_prompt_cont :: PromptFunction+default_prompt = generatePromptFunctionFromString "ghci> "+default_prompt_cont = generatePromptFunctionFromString "ghci| "++default_args :: [String]+default_args = []++interactiveUI :: GhciSettings -> [(FilePath, Maybe UnitId, Maybe Phase)] -> Maybe [String]+              -> Ghc ()+interactiveUI config srcs maybe_exprs = do+   -- This is a HACK to make sure dynflags are not overwritten when setting+   -- options. When GHCi is made properly multi component it should be removed.+   modifySession (\env -> hscSetActiveUnitId (hscActiveUnitId env) env)+   -- HACK! If we happen to get into an infinite loop (eg the user+   -- types 'let x=x in x' at the prompt), then the thread will block+   -- on a blackhole, and become unreachable during GC.  The GC will+   -- detect that it is unreachable and send it the NonTermination+   -- exception.  However, since the thread is unreachable, everything+   -- it refers to might be finalized, including the standard Handles.+   -- This sounds like a bug, but we don't have a good solution right+   -- now.+   _ <- liftIO $ newStablePtr stdin+   _ <- liftIO $ newStablePtr stdout+   _ <- liftIO $ newStablePtr stderr++    -- Initialise buffering for the *interpreted* I/O system+   (nobuffering, flush) <- runInternal initInterpBuffering++   -- The initial set of DynFlags used for interactive evaluation is the same+   -- as the global DynFlags, plus -XExtendedDefaultRules and+   -- -XNoMonomorphismRestriction.+   -- See Note [Changing language extensions for interactive evaluation] #10857+   dflags <- getDynFlags+   let dflags' = (xopt_set_unlessExplSpec+                      LangExt.ExtendedDefaultRules xopt_set)+               . (xopt_set_unlessExplSpec+                      LangExt.MonomorphismRestriction xopt_unset)+               $ dflags+   GHC.setInteractiveDynFlags dflags'+   _ <- GHC.setProgramDynFlags+               -- Set Opt_KeepGoing so that :reload loads as much as+               -- possible+               (gopt_set dflags Opt_KeepGoing)++   -- Update the LogAction. Ensure we don't override the user's log action lest+   -- we break -ddump-json (#14078)+   lastErrLocationsRef <- liftIO $ newIORef []+   pushLogHookM (ghciLogAction lastErrLocationsRef)++   when (isNothing maybe_exprs) $ do+        -- Only for GHCi (not runghc and ghc -e):++        -- Turn buffering off for the compiled program's stdout/stderr+        turnOffBuffering_ nobuffering+        -- Turn buffering off for GHCi's stdout+        liftIO $ hFlush stdout+        liftIO $ hSetBuffering stdout NoBuffering+        -- We don't want the cmd line to buffer any input that might be+        -- intended for the program, so unbuffer stdin.+        liftIO $ hSetBuffering stdin NoBuffering+        liftIO $ hSetBuffering stderr NoBuffering+#if defined(mingw32_HOST_OS)+        -- On Unix, stdin will use the locale encoding.  The IO library+        -- doesn't do this on Windows (yet), so for now we use UTF-8,+        -- for consistency with GHC 6.10 and to make the tests work.+        liftIO $ hSetEncoding stdin utf8+#endif++   default_editor <- liftIO $ findEditor+   eval_wrapper <- mkEvalWrapper default_progname default_args+   let prelude_import =+         case simpleImportDecl preludeModuleName of+           -- Set to True because Prelude is implicitly imported.+           impDecl@ImportDecl{ideclExt=ext} -> impDecl{ideclExt = ext{ideclImplicit=True}}+   hsc_env <- GHC.getSession+   let in_multi = length (hsc_all_home_unit_ids hsc_env) > 1+   empty_cache <- liftIO newIfaceCache+   startGHCi (runGHCi srcs maybe_exprs)+        GHCiState{ progname           = default_progname,+                   args               = default_args,+                   evalWrapper        = eval_wrapper,+                   prompt             = defPrompt config,+                   prompt_cont        = defPromptCont config,+                   stop               = default_stop,+                   editor             = default_editor,+                   options            = [],+                   multiMode          = in_multi,+                   localConfig        = SourceLocalConfig,+                   -- We initialize line number as 0, not 1, because we use+                   -- current line number while reporting errors which is+                   -- incremented after reading a line.+                   line_number        = 0,+                   break_ctr          = 0,+                   breaks             = IntMap.empty,+                   tickarrays         = emptyModuleEnv,+                   ghci_commands      = availableCommands config,+                   ghci_macros        = [],+                   last_command       = Nothing,+                   cmd_wrapper        = (cmdSuccess =<<),+                   cmdqueue           = [],+                   remembered_ctx     = [],+                   transient_ctx      = [],+                   extra_imports      = [],+                   prelude_imports    = [prelude_import],+                   ghc_e              = isJust maybe_exprs,+                   short_help         = shortHelpText config,+                   long_help          = fullHelpText config,+                   lastErrorLocations = lastErrLocationsRef,+                   mod_infos          = M.empty,+                   flushStdHandles    = flush,+                   noBuffering        = nobuffering,+                   ifaceCache = empty_cache,+                   dapContextGHCiState = dapContextGhciSettings config+                 }++   return ()++{-+Note [Changing language extensions for interactive evaluation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHCi maintains two sets of options:++- The "loading options" apply when loading modules+- The "interactive options" apply when evaluating expressions and commands+    typed at the GHCi prompt.++The loading options are mostly created in ghc/Main.hs:main' from the command+line flags. In the function ghc/GHCi/UI.hs:interactiveUI the loading options+are copied to the interactive options.++These interactive options (but not the loading options!) are supplemented+unconditionally by setting ExtendedDefaultRules ON and+MonomorphismRestriction OFF. The unconditional setting of these options+eventually overwrite settings already specified at the command line.++Therefore instead of unconditionally setting ExtendedDefaultRules and+NoMonomorphismRestriction for the interactive options, we use the function+'xopt_set_unlessExplSpec' to first check whether the extension has already+specified at the command line.++The ghci config file has not yet been processed.+-}++resetLastErrorLocations :: GhciMonad m => m ()+resetLastErrorLocations = do+    st <- getGHCiState+    liftIO $ writeIORef (lastErrorLocations st) []++ghciLogAction :: IORef [(FastString, Int)] -> LogAction -> LogAction+ghciLogAction lastErrLocations old_log_action+              dflags msg_class srcSpan msg = do+    old_log_action dflags msg_class srcSpan msg+    case msg_class of+        MCDiagnostic SevError _reason _code -> case srcSpan of+            RealSrcSpan rsp _ -> modifyIORef lastErrLocations+                (++ [(srcLocFile (realSrcSpanStart rsp), srcLocLine (realSrcSpanStart rsp))])+            _ -> return ()+        _ -> return ()++-- | Takes a file name and prefixes it with the appropriate+-- GHC appdir.+-- Uses ~/.ghc (getAppUserDataDirectory) if it exists+-- If it doesn't, then it uses $XDG_DATA_HOME/ghc+-- Earlier we always used to use ~/.ghc, but we want+-- to gradually move to $XDG_DATA_HOME to respect the XDG specification+--+-- As a migration strategy, we will only create new directories in+-- the appropriate XDG location. However, we will use the old directory+-- if it already exists.+getAppDataFile :: FilePath -> IO (Maybe FilePath)+getAppDataFile file = do+    let new_path = tryIO (getXdgDirectory XdgConfig "ghc") >>= \case+          Left _ -> pure Nothing+          Right dir -> flip catchIO (const $ return Nothing) $ do+            createDirectoryIfMissing False dir+            pure $ Just $ dir </> file++    e_old_path <- tryIO (getAppUserDataDirectory "ghc")+    case e_old_path of+      Right old_path -> doesDirectoryExist old_path >>= \case+        True -> pure $ Just $ old_path </> file+        False -> new_path+      Left _ -> new_path++runGHCi :: [(FilePath, Maybe UnitId, Maybe Phase)] -> Maybe [String] -> GHCi ()+runGHCi paths maybe_exprs = do+  dflags <- getDynFlags+  let+   ignore_dot_ghci = gopt Opt_IgnoreDotGhci dflags++   app_user_dir = liftIO $ getAppDataFile "ghci.conf"++   home_dir = do+    either_dir <- liftIO $ tryIO (getEnv "HOME")+    case either_dir of+      Right home -> return (Just (home </> ".ghci"))+      _ -> return Nothing++   canonicalizePath' :: FilePath -> IO (Maybe FilePath)+   canonicalizePath' fp = liftM Just (canonicalizePath fp)+                `catchIO` \_ -> return Nothing++   sourceConfigFile :: FilePath -> GHCi ()+   sourceConfigFile file = do+     exists <- liftIO $ doesFileExist file+     when exists $ do+       either_hdl <- liftIO $ tryIO (openFile file ReadMode)+       case either_hdl of+         Left _e   -> return ()+         -- NOTE: this assumes that runInputT won't affect the terminal;+         -- can we assume this will always be the case?+         -- This would be a good place for runFileInputT.+         Right hdl ->+             do runInputTWithPrefs defaultPrefs defaultSettings $+                          runCommands $ fileLoop hdl+                liftIO (hClose hdl `catchIO` \_ -> return ())+                -- Don't print a message if this is really ghc -e (#11478).+                -- Also, let the user silence the message with -v0+                -- (the default verbosity in GHCi is 1).+                when (isNothing maybe_exprs && verbosity dflags > 0) $+                  liftIO $ putStrLn ("Loaded GHCi configuration from " ++ file)++  --++  setGHCContextFromGHCiState++  processedCfgs <- if ignore_dot_ghci+    then pure []+    else do+      userCfgs <- do+        paths <- catMaybes <$> sequence [ app_user_dir, home_dir ]+        checkedPaths <- liftIO $ filterM checkFileAndDirPerms paths+        liftIO . fmap (nub . catMaybes) $ mapM canonicalizePath' checkedPaths++      localCfg <- do+        let path = ".ghci"+        ok <- liftIO $ checkFileAndDirPerms path+        if ok then liftIO $ canonicalizePath' path else pure Nothing++      mapM_ sourceConfigFile userCfgs+        -- Process the global and user .ghci+        -- (but not $CWD/.ghci or CLI args, yet)++      behaviour <- localConfig <$> getGHCiState++      processedLocalCfg <- case localCfg of+        Just path | path `notElem` userCfgs ->+          -- don't read .ghci twice if CWD is $HOME+          case behaviour of+            SourceLocalConfig -> localCfg <$ sourceConfigFile path+            IgnoreLocalConfig -> pure Nothing+        _ -> pure Nothing++      pure $ maybe id (:) processedLocalCfg userCfgs++  let arg_cfgs = reverse $ ghciScripts dflags+    -- -ghci-script are collected in reverse order+    -- We don't require that a script explicitly added by -ghci-script+    -- is owned by the current user. (#6017)++  mapM_ sourceConfigFile $ nub arg_cfgs \\ processedCfgs+    -- Dedup, and remove any configs we already processed.+    -- Importantly, if $PWD/.ghci was ignored due to configuration,+    -- explicitly specifying it does cause it to be processed.++  -- Perform a :reload for files given on the GHCi command line+  -- The appropriate targets will already be set+  -- When in -e mode, if the load fails then we want to stop+  -- immediately rather than going on to evaluate the expression.+  when (not (null paths)) $ do+     ok <- ghciHandle (\e -> do showException e; return Failed) $+                    loadModule paths+     when (isJust maybe_exprs && failed ok) $+        liftIO (exitWith (ExitFailure 1))++  installInteractivePrint (interactivePrint dflags) (isJust maybe_exprs)++  -- if verbosity is greater than 0, or we are connected to a+  -- terminal, display the prompt in the interactive loop.+  is_tty <- liftIO (return True)     -- DAP modified.+  let show_prompt = verbosity dflags > 0 || is_tty++  -- reset line number+  modifyGHCiState $ \st -> st{line_number=0}++  case maybe_exprs of+        Nothing ->+          do+            -- enter the interactive loop+            runGHCiInput $ runCommands $ nextInputLine show_prompt is_tty+        Just exprs -> do+            -- just evaluate the expression we were given+            enqueueCommands exprs+            let hdle e = do st <- getGHCiState+                            -- flush the interpreter's stdout/stderr on exit (#3890)+                            flushInterpBuffers+                            -- Jump through some hoops to get the+                            -- current progname in the exception text:+                            -- <progname>: <exception>+                            liftIO $ withProgName (progname st)+                                   $ topHandler e+                                   -- this used to be topHandlerFastExit, see #2228+            runInputTWithPrefs defaultPrefs defaultSettings $ do+                -- make `ghc -e` exit nonzero on failure, see #7962, #9916, #17560, #18441+                _ <- runCommands' hdle+                     (Just $ hdle (toException $ ExitFailure 1) >> return ())+                     (return Nothing)+                return ()++  -- and finally, exit+  liftIO $ when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."++runGHCiInput :: InputT GHCi a -> GHCi a+runGHCiInput f = do+    dflags <- getDynFlags+    let ghciHistory = gopt Opt_GhciHistory dflags+    let localGhciHistory = gopt Opt_LocalGhciHistory dflags+    currentDirectory <- liftIO $ getCurrentDirectory++    histFile <- case (ghciHistory, localGhciHistory) of+      (True, True) -> return (Just (currentDirectory </> ".ghci_history"))+      (True, _) -> liftIO $ getAppDataFile "ghci_history"+      _ -> return Nothing++    runInputT+        (setComplete ghciCompleteWord $ defaultSettings {historyFile = histFile})+        f++-- | How to get the next input line from the user+nextInputLine :: Bool -> Bool -> InputT GHCi (Maybe String)+nextInputLine show_prompt is_tty+  | is_tty = do+    prmpt <- if show_prompt then lift mkPrompt else return ""+    r <- getInputLine prmpt+    incrementLineNo+    return r+  | otherwise = do+    when show_prompt $ lift mkPrompt >>= liftIO . putStr+    fileLoop stdin++-- NOTE: We only read .ghci files if they are owned by the current user,+-- and aren't world writable (files owned by root are ok, see #9324).+-- Otherwise, we could be accidentally running code planted by+-- a malicious third party.++-- Furthermore, We only read ./.ghci if . is owned by the current user+-- and isn't writable by anyone else.  I think this is sufficient: we+-- don't need to check .. and ../.. etc. because "."  always refers to+-- the same directory while a process is running.++checkFileAndDirPerms :: FilePath -> IO Bool+checkFileAndDirPerms file = do+  file_ok <- checkPerms file+  -- Do not check dir perms when .ghci doesn't exist, otherwise GHCi will+  -- print some confusing and useless warnings in some cases (e.g. in+  -- travis). Note that we can't add a test for this, as all ghci tests should+  -- run with -ignore-dot-ghci, which means we never get here.+  if file_ok then checkPerms (getDirectory file) else return False+  where+  getDirectory f = case takeDirectory f of+    "" -> "."+    d -> d++checkPerms :: FilePath -> IO Bool+#if defined(mingw32_HOST_OS)+checkPerms _ = return True+#else+checkPerms file =+  handleIO (\_ -> return False) $ do+    st <- getFileStatus file+    me <- getRealUserID+    let mode = System.Posix.fileMode st+        ok = (fileOwner st == me || fileOwner st == 0) &&+             groupWriteMode /= mode `intersectFileModes` groupWriteMode &&+             otherWriteMode /= mode `intersectFileModes` otherWriteMode+    unless ok $+      -- #8248: Improving warning to include a possible fix.+      putStrLn $ "*** WARNING: " ++ file +++                 " is writable by someone else, IGNORING!" +++                 "\nSuggested fix: execute 'chmod go-w " ++ file ++ "'"+    return ok+#endif++incrementLineNo :: GhciMonad m => m ()+incrementLineNo = modifyGHCiState incLineNo+  where+    incLineNo st = st { line_number = line_number st + 1 }++fileLoop :: GhciMonad m => Handle -> m (Maybe String)+fileLoop hdl = do+   l <- liftIO $ tryIO $ hGetLine hdl+   case l of+        Left e | isEOFError e              -> return Nothing+               | -- as we share stdin with the program, the program+                 -- might have already closed it, so we might get a+                 -- handle-closed exception. We therefore catch that+                 -- too.+                 isIllegalOperation e      -> return Nothing+               | InvalidArgument <- etype  -> return Nothing+               | otherwise                 -> liftIO $ ioError e+                where etype = ioeGetErrorType e+                -- treat InvalidArgument in the same way as EOF:+                -- this can happen if the user closed stdin, or+                -- perhaps did getContents which closes stdin at+                -- EOF.+        Right l' -> do+           incrementLineNo+           return (Just l')++formatCurrentTime :: String -> IO String+formatCurrentTime format =+  getZonedTime >>= return . (formatTime defaultTimeLocale format)++getUserName :: IO String+getUserName = do+#if defined(mingw32_HOST_OS)+  getEnv "USERNAME"+    `catchIO` \e -> do+      putStrLn $ show e+      return ""+#else+  getLoginName+#endif++getInfoForPrompt :: GhciMonad m => m (SDoc, [String], Int)+getInfoForPrompt = do+  st <- getGHCiState+  imports <- GHC.getContext+  resumes <- GHC.getResumeContext++  context_bit <-+        case resumes of+            [] -> return empty+            r:_ -> do+                let ix = GHC.resumeHistoryIx r+                if ix == 0+                   then return (brackets (ppr (GHC.resumeSpan r)) <> space)+                   else do+                        let hist = GHC.resumeHistory r !! (ix-1)+                        pan <- GHC.getHistorySpan hist+                        return (brackets (ppr (negate ix) <> char ':'+                                          <+> ppr pan) <> space)++  let+        dots | _:rs <- resumes, not (null rs) = text "... "+             | otherwise = empty++        rev_imports = reverse imports -- rightmost are the most recent++        myIdeclName d | Just m <- ideclAs d = unLoc m+                      | otherwise           = unLoc (ideclName d)++        modules_names =+             ['*':(moduleNameString m) | IIModule m <- rev_imports] +++             [moduleNameString (myIdeclName d) | IIDecl d <- rev_imports]+        line = 1 + line_number st++  return (dots <> context_bit, modules_names, line)++-- | Takes a string, presumably following "%call", and tries to parse+-- a command and arguments in parentheses:+--+-- > parseCallEscape "  (cmd arg1 arg2)rest" = Just ("cmd" :| ["arg1", "arg2"], "rest")+-- > parseCallEscape "( )rest" = Nothing+--+parseCallEscape :: String -> Maybe (NE.NonEmpty String, String)+parseCallEscape s = case dropWhile isSpace s of+  '(' : sinceOpen -> case span (/= ')') sinceOpen of+    (call, ')' : sinceClosed)+      | cmd : args <- words call -> Just (cmd NE.:| args, sinceClosed)+    _ -> Nothing+  _ -> Nothing++checkPromptStringForErrors :: String -> Maybe String+checkPromptStringForErrors ('%':'c':'a':'l':'l':xs) =+  case parseCallEscape xs of+    Nothing  -> Just ("Incorrect %call syntax. " +++                      "Should be %call(a command and arguments).")+    Just (_, afterClosed) -> checkPromptStringForErrors afterClosed+checkPromptStringForErrors ('%':'%':xs) = checkPromptStringForErrors xs+checkPromptStringForErrors (_:xs) = checkPromptStringForErrors xs+checkPromptStringForErrors "" = Nothing++generatePromptFunctionFromString :: String -> PromptFunction+generatePromptFunctionFromString promptS modules_names line =+        processString promptS+  where+        processString :: String -> GHCi SDoc+        processString ('%':'s':xs) =+            liftM2 (<>) (return modules_list) (processString xs)+            where+              modules_list = hsep . map text . ordNub $ modules_names+        processString ('%':'l':xs) =+            liftM2 (<>) (return $ ppr line) (processString xs)+        processString ('%':'d':xs) =+            liftM2 (<>) (liftM text formatted_time) (processString xs)+            where+              formatted_time = liftIO $ formatCurrentTime "%a %b %d"+        processString ('%':'t':xs) =+            liftM2 (<>) (liftM text formatted_time) (processString xs)+            where+              formatted_time = liftIO $ formatCurrentTime "%H:%M:%S"+        processString ('%':'T':xs) = do+            liftM2 (<>) (liftM text formatted_time) (processString xs)+            where+              formatted_time = liftIO $ formatCurrentTime "%I:%M:%S"+        processString ('%':'@':xs) = do+            liftM2 (<>) (liftM text formatted_time) (processString xs)+            where+              formatted_time = liftIO $ formatCurrentTime "%I:%M %P"+        processString ('%':'A':xs) = do+            liftM2 (<>) (liftM text formatted_time) (processString xs)+            where+              formatted_time = liftIO $ formatCurrentTime "%H:%M"+        processString ('%':'u':xs) =+            liftM2 (<>) (liftM text user_name) (processString xs)+            where+              user_name = liftIO $ getUserName+        processString ('%':'w':xs) =+            liftM2 (<>) (liftM text current_directory) (processString xs)+            where+              current_directory = liftIO $ getCurrentDirectory+        processString ('%':'o':xs) =+            liftM ((text os) <>) (processString xs)+        processString ('%':'a':xs) =+            liftM ((text arch) <>) (processString xs)+        processString ('%':'N':xs) =+            liftM ((text compilerName) <>) (processString xs)+        processString ('%':'V':xs) =+            liftM ((text $ showVersion compilerVersion) <>) (processString xs)+        processString ('%':'c':'a':'l':'l':xs) = do+            -- Input has just been validated by parseCallEscape+            let (cmd NE.:| args, afterClosed) = fromJust $ parseCallEscape xs+            respond <- liftIO $ do+                (code, out, err) <-+                    readProcessWithExitCode+                    cmd args ""+                    `catchIO` \e -> return (ExitFailure 1, "", show e)+                case code of+                    ExitSuccess -> return out+                    _ -> do+                        hPutStrLn stderr err+                        return ""+            liftM ((text respond) <>) (processString afterClosed)+        processString ('%':'%':xs) =+            liftM ((char '%') <>) (processString xs)+        processString (x:xs) =+            liftM (char x <>) (processString xs)+        processString "" =+            return empty++mkPrompt :: GHCi String+mkPrompt = do+  st <- getGHCiState+  dflags <- getDynFlags+  (context, modules_names, line) <- getInfoForPrompt++  prompt_string <- (prompt st) modules_names line+  let prompt_doc = context <> prompt_string++  return (showSDoc dflags prompt_doc)++queryQueue :: GhciMonad m => m (Maybe String)+queryQueue = do+  st <- getGHCiState+  case cmdqueue st of+    []   -> return Nothing+    c:cs -> do setGHCiState st{ cmdqueue = cs }+               return (Just c)++-- Reconfigurable pretty-printing Ticket #5461+installInteractivePrint :: GhciMonad m => Maybe String -> Bool -> m ()+installInteractivePrint Nothing _  = return ()+installInteractivePrint (Just ipFun) exprmode = do+  ok <- trySuccess $ do+                name NE.:| _ <- GHC.parseName ipFun+                modifySession (\he -> let new_ic = setInteractivePrintName (hsc_IC he) name+                                      in he{hsc_IC = new_ic})+                return Succeeded++  when (failed ok && exprmode) $ liftIO (exitWith (ExitFailure 1))++-- | The main read-eval-print loop+runCommands :: InputT GHCi (Maybe String) -> InputT GHCi ()+runCommands gCmd = runCommands' handler Nothing gCmd >> return ()++runCommands' :: (SomeException -> GHCi Bool) -- ^ Exception handler+             -> Maybe (GHCi ()) -- ^ Source error handler+             -> InputT GHCi (Maybe String)+             -> InputT GHCi ()+runCommands' eh sourceErrorHandler gCmd = mask $ \unmask -> do+    b <- handle (\e -> case fromException e of+                          Just UserInterrupt -> return $ Just False+                          _ -> case fromException e of+                                 Just ghce ->+                                   do liftIO (print (ghce :: GhcException))+                                      return Nothing+                                 _other ->+                                   liftIO (Exception.throwIO e))+            (unmask $ runOneCommand eh gCmd)+    case b of+      Nothing -> return ()+      Just success -> do+        unless success $ maybe (return ()) lift sourceErrorHandler+        unmask $ runCommands' eh sourceErrorHandler gCmd++-- | Evaluate a single line of user input (either :<command> or Haskell code).+-- A result of Nothing means there was no more input to process.+-- Otherwise the result is Just b where b is True if the command succeeded;+-- this is relevant only to ghc -e, which will exit with status 1+-- if the command was unsuccessful. GHCi will continue in either case.+-- TODO: replace Bool with CmdExecOutcome+runOneCommand :: (SomeException -> GHCi Bool) -> InputT GHCi (Maybe String)+            -> InputT GHCi (Maybe Bool)+runOneCommand eh gCmd = do+  -- run a previously queued command if there is one, otherwise get new+  -- input from user+  mb_cmd0 <- noSpace (lift queryQueue)+  mb_cmd1 <- maybe (noSpace gCmd) (return . Just) mb_cmd0+  case mb_cmd1 of+    Nothing -> return Nothing+    Just c  -> do+      st <- getGHCiState+      ghciHandle (\e -> lift $ eh e >>= return . Just) $+        handleSourceError printErrorAndFail $+          cmd_wrapper st $ doCommand c+               -- source error's are handled by runStmt+               -- is the handler necessary here?+  where+    printErrorAndFail err = do+        printGhciException err+        return $ Just False     -- Exit ghc -e, but not GHCi++    noSpace q = q >>= maybe (return Nothing)+                            (\c -> case removeSpaces c of+                                     ""   -> noSpace q+                                     ":{" -> multiLineCmd q+                                     _    -> return (Just c) )+    multiLineCmd q = do+      st <- getGHCiState+      let p = prompt st+      setGHCiState st{ prompt = prompt_cont st }+      mb_cmd <- collectCommand q "" `MC.finally`+                modifyGHCiState (\st' -> st' { prompt = p })+      return mb_cmd+    -- we can't use removeSpaces for the sublines here, so+    -- multiline commands are somewhat more brittle against+    -- fileformat errors (such as \r in dos input on unix),+    -- we get rid of any extra spaces for the ":}" test;+    -- we also avoid silent failure if ":}" is not found;+    -- and since there is no (?) valid occurrence of \r (as+    -- opposed to its String representation, "\r") inside a+    -- ghci command, we replace any such with ' ' (argh:-(+    collectCommand q c = q >>=+      maybe (liftIO (ioError collectError))+            (\l->if removeSpaces l == ":}"+                 then return (Just c)+                 else collectCommand q (c ++ "\n" ++ map normSpace l))+      where normSpace '\r' = ' '+            normSpace   x  = x+    -- SDM (2007-11-07): is userError the one to use here?+    collectError = userError "unterminated multiline command :{ .. :}"++    cmdOutcome :: CmdExecOutcome -> Maybe Bool+    cmdOutcome CleanExit = Nothing+    cmdOutcome CmdSuccess = Just True+    cmdOutcome CmdFailure = Just False++    -- | Handle a line of input+    doCommand :: String -> InputT GHCi CommandResult++    -- command+    doCommand stmt | stmt'@(':' : cmd) <- removeSpaces stmt = do+      (stats, result) <- runWithStats (const Nothing) $ specialCommand cmd+      return $ CommandComplete stmt' (cmdOutcome <$> result) stats++    -- haskell+    doCommand stmt = do+      -- if 'stmt' was entered via ':{' it will contain '\n's+      let stmt_nl_cnt = length [ () | '\n' <- stmt ]+      ml <- lift $ isOptionSet Multiline+      if ml && stmt_nl_cnt == 0 -- don't trigger automatic multi-line mode for ':{'-multiline input+        then do+          fst_line_num <- line_number <$> getGHCiState+          mb_stmt <- checkInputForLayout stmt gCmd+          case mb_stmt of+            Nothing -> return CommandIncomplete+            Just ml_stmt -> do+              -- temporarily compensate line-number for multi-line input+              (stats, result) <- runAndPrintStats runAllocs $ lift $+                runStmtWithLineNum fst_line_num ml_stmt GHC.RunToCompletion+              return $+                CommandComplete ml_stmt (Just . runSuccess <$> result) stats+        else do -- single line input and :{ - multiline input+          last_line_num <- line_number <$> getGHCiState+          -- reconstruct first line num from last line num and stmt+          let fst_line_num | stmt_nl_cnt > 0 = last_line_num - (stmt_nl_cnt2 + 1)+                           | otherwise = last_line_num -- single line input+              stmt_nl_cnt2 = length [ () | '\n' <- stmt' ]+              stmt' = dropLeadingWhiteLines stmt -- runStmt doesn't like leading empty lines+          -- temporarily compensate line-number for multi-line input+          (stats, result) <- runAndPrintStats runAllocs $ lift $+            runStmtWithLineNum fst_line_num stmt' GHC.RunToCompletion+          return $ CommandComplete stmt' (Just . runSuccess <$> result) stats++    -- runStmt wrapper for temporarily overridden line-number+    runStmtWithLineNum :: Int -> String -> SingleStep+                       -> GHCi (Maybe GHC.ExecResult)+    runStmtWithLineNum lnum stmt step = do+        st0 <- getGHCiState+        setGHCiState st0 { line_number = lnum }+        result <- runStmt stmt step+        -- restore original line_number+        getGHCiState >>= \st -> setGHCiState st { line_number = line_number st0 }+        return result++    -- note: this is subtly different from 'unlines . dropWhile (all isSpace) . lines'+    dropLeadingWhiteLines s | (l0,'\n':r) <- break (=='\n') s+                            , all isSpace l0 = dropLeadingWhiteLines r+                            | otherwise = s+++-- #4316+-- lex the input.  If there is an unclosed layout context, request input+checkInputForLayout+  :: GhciMonad m => String -> m (Maybe String) -> m (Maybe String)+checkInputForLayout stmt getStmt = do+   dflags' <- getDynFlags+   let dflags = xopt_set dflags' LangExt.AlternativeLayoutRule+   st0 <- getGHCiState+   let buf'   =  stringToStringBuffer stmt+       loc    = mkRealSrcLoc (fsLit (progname st0)) (line_number st0) 1+       pstate = Lexer.initParserState (initParserOpts dflags) buf' loc+   case Lexer.unP goToEnd pstate of+     (Lexer.POk _ False) -> return $ Just stmt+     _other              -> do+       st1 <- getGHCiState+       let p = prompt st1+       setGHCiState st1{ prompt = prompt_cont st1 }+       mb_stmt <- ghciHandle (\ex -> case fromException ex of+                            Just UserInterrupt -> return Nothing+                            _ -> case fromException ex of+                                 Just ghce ->+                                   do liftIO (print (ghce :: GhcException))+                                      return Nothing+                                 _other -> liftIO (Exception.throwIO ex))+                     getStmt+       modifyGHCiState (\st' -> st' { prompt = p })+       -- the recursive call does not recycle parser state+       -- as we use a new string buffer+       case mb_stmt of+         Nothing  -> return Nothing+         Just str -> if str == ""+           then return $ Just stmt+           else do+             checkInputForLayout (stmt++"\n"++str) getStmt+     where goToEnd = do+             eof <- Lexer.nextIsEOF+             if eof+               then Lexer.activeContext+               else Lexer.lexer False return >> goToEnd++enqueueCommands :: GhciMonad m => [String] -> m ()+enqueueCommands cmds = do+  -- make sure we force any exceptions in the commands while we're+  -- still inside the exception handler, otherwise bad things will+  -- happen (see #10501)+  cmds `deepseq` return ()+  modifyGHCiState $ \st -> st{ cmdqueue = cmds ++ cmdqueue st }++-- | Entry point to execute some haskell code from user.+-- The return value True indicates success, as in `runOneCommand`.+runStmt :: GhciMonad m => String -> SingleStep -> m (Maybe GHC.ExecResult)+runStmt input step = do+  pflags <- initParserOpts <$> GHC.getInteractiveDynFlags+  -- In GHCi, we disable `-fdefer-type-errors`, as well as `-fdefer-type-holes`+  -- and `-fdefer-out-of-scope-variables` for **naked expressions**. The+  -- declarations and statements are not affected.+  -- See Note [Deferred type errors in GHCi] in GHC.Tc.Module+  st <- getGHCiState+  let source = progname st+  let line = line_number st++  -- Add any LANGUAGE/OPTIONS_GHC pragmas we find find.+  set_pragmas pflags++  if | GHC.isStmt pflags input -> do+         hsc_env <- GHC.getSession+         mb_stmt <- liftIO (runInteractiveHsc hsc_env (hscParseStmtWithLocation source line input))+         case mb_stmt of+           Nothing ->+             -- empty statement / comment+             return (Just exec_complete)+           Just stmt ->+             run_stmt stmt++     -- Otherwise assume a declaration (or a list of declarations)+     -- and/or import(s) (#20473).+     -- Note: `GHC.isDecl` returns False on input like+     -- `data Infix a b = a :@: b; infixl 4 :@:`+     -- and should therefore not be used here.+     | otherwise -> do+         hsc_env <- GHC.getSession+         let !ic = hsc_IC hsc_env  -- Bang-pattern to avoid space leaks+         setDumpFilePrefix ic+           -- `-ddump-to-file` must work for normal GHCi compilations /+           --     evaluations. (#17500)+         -- Use >>= \case instead of MonadFail desugaring to take into+         -- consideration `instance XXModule p = DataConCantHappen`.+         -- Tracked in #15681+         liftIO (hscParseModuleWithLocation hsc_env source line input) >>= \case+           HsModule { hsmodDecls = decls, hsmodImports = imports } -> do+             run_imports imports+             run_decls decls+  where+    exec_complete = GHC.ExecComplete (Right []) 0++    run_imports imports = mapM_ (addImportToContext . unLoc) imports++    set_pragmas pflags =+      let stringbuf = stringToStringBuffer input+          (_msgs, loc_opts) = Header.getOptions pflags stringbuf "<interactive>"+          opts = unLoc <$> loc_opts+      in setOptions opts++    run_stmt :: GhciMonad m => GhciLStmt GhcPs -> m (Maybe GHC.ExecResult)+    run_stmt stmt = do+           m_result <- GhciMonad.runStmt stmt input step+           case m_result of+               Nothing     -> return Nothing+               Just result -> Just <$> afterRunStmt (const True) result++    -- `x = y` (a declaration) should be treated as `let x = y` (a statement).+    -- The reason is because GHCi wasn't designed to support `x = y`, but then+    -- b98ff3 (#7253) added support for it, except it did not do a good job and+    -- caused problems like:+    --+    --  - not adding the binders defined this way in the necessary places caused+    --    `x = y` to not work in some cases (#12091).+    --  - some GHCi command crashed after `x = y` (#15721)+    --  - warning generation did not work for `x = y` (#11606)+    --  - because `x = y` is a declaration (instead of a statement) differences+    --    in generated code caused confusion (#16089)+    --+    -- Instead of dealing with all these problems individually here we fix this+    -- mess by just treating `x = y` as `let x = y`.+    run_decls :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe GHC.ExecResult)+    -- Only turn `FunBind` and `VarBind` into statements, other bindings+    -- (e.g. `PatBind`) need to stay as decls.+    run_decls [L l (ValD _ bind@FunBind{})] = run_stmt (mk_stmt (locA l) bind)+    run_decls [L l (ValD _ bind@VarBind{})] = run_stmt (mk_stmt (locA l) bind)+    -- Note that any `x = y` declarations below will be run as declarations+    -- instead of statements (e.g. `...; x = y; ...`)+    run_decls decls = do+      -- In the new IO library, read handles buffer data even if the Handle+      -- is set to NoBuffering.  This causes problems for GHCi where there+      -- are really two stdin Handles.  So we flush any bufferred data in+      -- GHCi's stdin Handle here (only relevant if stdin is attached to+      -- a file, otherwise the read buffer can't be flushed).+      _ <- liftIO $ tryIO $ hFlushAll stdin+      m_result <- GhciMonad.runDecls' decls+      forM m_result $ \result ->+        afterRunStmt (const True) (GHC.ExecComplete (Right result) 0)++    mk_stmt :: SrcSpan -> HsBind GhcPs -> GhciLStmt GhcPs+    mk_stmt loc bind =+      let+        la  = L (noAnnSrcSpan loc)+        la' = L (noAnnSrcSpan loc)+      in la (LetStmt noAnn (HsValBinds noAnn (ValBinds NoAnnSortKey (unitBag (la' bind)) [])))++    setDumpFilePrefix :: GHC.GhcMonad m => InteractiveContext -> m () -- #17500+    setDumpFilePrefix ic = do+        dflags <- GHC.getInteractiveDynFlags+        GHC.setInteractiveDynFlags dflags { dumpPrefix = modStr ++ "." }+      where+        modStr = moduleNameString $ moduleName $ icInteractiveModule $ ic++-- | Clean up the GHCi environment after a statement has run+afterRunStmt :: GhciMonad m+             => (SrcSpan -> Bool) -> GHC.ExecResult -> m GHC.ExecResult+afterRunStmt step_here run_result = do+  resumes <- GHC.getResumeContext+  case run_result of+     GHC.ExecComplete{..} ->+       case execResult of+          Left ex -> liftIO $ Exception.throwIO ex+          Right names -> do+            show_types <- isOptionSet ShowType+            when show_types $ printTypeOfNames names+     GHC.ExecBreak names mb_info+         | first_resume : _ <- resumes+         , isNothing  mb_info ||+           step_here (GHC.resumeSpan first_resume) -> do+               mb_id_loc <- toBreakIdAndLocation mb_info+               let bCmd = maybe "" ( \(_,l) -> onBreakCmd l ) mb_id_loc+               if (null bCmd)+                 then printStoppedAtBreakInfo first_resume names+                 else enqueueCommands [bCmd]+               -- run the command set with ":set stop <cmd>"+               st <- getGHCiState+               enqueueCommands [stop st]+               return ()+         | otherwise -> resume step_here GHC.SingleStep Nothing >>=+                        afterRunStmt step_here >> return ()++  flushInterpBuffers+  withSignalHandlers $ do+     b <- isOptionSet RevertCAFs+     when b revertCAFs++  return run_result++runSuccess :: Maybe GHC.ExecResult -> Bool+runSuccess run_result+  | Just (GHC.ExecComplete { execResult = Right _ }) <- run_result = True+  | otherwise = False++runAllocs :: Maybe GHC.ExecResult -> Maybe Integer+runAllocs m = do+  res <- m+  case res of+    GHC.ExecComplete{..} -> Just (fromIntegral execAllocation)+    _ -> Nothing++toBreakIdAndLocation :: GhciMonad m+                     => Maybe GHC.BreakInfo -> m (Maybe (Int, BreakLocation))+toBreakIdAndLocation Nothing = return Nothing+toBreakIdAndLocation (Just inf) = do+  let md = GHC.breakInfo_module inf+      nm = GHC.breakInfo_number inf+  st <- getGHCiState+  return $ listToMaybe [ id_loc | id_loc@(_,loc) <- IntMap.assocs (breaks st),+                                  breakModule loc == md,+                                  breakTick loc == nm ]++printStoppedAtBreakInfo :: GHC.GhcMonad m => Resume -> [Name] -> m ()+printStoppedAtBreakInfo res names = do+  printForUser $ pprStopped res+  --  printTypeOfNames session names+  let namesSorted = sortBy compareNames names+  tythings <- catMaybes `liftM` mapM GHC.lookupName namesSorted+  docs <- mapM pprTypeAndContents [i | AnId i <- tythings]+  printForUserPartWay $ vcat docs++printTypeOfNames :: GHC.GhcMonad m => [Name] -> m ()+printTypeOfNames names+ = mapM_ (printTypeOfName ) $ sortBy compareNames names++compareNames :: Name -> Name -> Ordering+compareNames = on compare getOccString S.<> on SrcLoc.leftmost_smallest getSrcSpan++printTypeOfName :: GHC.GhcMonad m => Name -> m ()+printTypeOfName n+   = do maybe_tything <- GHC.lookupName n+        case maybe_tything of+            Nothing    -> return ()+            Just thing -> printTyThing thing+++data MaybeCommand = GotCommand Command | BadCommand | NoLastCommand++-- | Entry point for execution a ':<command>' input from user+specialCommand :: String -> InputT GHCi CmdExecOutcome+specialCommand ('!':str) = lift $ shellEscape (dropWhile isSpace str)+specialCommand str = do+  let (cmd,rest) = break isSpace str+  maybe_cmd <- lookupCommand cmd+  htxt <- short_help <$> getGHCiState+  case maybe_cmd of+    GotCommand cmd -> (cmdAction cmd) (dropWhile isSpace rest)+    BadCommand ->+      do liftIO $ hPutStr stderr ("unknown command ':" ++ cmd ++ "'\n"+                           ++ htxt)+         return CmdFailure+    NoLastCommand ->+      do liftIO $ hPutStr stderr ("there is no last command to perform\n"+                           ++ htxt)+         return CmdFailure++shellEscape :: MonadIO m => String -> m CmdExecOutcome+shellEscape str = liftIO $ do+  exitCode <- system str+  case exitCode of+    ExitSuccess -> return CmdSuccess+    ExitFailure _ -> return CmdFailure++lookupCommand :: GhciMonad m => String -> m (MaybeCommand)+lookupCommand "" = do+  st <- getGHCiState+  case last_command st of+      Just c -> return $ GotCommand c+      Nothing -> return NoLastCommand+lookupCommand str = do+  mc <- lookupCommand' str+  modifyGHCiState (\st -> st { last_command = mc })+  return $ case mc of+           Just c -> GotCommand c+           Nothing -> BadCommand++lookupCommand' :: GhciMonad m => String -> m (Maybe Command)+lookupCommand' ":" = return Nothing+lookupCommand' str' = do+  macros    <- ghci_macros <$> getGHCiState+  ghci_cmds <- ghci_commands <$> getGHCiState++  let ghci_cmds_nohide = filter (not . cmdHidden) ghci_cmds++  let (str, xcmds) = case str' of+          ':' : rest -> (rest, [])     -- "::" selects a builtin command+          _          -> (str', macros) -- otherwise include macros in lookup++      lookupExact  s = find $ (s ==)              . cmdName+      lookupPrefix s = find $ (s `isPrefixOptOf`) . cmdName++      -- hidden commands can only be matched exact+      builtinPfxMatch = lookupPrefix str ghci_cmds_nohide++  -- first, look for exact match (while preferring macros); then, look+  -- for first prefix match (preferring builtins), *unless* a macro+  -- overrides the builtin; see #8305 for motivation+  return $ lookupExact str xcmds <|>+           lookupExact str ghci_cmds <|>+           (builtinPfxMatch >>= \c -> lookupExact (cmdName c) xcmds) <|>+           builtinPfxMatch <|>+           lookupPrefix str xcmds++-- This predicate is for prefix match with a command-body and+-- suffix match with an option, such as `!`.+-- The current implementation assumes only the `!` character+-- as the option delimiter.+-- See also #17345+isPrefixOptOf :: String -> String -> Bool+isPrefixOptOf s x = let (body, opt) = break (== '!') s+                    in  (body `isPrefixOf` x) && (opt `isSuffixOf` x)++getCurrentBreakSpan :: GHC.GhcMonad m => m (Maybe SrcSpan)+getCurrentBreakSpan = do+  resumes <- GHC.getResumeContext+  case resumes of+    [] -> return Nothing+    (r:_) -> do+        let ix = GHC.resumeHistoryIx r+        if ix == 0+           then return (Just (GHC.resumeSpan r))+           else do+                let hist = GHC.resumeHistory r !! (ix-1)+                pan <- GHC.getHistorySpan hist+                return (Just pan)++getCallStackAtCurrentBreakpoint :: GHC.GhcMonad m => m (Maybe [String])+getCallStackAtCurrentBreakpoint = do+  resumes <- GHC.getResumeContext+  case resumes of+    [] -> return Nothing+    (r:_) -> do+       interp <- hscInterp <$> GHC.getSession+       Just <$> liftIO (costCentreStackInfo interp (GHC.resumeCCS r))++getCurrentBreakModule :: GHC.GhcMonad m => m (Maybe Module)+getCurrentBreakModule = do+  resumes <- GHC.getResumeContext+  case resumes of+    [] -> return Nothing+    (r:_) -> do+        let ix = GHC.resumeHistoryIx r+        if ix == 0+           then return (GHC.breakInfo_module `liftM` GHC.resumeBreakInfo r)+           else do+                let hist = GHC.resumeHistory r !! (ix-1)+                return $ Just $ GHC.getHistoryModule  hist++-----------------------------------------------------------------------------+--+-- Commands+--+-----------------------------------------------------------------------------++noArgs :: MonadIO m => m () -> String -> m ()+noArgs m "" = m+noArgs _ _  = liftIO $ putStrLn "This command takes no arguments"++withSandboxOnly :: GHC.GhcMonad m => String -> m () -> m ()+withSandboxOnly cmd this = do+   dflags <- getDynFlags+   if not (gopt Opt_GhciSandbox dflags)+      then printForUser (text cmd <+>+                         text "is not supported with -fno-ghci-sandbox")+      else this++-----------------------------------------------------------------------------+-- :help++help :: GhciMonad m => String -> m ()+help _ = do+    txt <- long_help `fmap` getGHCiState+    liftIO $ putStr txt++-----------------------------------------------------------------------------+-- :info++info :: GHC.GhcMonad m => Bool -> String -> m ()+info _ "" = throwGhcException (CmdLineError "syntax: ':i <thing-you-want-info-about>'")+info allInfo s  = handleSourceError printGhciException $ do+    forM_ (words s) $ \thing -> do+      sdoc <- infoThing allInfo thing+      rendered <- showSDocForUser' sdoc+      liftIO (putStrLn rendered)++infoThing :: GHC.GhcMonad m => Bool -> String -> m SDoc+infoThing allInfo str = do+    names     <- GHC.parseName str+    mb_stuffs <- mapM (GHC.getInfo allInfo) names+    let filtered = filterOutChildren (\(t,_f,_ci,_fi,_sd) -> t)+                                     (catMaybes (NE.toList mb_stuffs))+    return $ vcat (intersperse (text "") $ map pprInfo filtered)++  -- Filter out names whose parent is also there. Good+  -- example is '[]', which is both a type and data+  -- constructor in the same type+filterOutChildren :: (a -> TyThing) -> [a] -> [a]+filterOutChildren get_thing xs+  = filterOut has_parent xs+  where+    all_names = mkNameSet (map (getName . get_thing) xs)+    has_parent x = case tyThingParent_maybe (get_thing x) of+                     Just p  -> getName p `elemNameSet` all_names+                     Nothing -> False++pprInfo :: (TyThing, Fixity, [GHC.ClsInst], [GHC.FamInst], SDoc) -> SDoc+pprInfo (thing, fixity, cls_insts, fam_insts, docs)+  =  docs+  $$ pprTyThingInContextLoc thing+  $$ showFixity thing fixity+  $$ vcat (map GHC.pprInstance cls_insts)+  $$ vcat (map GHC.pprFamInst  fam_insts)++-----------------------------------------------------------------------------+-- :main++runMain :: GhciMonad m => String -> m ()+runMain s = case toArgsNoLoc s of+              Left err   -> liftIO (hPutStrLn stderr err)+              Right args -> doWithMain (doWithArgs args)+  where+    doWithMain fun = do+      dflags  <- getDynFlags+      let main = fromMaybe "main" (mainFunIs dflags)+      handleSourceError printErrAndMaybeExit $ do+        -- doing this will prevent the main to run when it is not in scope+        -- this might seem useless, but it doesn't suggest other functions+        -- to be used, which is exactly what we want here. See #23996.+        _ <- GHC.parseName main++        -- Wrap the main function in 'void' to discard its value instead+        -- of printing it (#9086). See Haskell 2010 report Chapter 5.+        fun $ "Control.Monad.void (" ++ main ++ ")"+++++-----------------------------------------------------------------------------+-- :run++runRun :: GhciMonad m => String -> m ()+runRun s = case toCmdArgs s of+           Left err          -> liftIO (hPutStrLn stderr err)+           Right (cmd, args) -> doWithArgs args cmd++doWithArgs :: GhciMonad m => [String] -> String -> m ()+doWithArgs args cmd = enqueueCommands ["System.Environment.withArgs " +++                                       show args ++ " (" ++ cmd ++ ")"]++{-+Akin to @Prelude.words@, but acts like the Bourne shell, treating+quoted strings as Haskell Strings, and also parses Haskell [String]+syntax.+-}++getCmd :: String -> Either String             -- Error+                           (String, String) -- (Cmd, Rest)+getCmd s = case break isSpace $ dropWhile isSpace s of+           ([], _) -> Left ("Couldn't find command in " ++ show s)+           res -> Right res++toCmdArgs :: String -> Either String             -- Error+                              (String, [String]) -- (Cmd, Args)+toCmdArgs s = case getCmd s of+              Left err -> Left err+              Right (cmd, s') -> case toArgsNoLoc s' of+                                 Left err -> Left err+                                 Right args -> Right (cmd, args)++-- wrapper around GHC.Parser.Header.toArgs, but without locations+toArgsNoLoc :: String -> Either String [String]+toArgsNoLoc str = map unLoc <$> toArgs fake_loc str+  where+    fake_loc = mkRealSrcLoc (fsLit "<interactive>") 1 1+    -- this should never be seen, because it's discarded with the `map unLoc`++-----------------------------------------------------------------------------+-- :cd++changeDirectory :: GhciMonad m => String -> m ()+changeDirectory "" = do+  -- :cd on its own changes to the user's home directory+  either_dir <- liftIO $ tryIO getHomeDirectory+  case either_dir of+     Left _e -> return ()+     Right dir -> changeDirectory dir+changeDirectory dir = do+  graph <- GHC.getModuleGraph+  when (not (null $ GHC.mgModSummaries graph)) $+        liftIO $ putStrLn "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed."+  -- delete defined breakpoints and clear the interface file cache (#1620)+  clearCaches+  setContextAfterLoad False Nothing+  GHC.workingDirectoryChanged+  dir' <- expandPath dir+  liftIO $ setCurrentDirectory dir'+  -- With -fexternal-interpreter, we have to change the directory of the subprocess too.+  -- (this gives consistent behaviour with and without -fexternal-interpreter)+  interp <- hscInterp <$> GHC.getSession+  case interpInstance interp of+    ExternalInterp {} -> do+      fhv <- compileGHCiExpr $+        "System.Directory.setCurrentDirectory " ++ show dir'+      liftIO $ evalIO interp fhv+    _ -> pure ()++trySuccess :: GhciMonad m => m SuccessFlag -> m SuccessFlag+trySuccess act =+    handleSourceError (\e -> do printErrAndMaybeExit e -- immediately exit fith failure if in ghc -e+                                pure Failed) act++-----------------------------------------------------------------------------+-- :edit++editFile :: GhciMonad m => String -> m ()+editFile str =+  do file <- if null str then chooseEditFile else expandPath str+     st <- getGHCiState+     errs <- liftIO $ readIORef $ lastErrorLocations st+     let cmd = editor st+     when (null cmd)+       $ throwGhcException (CmdLineError "editor not set, use :set editor")+     lineOpt <- liftIO $ do+         let sameFile p1 p2 = liftA2 (==) (canonicalizePath p1) (canonicalizePath p2)+              `catchIO` (\_ -> return False)++         curFileErrs <- filterM (\(f, _) -> unpackFS f `sameFile` file) errs+         return $ case curFileErrs of+             (_, line):_ -> " +" ++ show line+             _ -> ""+     let cmdArgs = ' ':(file ++ lineOpt)+     code <- liftIO $ system (cmd ++ cmdArgs)++     when (code == ExitSuccess)+       $ reloadModule ""++-- The user didn't specify a file so we pick one for them.+-- Our strategy is to pick the first module that failed to load,+-- or otherwise the first target.+--+-- XXX: Can we figure out what happened if the dependency analysis fails+--      (e.g., because the porgrammeer mistyped the name of a module)?+-- XXX: Can we figure out the location of an error to pass to the editor?+-- XXX: if we could figure out the list of errors that occurred during the+-- last load/reaload, then we could start the editor focused on the first+-- of those.+chooseEditFile :: GHC.GhcMonad m => m String+chooseEditFile =+  do let hasFailed (GHC.ModuleNode _deps x) = fmap not $ isLoadedModSummary x+         hasFailed _ = return False++     graph <- GHC.getModuleGraph+     failed_graph <-+       GHC.mkModuleGraph <$> filterM hasFailed (GHC.mgModSummaries' graph)+     let order g  = flattenSCCs $ filterToposortToModules $+           GHC.topSortModuleGraph True g Nothing+         pick xs  = case xs of+                      x : _ -> GHC.ml_hs_file (GHC.ms_location x)+                      _     -> Nothing++     case pick (order failed_graph) of+       Just file -> return file+       Nothing   ->+         do targets <- GHC.getTargets+            case msum (map fromTarget targets) of+              Just file -> return file+              Nothing   -> throwGhcException (CmdLineError "No files to edit.")++  where fromTarget GHC.Target { targetId = GHC.TargetFile f _ } = Just f+        fromTarget _ = Nothing -- when would we get a module target?+++-----------------------------------------------------------------------------+-- :def++defineMacro :: GhciMonad m => Bool{-overwrite-} -> String -> m ()+defineMacro _ (':':_) = (liftIO $ hPutStrLn stderr+                          "macro name cannot start with a colon")+                            >> failIfExprEvalMode+defineMacro _ ('!':_) = (liftIO $ hPutStrLn stderr+                          "macro name cannot start with an exclamation mark")+                            >> failIfExprEvalMode+                          -- little code duplication allows to grep error msg+defineMacro overwrite s = do+  let (macro_name, definition) = break isSpace s+  macros <- ghci_macros <$> getGHCiState+  let defined = map cmdName macros+  if null macro_name+        then if null defined+                then liftIO $ putStrLn "no macros defined"+                else liftIO $ putStr ("the following macros are defined:\n" +++                                      unlines defined)+  else do+    isCommand <- isJust <$> lookupCommand' macro_name+    let check_newname+          | macro_name `elem` defined = throwGhcException (CmdLineError+            ("macro '" ++ macro_name ++ "' is already defined. " ++ hint))+          | isCommand = throwGhcException (CmdLineError+            ("macro '" ++ macro_name ++ "' overwrites builtin command. " ++ hint))+          | otherwise = return ()+        hint = " Use ':def!' to overwrite."++    unless overwrite check_newname+    -- compile the expression+    handleSourceError printErrAndMaybeExit $ do+      step <- getGhciStepIO+      expr <- GHC.parseExpr definition+      -- > ghciStepIO . definition :: String -> IO String+      let stringTy :: LHsType GhcPs+          stringTy = nlHsTyVar NotPromoted stringTyCon_RDR+          ioM :: LHsType GhcPs -- AZ+          ioM = nlHsTyVar NotPromoted (getRdrName ioTyConName) `nlHsAppTy` stringTy+          body = nlHsVar compose_RDR `mkHsApp` (nlHsPar step)+                                     `mkHsApp` (nlHsPar expr)+          tySig = mkHsWildCardBndrs $ noLocA $ mkHsImplicitSigType $+                  nlHsFunTy stringTy ioM+          new_expr = L (getLoc expr) $ ExprWithTySig noAnn body tySig+      hv <- GHC.compileParsedExprRemote new_expr++      let newCmd = Command { cmdName = macro_name+                           , cmdAction = lift . runMacro hv+                           , cmdHidden = False+                           , cmdCompletionFunc = noCompletion+                           }++      -- later defined macros have precedence+      modifyGHCiState $ \s ->+        let filtered = [ cmd | cmd <- macros, cmdName cmd /= macro_name ]+        in s { ghci_macros = newCmd : filtered }++runMacro+  :: GhciMonad m+  => GHC.ForeignHValue  -- String -> IO String+  -> String+  -> m CmdExecOutcome+runMacro fun s = do+  interp <- hscInterp <$> GHC.getSession+  str <- liftIO $ evalStringToIOString interp fun s+  enqueueCommands (lines str)+  return CmdSuccess+++-----------------------------------------------------------------------------+-- :undef++undefineMacro :: GhciMonad m => String -> m ()+undefineMacro str = mapM_ undef (words str)+ where undef macro_name = do+        cmds <- ghci_macros <$> getGHCiState+        if (macro_name `notElem` map cmdName cmds)+           then throwGhcException (CmdLineError+                ("macro '" ++ macro_name ++ "' is not defined"))+           else do+            -- This is a tad racy but really, it's a shell+            modifyGHCiState $ \s ->+                s { ghci_macros = filter ((/= macro_name) . cmdName)+                                         (ghci_macros s) }+++-----------------------------------------------------------------------------+-- :cmd++cmdCmd :: GhciMonad m => String -> m ()+cmdCmd str = handleSourceError printErrAndMaybeExit $ do+    step <- getGhciStepIO+    expr <- GHC.parseExpr str+    -- > ghciStepIO str :: IO String+    let new_expr = step `mkHsApp` expr+    hv <- GHC.compileParsedExprRemote new_expr++    interp <- hscInterp <$> GHC.getSession+    cmds <- liftIO $ evalString interp hv+    enqueueCommands (lines cmds)++-- | Generate a typed ghciStepIO expression+-- @ghciStepIO :: Ty String -> IO String@.+getGhciStepIO :: GHC.GhcMonad m => m (LHsExpr GhcPs)+getGhciStepIO = do+  ghciTyConName <- GHC.getGHCiMonad+  let stringTy = nlHsTyVar NotPromoted stringTyCon_RDR+      ghciM = nlHsTyVar NotPromoted (getRdrName ghciTyConName) `nlHsAppTy` stringTy+      ioM = nlHsTyVar NotPromoted (getRdrName ioTyConName) `nlHsAppTy` stringTy+      body = nlHsVar (getRdrName ghciStepIoMName)+      tySig = mkHsWildCardBndrs $ noLocA $ mkHsImplicitSigType $+              nlHsFunTy ghciM ioM+  return $ noLocA $ ExprWithTySig noAnn body tySig++-----------------------------------------------------------------------------+-- :check++checkModule :: GhciMonad m => String -> m ()+checkModule m = do+  let modl = GHC.mkModuleName m+  ok <- handleSourceError (\e -> printErrAndMaybeExit e >> return False) $ do+          r <- GHC.typecheckModule =<< GHC.parseModule =<< GHC.getModSummary modl+          dflags <- getDynFlags+          liftIO $ putStrLn $ showSDoc dflags $+           case GHC.moduleInfo r of+             cm | Just scope <- GHC.modInfoTopLevelScope cm ->+                let+                    (loc, glob) = assert (all isExternalName scope) $+                                  partition ((== modl) . GHC.moduleName . GHC.nameModule) scope+                in+                        (text "global names: " <+> ppr glob) $$+                        (text "local  names: " <+> ppr loc)+             _ -> empty+          return True+  afterLoad (successIf ok) Check++-----------------------------------------------------------------------------+-- :doc++docCmd :: GHC.GhcMonad m => String -> m ()+docCmd "" =+  throwGhcException (CmdLineError "syntax: ':doc <thing-you-want-docs-for>'")+docCmd s  = do+  -- TODO: Maybe also get module headers for module names+  names <- GHC.parseName s++  docs <- traverse (buildDocComponents s) names++  let sdocs = pprDocs (NE.toList docs)+      sdocs' = vcat (intersperse (text "") sdocs)+  sdoc <- showSDocForUser' sdocs'+  liftIO (putStrLn sdoc)++data DocComponents =+  DocComponents+    { docs      :: Maybe [HsDoc GhcRn]   -- ^ subject's haddocks+    , sigAndLoc :: Maybe SDoc          -- ^ type signature + category + location+    , argDocs   :: IntMap (HsDoc GhcRn) -- ^ haddocks for arguments+    }++buildDocComponents :: GHC.GhcMonad m => String -> Name -> m DocComponents+buildDocComponents str name = do+  mbThing <- GHC.lookupName name+  let sigAndLoc = sigAndLocDoc str <$> mbThing+  (docs, argDocs)+    <- either handleGetDocsFailure pure+         =<< GHC.getDocs name++  pure DocComponents{..}++-- | Produce output containing the type/kind signature, category, and definition+-- location of a TyThing.+sigAndLocDoc :: String -> TyThing -> SDoc+sigAndLocDoc str tyThing =+  let tyThingTyDoc :: TyThing -> SDoc+      tyThingTyDoc = \case+        AnId i                      -> pprSigmaType $ varType i+        AConLike (RealDataCon dc)   -> pprSigmaType $ dataConDisplayType False dc+        AConLike (PatSynCon patSyn) -> pprPatSynType patSyn+        ATyCon tyCon                -> pprSigmaType $ GHC.tyConKind tyCon+        ACoAxiom _                  -> empty++      tyDoc = tyThingTyDoc tyThing+      sigDoc = text str <+> nest 2 (dcolon <+> tyDoc)+      comment =+        hsep [ char '\t' <> text "--"+             , pprTyThingCategory tyThing+             , text "defined" <+> pprNameDefnLoc (getName tyThing)+             ]+   in hang sigDoc 2 comment++pprDocs :: [DocComponents] -> [SDoc]+pprDocs docs+  | null nonEmptyDocs = pprDoc <$> take 1 docs+  -- elide <has no documentation> if there's at least one non-empty doc (#15784)+  | otherwise = pprDoc <$> nonEmptyDocs+  where+    empty DocComponents{docs = mb_decl_docs, argDocs = arg_docs}+      = maybe True null mb_decl_docs && null arg_docs+    nonEmptyDocs = filter (not . empty) docs++-- TODO: also print arg docs.+pprDoc :: DocComponents -> SDoc+pprDoc DocComponents{sigAndLoc = mb_sig_loc, docs = mb_decl_docs} =+  maybe+    (text "<has no documentation>")+    formatDoc+    mb_decl_docs+  where+    formatDoc doc =+      vcat [ fromMaybe empty mb_sig_loc -- print contextual info (#19055)+           , pprHsDocStrings $ map hsDocString doc+           ]++handleGetDocsFailure :: GHC.GhcMonad m => GetDocsFailure -> m a+handleGetDocsFailure no_docs = do+  dflags <- getDynFlags+  let msg = showPpr dflags no_docs+  throwGhcException $ case no_docs of+    NameHasNoModule {} -> Sorry msg+    NoDocsInIface {} -> InstallationError msg+    InteractiveName -> ProgramError msg++-----------------------------------------------------------------------------+-- :instances++instancesCmd :: String -> InputT GHCi ()+instancesCmd "" =+  throwGhcException (CmdLineError "syntax: ':instances <type-you-want-instances-for>'")+instancesCmd s = do+  handleSourceError printGhciException $ do+    ty <- GHC.parseInstanceHead s+    res <- GHC.getInstancesForType ty++    printForUser $ vcat $ map ppr res++-----------------------------------------------------------------------------+-- :load, :add, :unadd, :reload++-- these are mainly used for displaying a more informative response+data LoadType = Add !Int | Unadd !Int | Load | Reload | Check++isReload :: LoadType -> Bool+isReload Reload = True+isReload _      = False++-- | Sets '-fdefer-type-errors' if 'defer' is true, executes 'load' and unsets+-- '-fdefer-type-errors' again if it has not been set before.+wrapDeferTypeErrors :: GHC.GhcMonad m => m a -> m a+wrapDeferTypeErrors load =+  MC.bracket+    (do+      -- Force originalFlags to avoid leaking the associated HscEnv+      !originalFlags <- getDynFlags+      void $ GHC.setProgramDynFlags $+         setGeneralFlag' Opt_DeferTypeErrors originalFlags+      return originalFlags)+    (\originalFlags -> void $ GHC.setProgramDynFlags originalFlags)+    (\_ -> load)++loadModule :: GhciMonad m => [(FilePath, Maybe UnitId, Maybe Phase)] -> m SuccessFlag+loadModule fs = do+  (_, result) <- runAndPrintStats (const Nothing) (loadModule' fs)+  either (liftIO . Exception.throwIO) return result++-- | @:load@ command+loadModule_ :: GhciMonad m => [FilePath] -> m ()+loadModule_ fs = void $ loadModule (zip3 fs (repeat Nothing) (repeat Nothing))++loadModuleDefer :: GhciMonad m => [FilePath] -> m ()+loadModuleDefer = wrapDeferTypeErrors . loadModule_++loadModule' :: GhciMonad m => [(FilePath, Maybe UnitId, Maybe Phase)] -> m SuccessFlag+loadModule' files = do+  let (filenames, uids, phases) = unzip3 files+  exp_filenames <- mapM expandPath filenames+  let files' = zip3 exp_filenames uids phases+  targets <- mapM (\(file, uid, phase) -> GHC.guessTarget file uid phase) files'++  -- NOTE: we used to do the dependency anal first, so that if it+  -- fails we didn't throw away the current set of modules.  This would+  -- require some re-working of the GHC interface, so we'll leave it+  -- as a ToDo for now.++  hsc_env <- GHC.getSession+  let !dflags = hsc_dflags hsc_env++  let load_module = do+        -- unload first+        _ <- GHC.abandonAll+        clearCaches++        GHC.setTargets targets+        doLoadAndCollectInfo Load LoadAllTargets++  if gopt Opt_GhciLeakCheck dflags+    then do+      -- Grab references to the currently loaded modules so that we can see if+      -- they leak.+      leak_indicators <- liftIO $ getLeakIndicators hsc_env+      success <- load_module+      liftIO $ checkLeakIndicators dflags leak_indicators+      return success+    else+      load_module++-- | @:add@ command+addModule :: GhciMonad m => [FilePath] -> m ()+addModule files = do+  revertCAFs -- always revert CAFs on load/add.+  files' <- mapM expandPath files+  targets <- mapM (\m -> GHC.guessTarget m Nothing Nothing) files'+  targets' <- filterM checkTarget targets+  -- remove old targets with the same id; e.g. for :add *M+  mapM_ GHC.removeTarget [ tid | Target { targetId = tid } <- targets' ]+  mapM_ GHC.addTarget targets'+  _ <- doLoadAndCollectInfo (Add $ length targets') LoadAllTargets+  return ()+  where+    checkTarget :: GhciMonad m => Target -> m Bool+    checkTarget Target { targetId = TargetModule m } = checkTargetModule m+    checkTarget Target { targetId = TargetFile f _ } = checkTargetFile f++    checkTargetModule :: GhciMonad m => ModuleName -> m Bool+    checkTargetModule m = do+      hsc_env <- GHC.getSession+      let home_unit = hsc_home_unit hsc_env+      result <- liftIO $+        Finder.findImportedModule hsc_env m (ThisPkg (homeUnitId home_unit))+      case result of+        Found _ _ -> return True+        _ -> do liftIO $ hPutStrLn stderr ("Module " ++ moduleNameString m ++ " not found")+                failIfExprEvalMode+                return False++    checkTargetFile :: GhciMonad m => String -> m Bool+    checkTargetFile f = do+      exists <- liftIO (doesFileExist f)+      unless exists $ do+        liftIO $ hPutStrLn stderr $ "File " ++ f ++ " not found"+        failIfExprEvalMode+      return exists++-- | @:unadd@ command+unAddModule :: GhciMonad m => [FilePath] -> m ()+unAddModule files = do+  files' <- mapM expandPath files+  targets <- mapM (\m -> GHC.guessTarget m Nothing Nothing) files'+  let removals = [ tid | Target { targetId = tid } <- targets ]+  mapM_ GHC.removeTarget removals+  _ <- doLoadAndCollectInfo (Unadd $ length removals) LoadAllTargets+  return ()++-- | @:reload@ command+reloadModule :: GhciMonad m => String -> m ()+reloadModule m = do+  session <- GHC.getSession+  let home_unit = homeUnitId (hsc_home_unit session)+  ok <- doLoadAndCollectInfo Reload (loadTargets home_unit)+  when (failed ok) failIfExprEvalMode+  where+    loadTargets hu | null m    = LoadAllTargets+                   | otherwise = LoadUpTo (mkModule hu (GHC.mkModuleName m))++reloadModuleDefer :: GhciMonad m => String -> m ()+reloadModuleDefer = wrapDeferTypeErrors . reloadModule++-- | Load/compile targets and (optionally) collect module-info+--+-- This collects the necessary SrcSpan annotated type information (via+-- 'collectInfo') required by the @:all-types@, @:loc-at@, @:type-at@,+-- and @:uses@ commands.+--+-- Meta-info collection is not enabled by default and needs to be+-- enabled explicitly via @:set +c@.  The reason is that collecting+-- the type-information for all sub-spans can be quite expensive, and+-- since those commands are designed to be used by editors and+-- tooling, it's useless to collect this data for normal GHCi+-- sessions.+doLoadAndCollectInfo :: GhciMonad m => LoadType -> LoadHowMuch -> m SuccessFlag+doLoadAndCollectInfo load_type howmuch = do+  doCollectInfo <- isOptionSet CollectInfo++  doLoad load_type howmuch >>= \case+    Succeeded | doCollectInfo -> do+      mod_summaries <- GHC.mgModSummaries <$> getModuleGraph+      -- MP: :set +c code path only works in single package mode atm, hence+      -- this call to isLoaded is ok. collectInfo needs to be modified further to+      -- work with :set +c so I have punted on that for now.+      loaded <- filterM GHC.isLoaded (map ms_mod_name mod_summaries)+      v <- mod_infos <$> getGHCiState+      !newInfos <- collectInfo v loaded+      modifyGHCiState (\st -> st { mod_infos = newInfos })+      pure Succeeded+    flag -> pure flag++doLoad :: GhciMonad m => LoadType -> LoadHowMuch -> m SuccessFlag+doLoad load_type howmuch = do+  -- turn off breakpoints before we load: we can't turn them off later, because+  -- the ModBreaks will have gone away.+  discardActiveBreakPoints++  resetLastErrorLocations+  -- Enable buffering stdout and stderr as we're compiling. Keeping these+  -- handles unbuffered will just slow the compilation down, especially when+  -- compiling in parallel.+  let setBuffering t = liftIO $ do+        hSetBuffering stdout t+        hSetBuffering stderr t+  MC.bracket_ (setBuffering LineBuffering) (setBuffering NoBuffering) $ do+      hmis <- ifaceCache <$> getGHCiState+      -- If GHCi message gets its own configuration at some stage then this will need to be+      -- modified to 'embedUnknownDiagnostic'.+      ok <- trySuccess $ GHC.loadWithCache (Just hmis) (mkUnknownDiagnostic . GHCiMessage) howmuch+      afterLoad ok load_type+      pure ok++++afterLoad+  :: GhciMonad m+  => SuccessFlag+  -> LoadType+  -> m ()+afterLoad ok load_type = do+  revertCAFs  -- always revert CAFs on load.+  discardTickArrays+  loaded_mods <- getLoadedModules+  modulesLoadedMsg ok loaded_mods load_type+  graph <- GHC.getModuleGraph+  setContextAfterLoad (isReload load_type) (Just graph)++setContextAfterLoad :: GhciMonad m => Bool -> Maybe GHC.ModuleGraph -> m ()+setContextAfterLoad keep_ctxt Nothing = do+  setContextKeepingPackageModules keep_ctxt []+setContextAfterLoad keep_ctxt (Just graph) = do+  -- load a target if one is available, otherwise load the topmost module.+  targets <- GHC.getTargets+  loaded_graph <- filterM is_loaded $ GHC.mgModSummaries' graph+  case [ m | Just m <- map (findTarget loaded_graph) targets ] of+        []    ->+          let graph' = flattenSCCs $ filterToposortToModules $+                GHC.topSortModuleGraph True (GHC.mkModuleGraph loaded_graph) Nothing+          in case graph' of+              [] -> setContextKeepingPackageModules keep_ctxt []+              xs -> load_this (last xs)+        (m:_) ->+          load_this m+ where+   is_loaded (GHC.ModuleNode _ ms) = isLoadedModSummary ms+   is_loaded _ = return False++   findTarget mds t+    = case mapMaybe (`matches` t) mds of+        []    -> Nothing+        (m:_) -> Just m++   (GHC.ModuleNode _ summary) `matches` Target { targetId = TargetModule m }+        = if GHC.ms_mod_name summary == m then Just summary else Nothing+   (GHC.ModuleNode _ summary) `matches` Target { targetId = TargetFile f _ }+        | Just f' <- GHC.ml_hs_file (GHC.ms_location summary)   =+          if f == f' then Just summary else Nothing+   _ `matches` _ = Nothing++   load_this summary | m <- GHC.ms_mod summary = do+        is_interp <- GHC.moduleIsInterpreted m+        dflags <- getDynFlags+        let star_ok = is_interp && not (safeLanguageOn dflags)+              -- We import the module with a * iff+              --   - it is interpreted, and+              --   - -XSafe is off (it doesn't allow *-imports)+        let new_ctx | star_ok   = [mkIIModule (GHC.moduleName m)]+                    | otherwise = [mkIIDecl   (GHC.moduleName m)]+        setContextKeepingPackageModules keep_ctxt new_ctx+++-- | Keep any package modules (except Prelude) when changing the context.+setContextKeepingPackageModules+  :: GhciMonad m+  => Bool                 -- True  <=> keep all of remembered_ctx+                          -- False <=> just keep package imports+  -> [InteractiveImport]  -- new context+  -> m ()+setContextKeepingPackageModules keep_ctx trans_ctx = do++  st <- getGHCiState+  let rem_ctx = remembered_ctx st+  new_rem_ctx <- if keep_ctx then return rem_ctx+                             else keepPackageImports rem_ctx+  setGHCiState st{ remembered_ctx = new_rem_ctx,+                   transient_ctx  = filterSubsumed new_rem_ctx trans_ctx }+  setGHCContextFromGHCiState++-- | Filters a list of 'InteractiveImport', clearing out any home package+-- imports so only imports from external packages are preserved.  ('IIModule'+-- counts as a home package import, because we are only able to bring a+-- full top-level into scope when the source is available.)+keepPackageImports+  :: GHC.GhcMonad m => [InteractiveImport] -> m [InteractiveImport]+keepPackageImports = filterM is_pkg_import+  where+     is_pkg_import :: GHC.GhcMonad m => InteractiveImport -> m Bool+     is_pkg_import (IIModule _) = return False+     is_pkg_import (IIDecl d)+         = do pkgqual <- GHC.renameRawPkgQualM (unLoc $ ideclName d) (ideclPkgQual d)+              e <- MC.try $ GHC.findQualifiedModule pkgqual mod_name+              case e :: Either SomeException Module of+                Left _  -> return False+                Right m -> return (not (isMainUnitModule m))+        where+          mod_name = unLoc (ideclName d)++++modulesLoadedMsg :: GHC.GhcMonad m => SuccessFlag -> [GHC.ModSummary] -> LoadType -> m ()+modulesLoadedMsg ok mods load_type = do+  dflags <- getDynFlags+  when (verbosity dflags > 0) $ do+     mod_names <- mapM mod_name mods+     rendered_msg <- showSDocForUser' $+       if gopt Opt_ShowLoadedModules dflags+         then loaded_msg mod_names+         else msg+     liftIO $ putStrLn rendered_msg+  where+    num_mods = length mods+    none_loaded = num_mods == 0++    loaded_msg names =+      let mod_commas+           | null mods = text "none."+           | otherwise = hsep (punctuate comma names) <> text "."+      in status <> text ", modules loaded:" <+> mod_commas++    msg  = status <> comma <+> msg' <> dot+    msg' = case load_type of+      Reload  -> if none_loaded+                   then "no modules to be reloaded"+                   else n_mods num_mods "reloaded"+      Load    -> if none_loaded+                   then "unloaded all modules"+                   else n_mods num_mods "loaded"+      Check   -> n_mods 1 "checked"+      Add   n -> n_mods n "added"+      Unadd n -> n_mods n "unadded"+    n_mods amount action = speakNOf amount "module" <+> action++    status | Succeeded <- ok = "Ok"+           | otherwise       = "Failed"++    mod_name mod = do+        is_interpreted <- GHC.moduleIsBootOrNotObjectLinkable mod+        pure $ if is_interpreted+               then ppr (GHC.ms_mod mod)+               else ppr (GHC.ms_mod mod)+                    <+> parens (text $ normalise $ msObjFilePath mod)+                    -- Fix #9887++-- | Run an 'ExceptT' wrapped 'GhcMonad' while handling source errors+-- and printing 'throwE' strings to 'stderr'. If in expression+-- evaluation mode - throw GhcException and exit.+runExceptGhciMonad :: GhciMonad m => ExceptT SDoc m () -> m ()+runExceptGhciMonad act = handleSourceError printGhciException $+                         either handleErr pure =<<+                         runExceptT act+  where+    handleErr sdoc = do+        rendered <- showSDocForUserQualify sdoc+        liftIO $ hPutStrLn stderr rendered+        failIfExprEvalMode++-- | Inverse of 'runExceptT' for \"pure\" computations+-- (c.f. 'except' for 'Except')+exceptT :: Applicative m => Either e a -> ExceptT e m a+exceptT = ExceptT . pure++-----------------------------------------------------------------------------+-- | @:type@ command. See also Note [TcRnExprMode] in GHC.Tc.Module.++typeOfExpr :: GhciMonad m => String -> m ()+typeOfExpr str = handleSourceError printErrAndMaybeExit $+    case break isSpace str of+      ("+v", _)    -> printForUser (text "`:type +v' has gone; use `:type' instead")+      ("+d", rest) -> do_it GHC.TM_Default (dropWhile isSpace rest)+      _            -> do_it GHC.TM_Inst    str+  where+    do_it mode expr_str+      = do { ty <- GHC.exprType mode expr_str+           ;    printForUser $ sep [ text expr_str+                                   , nest 2 (dcolon <+> pprSigmaType ty)] }++-----------------------------------------------------------------------------+-- | @:type-at@ command++typeAtCmd :: GhciMonad m => String -> m ()+typeAtCmd str = runExceptGhciMonad $ do+    (span',sample) <- exceptT $ parseSpanArg str+    infos      <- lift $ mod_infos <$> getGHCiState+    (info, ty) <- findType infos span' sample+    let mb_rdr_env = case modinfoRdrEnv info of+          Strict.Just rdrs -> Just rdrs+          Strict.Nothing   -> Nothing+    lift $ printForUserGlobalRdrEnv+              mb_rdr_env+              (sep [text sample,nest 2 (dcolon <+> ppr ty)])++-----------------------------------------------------------------------------+-- | @:uses@ command++usesCmd :: GhciMonad m => String -> m ()+usesCmd str = runExceptGhciMonad $ do+    (span',sample) <- exceptT $ parseSpanArg str+    infos  <- lift $ mod_infos <$> getGHCiState+    uses   <- findNameUses infos span' sample+    forM_ uses (liftIO . putStrLn . showSrcSpan)++-----------------------------------------------------------------------------+-- | @:loc-at@ command++locAtCmd :: GhciMonad m => String -> m ()+locAtCmd str = runExceptGhciMonad $ do+    (span',sample) <- exceptT $ parseSpanArg str+    infos    <- lift $ mod_infos <$> getGHCiState+    (_,_,sp) <- findLoc infos span' sample+    liftIO . putStrLn . showSrcSpan $ sp++-----------------------------------------------------------------------------+-- | @:all-types@ command++allTypesCmd :: GhciMonad m => String -> m ()+allTypesCmd _ = runExceptGhciMonad $ do+    infos <- lift $ mod_infos <$> getGHCiState+    forM_ (M.elems infos) $ \mi ->+        forM_ (modinfoSpans mi) (lift . printSpan)+  where+    printSpan span'+      | Just ty <- spaninfoType span' = do+        tyInfo <- (unwords . words) <$>+                  showSDocForUserQualify (pprSigmaType ty)+        liftIO . putStrLn $+            showRealSrcSpan (spaninfoSrcSpan span') ++ ": " ++ tyInfo+      | otherwise = return ()++-----------------------------------------------------------------------------+-- Helpers for locAtCmd/typeAtCmd/usesCmd++-- | Parse a span: <module-name/filepath> <sl> <sc> <el> <ec> <string>+parseSpanArg :: String -> Either SDoc (RealSrcSpan,String)+parseSpanArg s = do+    (fp,s0) <- readAsString (skipWs s)+    s0'     <- skipWs1 s0+    (sl,s1) <- readAsInt s0'+    s1'     <- skipWs1 s1+    (sc,s2) <- readAsInt s1'+    s2'     <- skipWs1 s2+    (el,s3) <- readAsInt s2'+    s3'     <- skipWs1 s3+    (ec,s4) <- readAsInt s3'++    trailer <- case s4 of+        [] -> Right ""+        _  -> skipWs1 s4++    let fs    = mkFastString fp+        span' = mkRealSrcSpan (mkRealSrcLoc fs sl sc)+                              -- End column of RealSrcSpan is the column+                              -- after the end of the span.+                              (mkRealSrcLoc fs el (ec + 1))++    return (span',trailer)+  where+    readAsInt :: String -> Either SDoc (Int,String)+    readAsInt "" = Left "Premature end of string while expecting Int"+    readAsInt s0 = case reads s0 of+        [s_rest] -> Right s_rest+        _        -> Left ("Couldn't read" <+> text (show s0) <+> "as Int")++    readAsString :: String -> Either SDoc (String,String)+    readAsString s0+      | '"':_ <- s0 = case reads s0 of+          [s_rest] -> Right s_rest+          _        -> leftRes+      | s_rest@(_:_,_) <- breakWs s0 = Right s_rest+      | otherwise = leftRes+      where+        leftRes = Left ("Couldn't read" <+> text (show s0) <+> "as String")++    skipWs1 :: String -> Either SDoc String+    skipWs1 (c:cs) | isWs c = Right (skipWs cs)+    skipWs1 s0 = Left ("Expected whitespace in" <+> text (show s0))++    isWs    = (`elem` [' ','\t'])+    skipWs  = dropWhile isWs+    breakWs = break isWs+++-- | Pretty-print \"real\" 'SrcSpan's as+-- @<filename>:(<line>,<col>)-(<line-end>,<col-end>)@+-- while simply unpacking 'UnhelpfulSpan's+showSrcSpan :: SrcSpan -> String+showSrcSpan (UnhelpfulSpan s)  = unpackFS (unhelpfulSpanFS s)+showSrcSpan (RealSrcSpan spn _) = showRealSrcSpan spn++-- | Variant of 'showSrcSpan' for 'RealSrcSpan's+showRealSrcSpan :: RealSrcSpan -> String+showRealSrcSpan spn = concat [ fp, ":(", show sl, ",", show sc+                             , ")-(", show el, ",", show ec, ")"+                             ]+  where+    fp = unpackFS (srcSpanFile spn)+    sl = srcSpanStartLine spn+    sc = srcSpanStartCol  spn+    el = srcSpanEndLine   spn+    -- The end column is the column after the end of the span see the+    -- RealSrcSpan module+    ec = let ec' = srcSpanEndCol    spn in if ec' == 0 then 0 else ec' - 1++-----------------------------------------------------------------------------+-- | @:kind@ command++kindOfType :: GhciMonad m => Bool -> String -> m ()+kindOfType norm str = handleSourceError printErrAndMaybeExit $ do+    (ty, kind) <- GHC.typeKind norm str+    printForUser $ vcat [ text str <+> dcolon <+> pprSigmaType kind+                        , ppWhen norm $ equals <+> pprSigmaType ty ]++-----------------------------------------------------------------------------+-- :quit++quit :: Monad m => String -> m CmdExecOutcome+quit _ = return CleanExit+++-----------------------------------------------------------------------------+-- :script++-- running a script file #1363++scriptCmd :: String -> InputT GHCi ()+scriptCmd ws = do+  case words' ws of+    [s]    -> runScript s+    _      -> throwGhcException (CmdLineError "syntax:  :script <filename>")++-- | A version of 'words' that treats sequences enclosed in double quotes as+-- single words and that does not break on backslash-escaped spaces.+-- E.g., 'words\' "\"lorem ipsum\" dolor"' and 'words\' "lorem\\ ipsum dolor"'+-- yield '["lorem ipsum", "dolor"]'.+-- Used to scan for file paths in 'scriptCmd'.+words' :: String -> [String]+words' s = case dropWhile isSpace s of+  "" -> []+  s'@('\"' : _) | [(w, s'')] <- reads s' -> w : words' s''+  s' -> go id s'+ where+  go acc []                          = [acc []]+  go acc ('\\' : c : cs) | isSpace c = go (acc . (c :)) cs+  go acc (c : cs) | isSpace c = acc [] : words' cs+                  | otherwise = go (acc . (c :)) cs++runScript :: String    -- ^ filename+           -> InputT GHCi ()+runScript filename = do+  filename' <- expandPath filename+  either_script <- liftIO $ tryIO (openFile filename' ReadMode)+  case either_script of+    Left _err    -> throwGhcException (CmdLineError $ "IO error:  \""++filename++"\" "+                      ++(ioeGetErrorString _err))+    Right script -> do+      st <- getGHCiState+      let prog = progname st+          line = line_number st+      setGHCiState st{progname=filename',line_number=0}+      scriptLoop script+      liftIO $ hClose script+      new_st <- getGHCiState+      setGHCiState new_st{progname=prog,line_number=line}+  where scriptLoop script = do+          res <- runOneCommand handler $ fileLoop script+          case res of+            Nothing -> return ()+            Just s  -> if s+              then scriptLoop script+              else return ()++-----------------------------------------------------------------------------+-- :issafe++-- Displaying Safe Haskell properties of a module++isSafeCmd :: GHC.GhcMonad m => String -> m ()+isSafeCmd m =+    case words m of+        [s] | looksLikeModuleName s -> do+            md <- lookupModule s+            isSafeModule md+        [] -> do md <- guessCurrentModule "issafe"+                 isSafeModule md+        _ -> throwGhcException (CmdLineError "syntax:  :issafe <module>")++isSafeModule :: GHC.GhcMonad m => Module -> m ()+isSafeModule m = do+    mb_mod_info <- GHC.getModuleInfo m+    when (isNothing mb_mod_info)+         (throwGhcException $ CmdLineError $ "unknown module: " ++ mname)++    dflags <- getDynFlags+    hsc_env <- GHC.getSession+    let iface = GHC.modInfoIface $ fromJust mb_mod_info+    when (isNothing iface)+         (throwGhcException $ CmdLineError $ "can't load interface file for module: " +++                                    (GHC.moduleNameString $ GHC.moduleName m))++    (msafe, pkgs) <- GHC.moduleTrustReqs m+    let trust  = show $ getSafeMode $ GHC.mi_trust $ fromJust iface+        pkg    = if packageTrusted hsc_env m then "trusted" else "untrusted"+        (good, bad) = tallyPkgs hsc_env pkgs++    -- print info to user...+    liftIO $ putStrLn $ "Trust type is (Module: " ++ trust ++ ", Package: " ++ pkg ++ ")"+    liftIO $ putStrLn $ "Package Trust: " ++ (if packageTrustOn dflags then "On" else "Off")+    when (not $ S.null good)+         (liftIO $ putStrLn $ "Trusted package dependencies (trusted): " +++                        (intercalate ", " $ map (showPpr dflags) (S.toList good)))+    case msafe && S.null bad of+        True -> liftIO $ putStrLn $ mname ++ " is trusted!"+        False -> do+            when (not $ null bad)+                 (liftIO $ putStrLn $ "Trusted package dependencies (untrusted): "+                            ++ (intercalate ", " $ map (showPpr dflags) (S.toList bad)))+            liftIO $ putStrLn $ mname ++ " is NOT trusted!"++  where+    mname = GHC.moduleNameString $ GHC.moduleName m++    packageTrusted hsc_env md+        | isHomeModule (hsc_home_unit hsc_env) md = True+        | otherwise = unitIsTrusted $ unsafeLookupUnit (hsc_units hsc_env) (moduleUnit md)++    tallyPkgs hsc_env deps | not (packageTrustOn dflags) = (S.empty, S.empty)+                          | otherwise = S.partition part deps+        where part pkg   = unitIsTrusted $ unsafeLookupUnitId unit_state pkg+              unit_state = hsc_units hsc_env+              dflags     = hsc_dflags hsc_env++-----------------------------------------------------------------------------+-- :browse++-- Browsing a module's contents++browseCmd :: GHC.GhcMonad m => Bool -> String -> m ()+browseCmd bang m =+  case words m of+    ['*':s] | looksLikeModuleName s -> do+        md <- wantInterpretedModule s+        browseModule bang md False+    [s] | looksLikeModuleName s -> do+        md <- lookupModule s+        browseModule bang md True+    [] -> do md <- guessCurrentModule ("browse" ++ if bang then "!" else "")+             browseModule bang md True+    _ -> throwGhcException (CmdLineError "syntax:  :browse <module>")++guessCurrentModule :: GHC.GhcMonad m => String -> m Module+-- Guess which module the user wants to browse.  Pick+-- modules that are interpreted first.  The most+-- recently-added module occurs last, it seems.+guessCurrentModule cmd = do+  imports <- GHC.getContext+  case imports of+    [] -> throwGhcException $ CmdLineError (':' : cmd ++ ": no current module")+    IIModule m : _ -> GHC.findQualifiedModule NoPkgQual m+    IIDecl d : _ -> do+      pkgqual <- GHC.renameRawPkgQualM (unLoc $ ideclName d) (ideclPkgQual d)+      GHC.findQualifiedModule pkgqual (unLoc (ideclName d))++-- without bang, show items in context of their parents and omit children+-- with bang, show class methods and data constructors separately, and+--            indicate import modules, to aid qualifying unqualified names+-- with sorted, sort items alphabetically+browseModule :: GHC.GhcMonad m => Bool -> Module -> Bool -> m ()+browseModule bang modl exports_only = do+  mb_mod_info <- GHC.getModuleInfo modl+  case mb_mod_info of+    Nothing -> throwGhcException (CmdLineError ("unknown module: " +++                                GHC.moduleNameString (GHC.moduleName modl)))+    Just mod_info -> do+        let names+               | exports_only = GHC.modInfoExports mod_info+               | otherwise    = GHC.modInfoTopLevelScope mod_info+                                `orElse` []++                -- sort alphabetically name, but putting locally-defined+                -- identifiers first. We would like to improve this; see #1799.+            sorted_names = loc_sort local ++ occ_sort external+                where+                (local,external) = assert (all isExternalName names) $+                                   partition ((==modl) . nameModule) names+                occ_sort = sortBy (compare `on` nameOccName)+                -- try to sort by src location. If the first name in our list+                -- has a good source location, then they all should.+                loc_sort ns+                      | n:_ <- ns, isGoodSrcSpan (nameSrcSpan n)+                      = sortBy (SrcLoc.leftmost_smallest `on` nameSrcSpan) ns+                      | otherwise+                      = occ_sort ns++        mb_things <- mapM GHC.lookupName sorted_names+        let filtered_things = filterOutChildren (\t -> t) (catMaybes mb_things)++        rdr_env <- GHC.getGRE++        let things | bang      = catMaybes mb_things+                   | otherwise = filtered_things+            pretty | bang      = pprTyThing showToHeader+                   | otherwise = pprTyThingInContext showToHeader++            labels  [] = text "-- not currently imported"+            labels  l  = text $ intercalate "\n" $ map qualifier l++            qualifier :: Maybe [ModuleName] -> String+            qualifier  = maybe "-- defined locally"+                             (("-- imported via "++) . intercalate ", "+                               . map GHC.moduleNameString)+            importInfo = RdrName.getGRE_NameQualifier_maybes rdr_env++            modNames :: [[Maybe [ModuleName]]]+            modNames   = map (importInfo . GHC.getName) things++            -- annotate groups of imports with their import modules+            -- the default ordering is somewhat arbitrary, so we group+            -- by header and sort groups; the names themselves should+            -- really come in order of source appearance.. (#1799)+            annotate mts = concatMap (\(m,ts)->labels m:ts)+                         $ sortBy cmpQualifiers $ grp mts+              where cmpQualifiers =+                      compare `on` (map (fmap (map (unpackFS . moduleNameFS))) . fst)+            grp []            = []+            grp mts@((m,_):_) = (m,map snd g) : grp ng+              where (g,ng) = partition ((==m).fst) mts++        let prettyThings, prettyThings' :: [SDoc]+            prettyThings = map pretty things+            prettyThings' | bang      = annotate $ zip modNames prettyThings+                          | otherwise = prettyThings++        -- :browse reports qualifiers wrt current context+        rendered_things <- showSDocForUser' (vcat prettyThings')+        liftIO $ putStrLn rendered_things+        -- ToDo: modInfoInstances currently throws an exception for+        -- package modules.  When it works, we can do this:+        --        $$ vcat (map GHC.pprInstance (GHC.modInfoInstances mod_info))+++-----------------------------------------------------------------------------+-- :module++-- Setting the module context.  For details on context handling see+-- "remembered_ctx" and "transient_ctx" in GhciMonad.++moduleCmd :: GhciMonad m => String -> m ()+moduleCmd str+  | all sensible strs = cmd+  | otherwise = throwGhcException (CmdLineError "syntax:  :module [+/-] [*]M1 ... [*]Mn")+  where+    (cmd, strs) =+        case str of+          '+':stuff -> rest addModulesToContext   stuff+          '-':stuff -> rest remModulesFromContext stuff+          stuff     -> rest setContext            stuff++    rest op stuff = (op as bs, stuffs)+       where (as,bs) = partitionWith starred stuffs+             stuffs  = words stuff++    sensible ('*':m) = looksLikeModuleName m+    sensible m       = looksLikeModuleName m++    starred ('*':m) = Left  (GHC.mkModuleName m)+    starred m       = Right (GHC.mkModuleName m)+++-- -----------------------------------------------------------------------------+-- Four ways to manipulate the context:+--   (a) :module +<stuff>:     addModulesToContext+--   (b) :module -<stuff>:     remModulesFromContext+--   (c) :module <stuff>:      setContext+--   (d) import <module>...:   addImportToContext++addModulesToContext :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()+addModulesToContext starred unstarred = restoreContextOnFailure $ do+   addModulesToContext_ starred unstarred++addModulesToContext_ :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()+addModulesToContext_ starred unstarred = do+   mapM_ addII (map mkIIModule starred ++ map mkIIDecl unstarred)+   setGHCContextFromGHCiState++remModulesFromContext :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()+remModulesFromContext  starred unstarred = do+   -- we do *not* call restoreContextOnFailure here.  If the user+   -- is trying to fix up a context that contains errors by removing+   -- modules, we don't want GHC to silently put them back in again.+   mapM_ rm (starred ++ unstarred)+   setGHCContextFromGHCiState+ where+   rm :: GhciMonad m => ModuleName -> m ()+   rm str = do+     m <- moduleName <$> lookupModuleName str+     let filt = filter ((/=) m . iiModuleName)+     modifyGHCiState $ \st ->+        st { remembered_ctx = filt (remembered_ctx st)+           , transient_ctx  = filt (transient_ctx st) }++setContext :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()+setContext starred unstarred = restoreContextOnFailure $ do+  modifyGHCiState $ \st -> st { remembered_ctx = [], transient_ctx = [] }+                                -- delete the transient context+  addModulesToContext_ starred unstarred++addImportToContext :: GhciMonad m => ImportDecl GhcPs -> m ()+addImportToContext idecl = restoreContextOnFailure $ do+  addII (IIDecl idecl)   -- #5836+  setGHCContextFromGHCiState++-- Util used by addImportToContext and addModulesToContext+addII :: GhciMonad m => InteractiveImport -> m ()+addII iidecl = do+  checkAdd iidecl+  modifyGHCiState $ \st ->+     st { remembered_ctx = addNotSubsumed iidecl (remembered_ctx st)+        , transient_ctx = filter (not . (iidecl `iiSubsumes`))+                                 (transient_ctx st)+        }++-- Sometimes we can't tell whether an import is valid or not until+-- we finally call 'GHC.setContext'.  e.g.+--+--   import System.IO (foo)+--+-- will fail because System.IO does not export foo.  In this case we+-- don't want to store the import in the context permanently, so we+-- catch the failure from 'setGHCContextFromGHCiState' and set the+-- context back to what it was.+--+-- See #6007+--+restoreContextOnFailure :: GhciMonad m => m a -> m a+restoreContextOnFailure do_this = do+  st <- getGHCiState+  let rc = remembered_ctx st; tc = transient_ctx st+  do_this `MC.onException` (modifyGHCiState $ \st' ->+     st' { remembered_ctx = rc, transient_ctx = tc })++-- -----------------------------------------------------------------------------+-- Validate a module that we want to add to the context++checkAdd :: GHC.GhcMonad m => InteractiveImport -> m ()+checkAdd ii = do+  dflags <- getDynFlags+  let safe = safeLanguageOn dflags+  case ii of+    IIModule modname+       | safe -> throwGhcException $ CmdLineError "can't use * imports with Safe Haskell"+       | otherwise -> wantInterpretedModuleName modname >> return ()++    IIDecl d -> do+       let modname = unLoc (ideclName d)+       pkgqual <- GHC.renameRawPkgQualM modname (ideclPkgQual d)+       m <- GHC.lookupQualifiedModule pkgqual modname+       when safe $ do+           t <- GHC.isModuleTrusted m+           when (not t) $ throwGhcException $ ProgramError $ ""++-- -----------------------------------------------------------------------------+-- Update the GHC API's view of the context++-- | Sets the GHC context from the GHCi state.  The GHC context is+-- always set this way, we never modify it incrementally.+--+-- We ignore any imports for which the ModuleName does not currently+-- exist.  This is so that the remembered_ctx can contain imports for+-- modules that are not currently loaded, perhaps because we just did+-- a :reload and encountered errors.+--+-- Prelude is added if not already present in the list.  Therefore to+-- override the implicit Prelude import you can say 'import Prelude ()'+-- at the prompt, just as in Haskell source.+--+setGHCContextFromGHCiState :: GhciMonad m => m ()+setGHCContextFromGHCiState = do+  st <- getGHCiState+      -- re-use checkAdd to check whether the module is valid.  If the+      -- module does not exist, we do *not* want to print an error+      -- here, we just want to silently keep the module in the context+      -- until such time as the module reappears again.  So we ignore+      -- the actual exception thrown by checkAdd, using tryBool to+      -- turn it into a Bool.+  iidecls <- filterM (tryBool.checkAdd) (transient_ctx st ++ remembered_ctx st)++  prel_iidecls <- getImplicitPreludeImports iidecls+  valid_prel_iidecls <- filterM (tryBool . checkAdd) prel_iidecls++  extra_imports <- filterM (tryBool . checkAdd) (map IIDecl (extra_imports st))++  GHC.setContext $ iidecls ++ extra_imports ++ valid_prel_iidecls+++getImplicitPreludeImports :: GhciMonad m+                          => [InteractiveImport] -> m [InteractiveImport]+getImplicitPreludeImports iidecls = do+  dflags <- GHC.getInteractiveDynFlags+     -- allow :seti to override -XNoImplicitPrelude+  st <- getGHCiState++  -- We add the prelude imports if there are no *-imports, and we also+  -- allow each prelude import to be subsumed by another explicit import+  -- of the same module.  This means that you can override the prelude import+  -- with "import Prelude hiding (map)", for example.+  let prel_iidecls =+         if xopt LangExt.ImplicitPrelude dflags && not (any isIIModule iidecls)+            then [ IIDecl imp+                 | imp <- prelude_imports st+                 , not (any (sameImpModule imp) iidecls) ]+            else []++  return prel_iidecls++-- -----------------------------------------------------------------------------+-- Utils on InteractiveImport++mkIIModule :: ModuleName -> InteractiveImport+mkIIModule = IIModule++mkIIDecl :: ModuleName -> InteractiveImport+mkIIDecl = IIDecl . simpleImportDecl++iiModules :: [InteractiveImport] -> [ModuleName]+iiModules is = [m | IIModule m <- is]++isIIModule :: InteractiveImport -> Bool+isIIModule (IIModule _) = True+isIIModule _ = False++iiModuleName :: InteractiveImport -> ModuleName+iiModuleName (IIModule m) = m+iiModuleName (IIDecl d)   = unLoc (ideclName d)++preludeModuleName :: ModuleName+preludeModuleName = GHC.mkModuleName "Prelude"++sameImpModule :: ImportDecl GhcPs -> InteractiveImport -> Bool+sameImpModule _ (IIModule _) = False -- we only care about imports here+sameImpModule imp (IIDecl d) = unLoc (ideclName d) == unLoc (ideclName imp)++addNotSubsumed :: InteractiveImport+               -> [InteractiveImport] -> [InteractiveImport]+addNotSubsumed i is+  | any (`iiSubsumes` i) is = is+  | otherwise               = i : filter (not . (i `iiSubsumes`)) is++-- | @filterSubsumed is js@ returns the elements of @js@ not subsumed+-- by any of @is@.+filterSubsumed :: [InteractiveImport] -> [InteractiveImport]+               -> [InteractiveImport]+filterSubsumed is js = filter (\j -> not (any (`iiSubsumes` j) is)) js++-- | Returns True if the left import subsumes the right one.  Doesn't+-- need to be 100% accurate, conservatively returning False is fine.+-- (EXCEPT: (IIModule m) *must* subsume itself, otherwise a panic in+-- plusProv will ensue (#5904))+--+-- Note that an IIModule does not necessarily subsume an IIDecl,+-- because e.g. a module might export a name that is only available+-- qualified within the module itself.+--+-- Note that 'import M' does not necessarily subsume 'import M(foo)',+-- because M might not export foo and we want an error to be produced+-- in that case.+--+iiSubsumes :: InteractiveImport -> InteractiveImport -> Bool+iiSubsumes (IIModule m1) (IIModule m2) = m1==m2+iiSubsumes (IIDecl d1) (IIDecl d2)      -- A bit crude+  =  unLoc (ideclName d1) == unLoc (ideclName d2)+     && ideclAs d1 == ideclAs d2+     && (not (isImportDeclQualified (ideclQualified d1)) || isImportDeclQualified (ideclQualified d2))+     && (ideclImportList d1 `hidingSubsumes` ideclImportList d2)+  where+     _                    `hidingSubsumes` Just (Exactly,L _ []) = True+     Just (Exactly, L _ xs) `hidingSubsumes` Just (Exactly,L _ ys)+                                                           = all (`elem` xs) ys+     h1                   `hidingSubsumes` h2              = h1 == h2+iiSubsumes _ _ = False+++----------------------------------------------------------------------------+-- :set++-- set options in the interpreter.  Syntax is exactly the same as the+-- ghc command line, except that certain options aren't available (-C,+-- -E etc.)+--+-- This is pretty fragile: most options won't work as expected.  ToDo:+-- figure out which ones & disallow them.++setCmd :: GhciMonad m => String -> m ()+setCmd ""   = showOptions False+setCmd "-a" = showOptions True+setCmd str+  = case getCmd str of+    Right ("args",    rest) ->+        case toArgsNoLoc rest of+            Left err -> liftIO (hPutStrLn stderr err)+            Right args -> setArgs args+    Right ("prog",    rest) ->+        case toArgsNoLoc rest of+            Right [prog] -> setProg prog+            _ -> liftIO (hPutStrLn stderr "syntax: :set prog <progname>")++    Right ("prompt",           rest) ->+        setPromptString setPrompt (dropWhile isSpace rest)+                        "syntax: set prompt <string>"+    Right ("prompt-function",  rest) ->+        setPromptFunc setPrompt $ dropWhile isSpace rest+    Right ("prompt-cont",          rest) ->+        setPromptString setPromptCont (dropWhile isSpace rest)+                        "syntax: :set prompt-cont <string>"+    Right ("prompt-cont-function", rest) ->+        setPromptFunc setPromptCont $ dropWhile isSpace rest++    Right ("editor",  rest) -> setEditor  $ dropWhile isSpace rest+    Right ("stop",    rest) -> setStop    $ dropWhile isSpace rest+    Right ("local-config", rest) ->+        setLocalConfigBehaviour $ dropWhile isSpace rest+    _ -> case toArgsNoLoc str of+         Left err -> liftIO (hPutStrLn stderr err)+         Right wds -> () <$ keepGoing' setOptions wds++setiCmd :: GhciMonad m => String -> m ()+setiCmd ""   = GHC.getInteractiveDynFlags >>= liftIO . showDynFlags False+setiCmd "-a" = GHC.getInteractiveDynFlags >>= liftIO . showDynFlags True+setiCmd str  =+  case toArgsNoLoc str of+    Left err -> liftIO (hPutStrLn stderr err)+    Right wds -> newDynFlags True wds++showOptions :: GhciMonad m => Bool -> m ()+showOptions show_all+  = do st <- getGHCiState+       dflags <- getDynFlags+       let opts = options st+       liftIO $ putStrLn (showSDoc dflags (+              text "options currently set: " <>+              if null opts+                   then text "none."+                   else hsep (map (\o -> char '+' <> text (optToStr o)) opts)+           ))+       liftIO $ showDynFlags show_all dflags+++showDynFlags :: Bool -> DynFlags -> IO ()+showDynFlags show_all dflags = do+  showLanguages' show_all dflags+  putStrLn $ showSDoc dflags $+     text "GHCi-specific dynamic flag settings:" $$+         nest 2 (vcat (map (setting "-f" "-fno-" gopt) ghciFlags))+  putStrLn $ showSDoc dflags $+     text "other dynamic, non-language, flag settings:" $$+         nest 2 (vcat (map (setting "-f" "-fno-" gopt) others))+  putStrLn $ showSDoc dflags $+     text "warning settings:" $$+         nest 2 (vcat (map (setting "-W" "-Wno-" wopt) DynFlags.wWarningFlags))+  where+        setting :: String -> String -> (flag -> DynFlags -> Bool) -> FlagSpec flag -> SDoc+        setting prefix noPrefix test flag+          | quiet     = empty+          | is_on     = text prefix <> text name+          | otherwise = text noPrefix <> text name+          where name = flagSpecName flag+                f = flagSpecFlag flag+                is_on = test f dflags+                quiet = not show_all && test f default_dflags == is_on++        default_dflags = defaultDynFlags (settings dflags)++        (ghciFlags,others)  = partition (\f -> flagSpecFlag f `elem` flgs)+                                        DynFlags.fFlags+        flgs = [ Opt_PrintExplicitForalls+               , Opt_PrintExplicitKinds+               , Opt_PrintUnicodeSyntax+               , Opt_PrintBindResult+               , Opt_BreakOnException+               , Opt_BreakOnError+               , Opt_PrintEvldWithShow+               ]++setArgs, setOptions :: GhciMonad m => [String] -> m ()+setProg, setEditor, setStop :: GhciMonad m => String -> m ()+setLocalConfigBehaviour :: GhciMonad m => String -> m ()++setArgs args = do+  st <- getGHCiState+  wrapper <- mkEvalWrapper (progname st) args+  setGHCiState st { GhciMonad.args = args, evalWrapper = wrapper }++setProg prog = do+  st <- getGHCiState+  wrapper <- mkEvalWrapper prog (GhciMonad.args st)+  setGHCiState st { progname = prog, evalWrapper = wrapper }++setEditor cmd = modifyGHCiState (\st -> st { editor = cmd })++setLocalConfigBehaviour s+  | s == "source" =+      modifyGHCiState (\st -> st { localConfig = SourceLocalConfig })+  | s == "ignore" =+      modifyGHCiState (\st -> st { localConfig = IgnoreLocalConfig })+  | otherwise = throwGhcException+      (CmdLineError "syntax:  :set local-config { source | ignore }")++setStop str@(c:_) | isDigit c+  = do let (nm_str,rest) = break (not.isDigit) str+           nm = read nm_str+       st <- getGHCiState+       let old_breaks = breaks st+       case IntMap.lookup nm old_breaks of+         Nothing ->  printForUser (text "Breakpoint" <+> ppr nm <+>+                                   text "does not exist")+         Just loc -> do+            let new_breaks = IntMap.insert nm+                                loc { onBreakCmd = dropWhile isSpace rest }+                                old_breaks+            setGHCiState st{ breaks = new_breaks }+setStop cmd = modifyGHCiState (\st -> st { stop = cmd })++setPrompt :: GhciMonad m => PromptFunction -> m ()+setPrompt v = modifyGHCiState (\st -> st {prompt = v})++setPromptCont :: GhciMonad m => PromptFunction -> m ()+setPromptCont v = modifyGHCiState (\st -> st {prompt_cont = v})++setPromptFunc :: GHC.GhcMonad m => (PromptFunction -> m ()) -> String -> m ()+setPromptFunc fSetPrompt s = do+    -- We explicitly annotate the type of the expression to ensure+    -- that unsafeCoerce# is passed the exact type necessary rather+    -- than a more general one+    let exprStr = "(" ++ s ++ ") :: [String] -> Int -> IO String"+    (HValue funValue) <- GHC.compileExpr exprStr+    fSetPrompt (convertToPromptFunction $ unsafeCoerce funValue)+    where+      convertToPromptFunction :: ([String] -> Int -> IO String)+                              -> PromptFunction+      convertToPromptFunction func = (\mods line -> liftIO $+                                       liftM text (func mods line))++setPromptString :: MonadIO m+                => (PromptFunction -> m ()) -> String -> String -> m ()+setPromptString fSetPrompt value err = do+  if null value+    then liftIO $ hPutStrLn stderr $ err+    else case value of+           ('\"':_) ->+             case reads value of+               [(value', xs)] | all isSpace xs ->+                 setParsedPromptString fSetPrompt value'+               _ -> liftIO $ hPutStrLn stderr+                             "Can't parse prompt string. Use Haskell syntax."+           _ ->+             setParsedPromptString fSetPrompt value++setParsedPromptString :: MonadIO m+                      => (PromptFunction -> m ()) ->  String -> m ()+setParsedPromptString fSetPrompt s = do+  case (checkPromptStringForErrors s) of+    Just err ->+      liftIO $ hPutStrLn stderr err+    Nothing ->+      fSetPrompt $ generatePromptFunctionFromString s++setOptions wds =+   do -- first, deal with the GHCi opts (+s, +t, etc.)+      let (plus_opts, minus_opts)  = partitionWith isPlus wds+      mapM_ setOpt plus_opts+      -- then, dynamic flags+      when (not (null minus_opts)) $ newDynFlags False minus_opts++-- | newDynFlags will *not* read package environment files, therefore we+-- use 'parseDynamicFlagsCmdLine' rather than 'parseDynamicFlags'. This+-- function is called very often and results in repeatedly loading+-- environment files (see #19650)+newDynFlags :: GhciMonad m => Bool -> [String] -> m ()+newDynFlags interactive_only minus_opts = do+      let lopts = map noLoc minus_opts++      logger <- getLogger+      idflags0 <- GHC.getInteractiveDynFlags+      (idflags1, leftovers, warns) <- DynFlags.parseDynamicFlagsCmdLine idflags0 lopts++      liftIO $ printOrThrowDiagnostics logger (initPrintConfig idflags1) (initDiagOpts idflags1) (GhcDriverMessage <$> warns)+      when (not $ null leftovers) (unknownFlagsErr $ map unLoc leftovers)++      when (interactive_only && packageFlagsChanged idflags1 idflags0) $ do+          liftIO $ hPutStrLn stderr "cannot set package flags with :seti; use :set"+      GHC.setInteractiveDynFlags idflags1+      installInteractivePrint (interactivePrint idflags1) False++      dflags0 <- getDynFlags++      when (not interactive_only) $ do+        (dflags1, _, _) <- liftIO $ DynFlags.parseDynamicFlagsCmdLine dflags0 lopts+        must_reload <- GHC.setProgramDynFlags dflags1++        -- if the package flags changed, reset the context and link+        -- the new packages.+        hsc_env <- GHC.getSession+        let dflags2 = hsc_dflags hsc_env+        let interp  = hscInterp hsc_env+        when (packageFlagsChanged dflags2 dflags0) $ do+          when (verbosity dflags2 > 0) $+            liftIO . putStrLn $+              "package flags have changed, resetting and loading new packages..."+          -- Clear caches and eventually defined breakpoints. (#1620)+          clearCaches+          when must_reload $ do+            let units = preloadUnits (hsc_units hsc_env)+            liftIO $ Loader.loadPackages interp hsc_env units+          -- package flags changed, we can't re-use any of the old context+          setContextAfterLoad False Nothing+          -- and copy the package flags to the interactive DynFlags+          idflags <- GHC.getInteractiveDynFlags+          GHC.setInteractiveDynFlags+              idflags{ packageFlags = packageFlags dflags2 }++        let ld0length   = length $ ldInputs dflags0+            fmrk0length = length $ cmdlineFrameworks dflags0++            newLdInputs     = drop ld0length (ldInputs dflags2)+            newCLFrameworks = drop fmrk0length (cmdlineFrameworks dflags2)++            dflags'  = dflags2 { ldInputs = newLdInputs+                               , cmdlineFrameworks = newCLFrameworks+                               }+            hsc_env' = hscSetFlags dflags' hsc_env++        when (not (null newLdInputs && null newCLFrameworks)) $+          liftIO $ Loader.loadCmdLineLibs (hscInterp hsc_env') hsc_env'++      return ()++unknownFlagsErr :: [String] -> a+unknownFlagsErr fs = throwGhcException $ CmdLineError $ concatMap oneError fs+  where+    oneError f =+        "unrecognised flag: " ++ f ++ "\n" +++        (case flagSuggestions ghciFlags f of+            [] -> ""+            suggs -> "did you mean one of:\n" ++ unlines (map ("  " ++) suggs))+    ghciFlags = nubSort $ flagsForCompletion True++unsetOptions :: GhciMonad m => String -> m ()+unsetOptions str+  =   -- first, deal with the GHCi opts (+s, +t, etc.)+     let opts = words str+         (minus_opts, rest1) = partition isMinus opts+         (plus_opts, rest2)  = partitionWith isPlus rest1+         (other_opts, rest3) = partition (`elem` map fst defaulters) rest2++         defaulters =+           [ ("args"   , setArgs default_args)+           , ("prog"   , setProg default_progname)+           , ("prompt"     , setPrompt default_prompt)+           , ("prompt-cont", setPromptCont default_prompt_cont)+           , ("editor" , liftIO findEditor >>= setEditor)+           , ("stop"   , setStop default_stop)+           ]++         no_flag ('-':'f':rest) = return ("-fno-" ++ rest)+         no_flag ('-':'X':rest) = return ("-XNo" ++ rest)+         no_flag f = throwGhcException (ProgramError ("don't know how to reverse " ++ f))++     in case rest3 of+          opt:_ -> liftIO (putStrLn ("unknown option: '" ++ opt ++ "'"))+          [] -> do+             mapM_ (fromJust.flip lookup defaulters) other_opts++             mapM_ unsetOpt plus_opts++             no_flags <- mapM no_flag minus_opts+             when (not (null no_flags)) $ newDynFlags False no_flags++isMinus :: String -> Bool+isMinus ('-':_) = True+isMinus _ = False++isPlus :: String -> Either String String+isPlus ('+':opt) = Left opt+isPlus other     = Right other++setOpt, unsetOpt :: GhciMonad m => String -> m ()++setOpt str+  = case strToGHCiOpt str of+        Nothing -> liftIO (putStrLn ("unknown option: '" ++ str ++ "'"))+        Just o  -> setOption o++unsetOpt str+  = case strToGHCiOpt str of+        Nothing -> liftIO (putStrLn ("unknown option: '" ++ str ++ "'"))+        Just o  -> unsetOption o++strToGHCiOpt :: String -> (Maybe GHCiOption)+strToGHCiOpt "m" = Just Multiline+strToGHCiOpt "s" = Just ShowTiming+strToGHCiOpt "t" = Just ShowType+strToGHCiOpt "r" = Just RevertCAFs+strToGHCiOpt "c" = Just CollectInfo+strToGHCiOpt _   = Nothing++optToStr :: GHCiOption -> String+optToStr Multiline  = "m"+optToStr ShowTiming = "s"+optToStr ShowType   = "t"+optToStr RevertCAFs = "r"+optToStr CollectInfo = "c"+++-- ---------------------------------------------------------------------------+-- :show++showCmd :: forall m. GhciMonad m => String -> m ()+showCmd ""   = showOptions False+showCmd "-a" = showOptions True+showCmd str = do+    st <- getGHCiState+    dflags <- getDynFlags+    hsc_env <- GHC.getSession++    let lookupCmd :: String -> Maybe (m ())+        lookupCmd name = lookup name $ map (\(_,b,c) -> (b,c)) cmds++        -- (show in help?, command name, action)+        action :: String -> m () -> (Bool, String, m ())+        action name m = (True, name, m)++        hidden :: String -> m () -> (Bool, String, m ())+        hidden name m = (False, name, m)++        cmds =+            [ action "args"       $ liftIO $ putStrLn (show (GhciMonad.args st))+            , action "prog"       $ liftIO $ putStrLn (show (progname st))+            , action "editor"     $ liftIO $ putStrLn (show (editor st))+            , action "stop"       $ liftIO $ putStrLn (show (stop st))+            , action "imports"    $ showImports+            , action "modules"    $ showModules+            , action "bindings"   $ showBindings+            , action "linker"     $ do+               msg <- liftIO $ Loader.showLoaderState (hscInterp hsc_env)+               dflags <- getDynFlags+               liftIO $ putStrLn $ showSDoc dflags msg+            , action "breaks"     $ showBkptTable+            , action "context"    $ showContext+            , action "packages"   $ showUnits+            , action "paths"      $ showPaths+            , action "language"   $ showLanguages+            , hidden "languages"  $ showLanguages -- backwards compat+            , hidden "lang"       $ showLanguages -- useful abbreviation+            , action "targets"    $ showTargets+            ]++    case words str of+      [w] | Just action <- lookupCmd w -> action++      _ -> let helpCmds = [ text name | (True, name, _) <- cmds ]+           in throwGhcException $ CmdLineError $ showSDoc dflags+              $ hang (text "syntax:") 4+              $ hang (text ":show") 6+              $ brackets (fsep $ punctuate (text " |") helpCmds)++showiCmd :: GHC.GhcMonad m => String -> m ()+showiCmd str = do+  case words str of+        ["languages"]  -> showiLanguages -- backwards compat+        ["language"]   -> showiLanguages+        ["lang"]       -> showiLanguages -- useful abbreviation+        _ -> throwGhcException (CmdLineError ("syntax:  :showi language"))++showImports :: GhciMonad m => m ()+showImports = do+  st <- getGHCiState+  dflags <- getDynFlags+  let rem_ctx   = reverse (remembered_ctx st)+      trans_ctx = transient_ctx st++      show_one (IIModule star_m)+          = ":module +*" ++ moduleNameString star_m+      show_one (IIDecl imp) = showPpr dflags imp++  prel_iidecls <- getImplicitPreludeImports (rem_ctx ++ trans_ctx)++  let show_prel p = show_one p ++ " -- implicit"+      show_extra p = show_one (IIDecl p) ++ " -- fixed"++      trans_comment s = s ++ " -- added automatically" :: String+  --+  liftIO $ mapM_ putStrLn (map show_one rem_ctx +++                           map (trans_comment . show_one) trans_ctx +++                           map show_prel prel_iidecls +++                           map show_extra (extra_imports st))++showModules :: GHC.GhcMonad m => m ()+showModules = do+  loaded_mods <- getLoadedModules+        -- we want *loaded* modules only, see #1734+  let show_one ms = do m <- GHC.showModule ms; liftIO (putStrLn m)+  mapM_ show_one loaded_mods++getLoadedModules :: GHC.GhcMonad m => m [GHC.ModSummary]+getLoadedModules = do+  graph <- GHC.getModuleGraph+  filterM isLoadedModSummary (GHC.mgModSummaries graph)++showBindings :: GHC.GhcMonad m => m ()+showBindings = do+    bindings <- GHC.getBindings+    (insts, finsts) <- GHC.getInsts+    let idocs  = map GHC.pprInstanceHdr insts+        fidocs = map GHC.pprFamInst finsts+        binds = filter (not . isDerivedOccName . getOccName) bindings -- #12525+        -- See Note [Filter bindings]+    docs <- mapM makeDoc (reverse binds)+                  -- reverse so the new ones come last+    mapM_ printForUserPartWay (docs ++ idocs ++ fidocs)+  where+    makeDoc (AnId i) = pprTypeAndContents i+    makeDoc tt = do+        mb_stuff <- GHC.getInfo False (getName tt)+        return $ maybe (text "") pprTT mb_stuff++    pprTT :: (TyThing, Fixity, [GHC.ClsInst], [GHC.FamInst], SDoc) -> SDoc+    pprTT (thing, fixity, _cls_insts, _fam_insts, _docs)+      = pprTyThing showToHeader thing+        $$ showFixity thing fixity+++printTyThing :: GHC.GhcMonad m => TyThing -> m ()+printTyThing tyth = printForUser (pprTyThing showToHeader tyth)++isLoadedModSummary :: GHC.GhcMonad m => ModSummary -> m Bool+isLoadedModSummary ms = GHC.isLoadedModule (ms_unitid ms) (ms_mod_name ms)++{-+Note [Filter bindings]+~~~~~~~~~~~~~~~~~~~~~~+If we don't filter the bindings returned by the function GHC.getBindings,+then the :show bindings command will also show unwanted bound names,+internally generated by GHC, eg:+    $tcFoo :: GHC.Types.TyCon = _+    $trModule :: GHC.Unit.Module = _ .++The filter was introduced as a fix for #12525 [1]. Comment:1 [2] to this+ticket contains an analysis of the situation and suggests the solution+implemented above.++The same filter was also implemented to fix #11051 [3]. See the+Note [What to show to users] in GHC.Runtime.Eval++[1] https://gitlab.haskell.org/ghc/ghc/issues/12525+[2] https://gitlab.haskell.org/ghc/ghc/issues/12525#note_123489+[3] https://gitlab.haskell.org/ghc/ghc/issues/11051+-}+++showBkptTable :: GhciMonad m => m ()+showBkptTable = do+  st <- getGHCiState+  printForUser $ prettyLocations (breaks st)++showContext :: GHC.GhcMonad m => m ()+showContext = do+   resumes <- GHC.getResumeContext+   printForUser $ vcat (map pp_resume (reverse resumes))+  where+   pp_resume res =+        text "--> " <> text (GHC.resumeStmt res)+        $$ nest 2 (pprStopped res)++pprStopped :: GHC.Resume -> SDoc+pprStopped res =+  text "Stopped in"+    <+> ((case mb_mod_name of+           Nothing -> empty+           Just mod_name -> ftext (moduleNameFS mod_name) <> char '.')+         <> text (GHC.resumeDecl res))+    <> char ',' <+> ppr (GHC.resumeSpan res)+ where+  mb_mod_name = moduleName <$> GHC.breakInfo_module <$> GHC.resumeBreakInfo res++showUnits :: GHC.GhcMonad m => m ()+showUnits = do+  dflags <- getDynFlags+  let pkg_flags = packageFlags dflags+  liftIO $ putStrLn $ showSDoc dflags $+    text ("active package flags:"++if null pkg_flags then " none" else "") $$+      nest 2 (vcat (map pprFlag pkg_flags))++showPaths :: GHC.GhcMonad m => m ()+showPaths = do+  dflags <- getDynFlags+  liftIO $ do+    cwd <- getCurrentDirectory+    putStrLn $ showSDoc dflags $+      text "current working directory: " $$+        nest 2 (text cwd)+    let ipaths = importPaths dflags+    putStrLn $ showSDoc dflags $+      text ("module import search paths:"++if null ipaths then " none" else "") $$+        nest 2 (vcat (map text ipaths))++showLanguages :: GHC.GhcMonad m => m ()+showLanguages = getDynFlags >>= liftIO . showLanguages' False++showiLanguages :: GHC.GhcMonad m => m ()+showiLanguages = GHC.getInteractiveDynFlags >>= liftIO . showLanguages' False++showLanguages' :: Bool -> DynFlags -> IO ()+showLanguages' show_all dflags =+  putStrLn $ showSDoc dflags $ vcat+     [ text "base language is: " <>+         case lang of+           Haskell98   -> text "Haskell98"+           Haskell2010 -> text "Haskell2010"+           GHC2021     -> text "GHC2021"+           GHC2024     -> text "GHC2024"+     , (if show_all then text "all active language options:"+                    else text "with the following modifiers:") $$+          nest 2 (vcat (map (setting xopt) DynFlags.xFlags))+     ]+  where+   setting test flag+          | quiet     = empty+          | is_on     = text "-X" <> text name+          | otherwise = text "-XNo" <> text name+          where name = flagSpecName flag+                f = flagSpecFlag flag+                is_on = test f dflags+                quiet = not show_all && test f default_dflags == is_on++   default_dflags = defaultDynFlags (settings dflags) `lang_set` Just lang++   lang = fromMaybe defaultLanguage (language dflags)+++showTargets :: GHC.GhcMonad m => m ()+showTargets = mapM_ showTarget =<< GHC.getTargets+  where+    showTarget :: GHC.GhcMonad m => Target -> m ()+    showTarget Target { targetId = TargetFile f _ } = liftIO (putStrLn f)+    showTarget Target { targetId = TargetModule m } =+      liftIO (putStrLn $ moduleNameString m)++-- -----------------------------------------------------------------------------+-- Completion++completeCmd :: String -> GHCi ()+completeCmd argLine0 = case parseLine argLine0 of+    Just ("repl", resultRange, left) -> do+        (unusedLine,compls) <- ghciCompleteWord (reverse left,"")+        let compls' = takeRange resultRange compls+        liftIO . putStrLn $ unwords [ show (length compls'), show (length compls), show (reverse unusedLine) ]+        forM_ (takeRange resultRange compls) $ \(Completion r _ _) -> do+            liftIO $ print r+    _ -> throwGhcException (CmdLineError "Syntax: :complete repl [<range>] <quoted-string-to-complete>")+  where+    parseLine [] = Nothing+    parseLine argLine = case breakSpace argLine of+      (_, []) -> Nothing+      (dom, rest1@('"' : _)) -> (dom,,) <$> parseRange "" <*> (readMaybe rest1 :: Maybe String)+      (dom, rest1) -> (dom,,) <$> parseRange rng <*> readMaybe rest2+        where+          (rng, rest2) = breakSpace rest1++    breakSpace = fmap (dropWhile isSpace) . break isSpace++    takeRange (lb,ub) = maybe id (drop . pred) lb . maybe id take ub++    -- syntax: [n-][m] with semantics "drop (n-1) . take m"+    parseRange :: String -> Maybe (Maybe Int,Maybe Int)+    parseRange s = case span isDigit s of+                   (_, "") ->+                       -- upper limit only+                       Just (Nothing, bndRead s)+                   (s1, '-' : s2)+                    | all isDigit s2 ->+                       Just (bndRead s1, bndRead s2)+                   _ ->+                       Nothing+      where+        bndRead x = if null x then Nothing else Just (read x)++++completeGhciCommand, completeMacro, completeIdentifier, completeModule,+    completeSetModule, completeSeti, completeShowiOptions,+    completeHomeModule, completeSetOptions, completeShowOptions,+    completeHomeModuleOrFile, completeExpression, completeBreakpoint+    :: GhciMonad m => CompletionFunc m++-- | Provide completions for last word in a given string.+--+-- Takes a tuple of two strings.  First string is a reversed line to be+-- completed.  Second string is likely unused, 'completeCmd' always passes an+-- empty string as second item in tuple.+ghciCompleteWord :: CompletionFunc GHCi+ghciCompleteWord line@(left,_) = case firstWord of+    -- If given string starts with `:` colon, and there is only one following+    -- word then provide REPL command completions.  If there is more than one+    -- word complete either filename or builtin ghci commands or macros.+    ':':cmd     | null rest     -> completeGhciCommand line+                | otherwise     -> do+                        completion <- lookupCompletion cmd+                        completion line+    -- If given string starts with `import` keyword provide module name+    -- completions+    "import"    -> completeModule line+    -- otherwise provide identifier completions+    _           -> completeExpression line+  where+    (firstWord,rest) = break isSpace $ dropWhile isSpace $ reverse left+    lookupCompletion ('!':_) = return completeFilename+    lookupCompletion c = do+        maybe_cmd <- lookupCommand' c+        case maybe_cmd of+            Just cmd -> return (cmdCompletionFunc cmd)+            Nothing  -> return completeFilename++completeGhciCommand = wrapCompleter " " $ \w -> do+  macros <- ghci_macros <$> getGHCiState+  cmds   <- ghci_commands `fmap` getGHCiState+  let macro_names = map (':':) . map cmdName $ macros+  let command_names = map (':':) . map cmdName $ filter (not . cmdHidden) cmds+  let{ candidates = case w of+      ':' : ':' : _ -> map (':':) command_names+      _ -> nub $ macro_names ++ command_names }+  return $ filter (w `isPrefixOptOf`) candidates++completeMacro = wrapIdentCompleter $ \w -> do+  cmds <- ghci_macros <$> getGHCiState+  return (filter (w `isPrefixOf`) (map cmdName cmds))++completeIdentifier line@(left, _) =+  -- Note: `left` is a reversed input+  case left of+    ('.':_)  -> wrapCompleter (specials ++ spaces) complete line+               -- operator or qualification+    (x:_) | isSymbolChar x -> wrapCompleter' (\c -> c `elem` (specials ++ spaces) || not (isSymbolChar c))+                                 complete line         -- operator+    _                      -> wrapIdentCompleter complete line+  where+    complete w = do+      rdrs <- GHC.getRdrNamesInScope+      dflags <- GHC.getSessionDynFlags+      return (filter (w `isPrefixOf`) (map (showPpr dflags) rdrs))++-- TAB-completion for the :break command.+-- Build and return a list of breakpoint identifiers with a given prefix.+-- See Note [Tab-completion for :break]+completeBreakpoint = wrapCompleter spaces $ \w -> do          -- #3000+    -- bid ~ breakpoint identifier = a name of a function that is+    --       eligible to set a breakpoint.+    let (mod_str, _, _) = splitIdent w+    bids_mod_breaks <- bidsFromModBreaks mod_str+    bids_inscopes <- bidsFromInscopes+    pure $ nub $ filter (isPrefixOf w) $ bids_mod_breaks ++ bids_inscopes+  where+    -- Extract all bids from ModBreaks for a given module name prefix+    bidsFromModBreaks :: GhciMonad m => String -> m [String]+    bidsFromModBreaks mod_pref = do+        imods <- interpretedHomeMods+        let pmods = filter ((isPrefixOf mod_pref) . showModule) imods+        nonquals <- case null mod_pref of+          -- If the prefix is empty, then for functions declared in a module+          -- in scope, don't qualify the function name.+          -- (eg: `main` instead of `Main.main`)+            True -> do+                imports <- GHC.getContext+                pure [ m | IIModule m <- imports]+            False -> return []+        bidss <- mapM (bidsByModule nonquals) pmods+        pure $ concat bidss++    -- Return a list of interpreted home modules+    interpretedHomeMods :: GhciMonad m => m [Module]+    interpretedHomeMods = do+        graph <- GHC.getModuleGraph+        let hmods = ms_mod <$> GHC.mgModSummaries graph+        filterM GHC.moduleIsInterpreted hmods++    -- Return all possible bids for a given Module+    bidsByModule :: GhciMonad m => [ModuleName] -> Module -> m [String]+    bidsByModule nonquals mod = do+      (_, decls) <- getModBreak mod+      let bids = nub $ declPath <$> elems decls+      pure $ case (moduleName mod) `elem` nonquals of+              True  -> bids+              False -> (combineModIdent (showModule mod)) <$> bids++    -- Extract all bids from all top-level identifiers in scope.+    bidsFromInscopes :: GhciMonad m => m [String]+    bidsFromInscopes = do+        dflags <- getDynFlags+        rdrs <- GHC.getRdrNamesInScope+        inscopess <- mapM createInscope $ (showSDoc dflags . ppr) <$> rdrs+        imods <- interpretedHomeMods+        let topLevels = filter ((`elem` imods) . snd) $ concat inscopess+        bidss <- mapM (addNestedDecls) topLevels+        pure $ concat bidss++    -- Return a list of (bid,module) for a single top-level in-scope identifier+    createInscope :: GhciMonad m => String -> m [(String, Module)]+    createInscope str_rdr = do+        names <- GHC.parseName str_rdr+        pure $ map (str_rdr, ) $ NE.toList $ GHC.nameModule <$> names++    -- For every top-level identifier in scope, add the bids of the nested+    -- declarations. See Note [Field modBreaks_decls] in GHC.ByteCode.Types+    addNestedDecls :: GhciMonad m => (String, Module) -> m [String]+    addNestedDecls (ident, mod) = do+        (_, decls) <- getModBreak mod+        let (mod_str, topLvl, _) = splitIdent ident+            ident_decls = [ elm | elm@(el : _) <- elems decls, el == topLvl ]+            bids = nub $ declPath <$> ident_decls+        pure $ map (combineModIdent mod_str) bids++completeModule = wrapIdentCompleterMod $ \w -> do+  hsc_env <- GHC.getSession+  let pkg_mods = allVisibleModules (hsc_units hsc_env)+  loaded_mods <- liftM (map GHC.ms_mod_name) getLoadedModules+  return $ filter (w `isPrefixOf`)+        $ map (showPpr (hsc_dflags hsc_env)) $ loaded_mods ++ pkg_mods++completeSetModule = wrapIdentCompleterWithModifier "+-" $ \m w -> do+  hsc_env <- GHC.getSession+  modules <- case m of+    Just '-' -> do+      imports <- GHC.getContext+      return $ map iiModuleName imports+    _ -> do+      let pkg_mods = allVisibleModules (hsc_units hsc_env)+      loaded_mods <- liftM (map GHC.ms_mod_name) getLoadedModules+      return $ loaded_mods ++ pkg_mods+  return $ filter (w `isPrefixOf`) $ map (showPpr (hsc_dflags hsc_env)) modules++completeHomeModule = wrapIdentCompleterMod listHomeModules++listHomeModules :: GHC.GhcMonad m => String -> m [String]+listHomeModules w = do+    g <- GHC.getModuleGraph+    let home_mods = map GHC.ms_mod_name (GHC.mgModSummaries g)+    dflags <- getDynFlags+    return $ sort $ filter (w `isPrefixOf`)+            $ map (showPpr dflags) home_mods++completeSetOptions = wrapCompleter flagWordBreakChars $ \w -> do+  return (filter (w `isPrefixOf`) opts)+    where opts = "args":"prog":"prompt":"prompt-cont":"prompt-function":+                 "prompt-cont-function":"editor":"stop":flagList+          flagList = map NE.head $ NE.group $ sort allNonDeprecatedFlags++completeSeti = wrapCompleter flagWordBreakChars $ \w -> do+  return (filter (w `isPrefixOf`) flagList)+    where flagList = map NE.head $ NE.group $ sort allNonDeprecatedFlags++completeShowOptions = wrapCompleter flagWordBreakChars $ \w -> do+  return (filter (w `isPrefixOf`) opts)+    where opts = ["args", "prog", "editor", "stop",+                     "modules", "bindings", "linker", "breaks",+                     "context", "packages", "paths", "language", "imports"]++completeShowiOptions = wrapCompleter flagWordBreakChars $ \w -> do+  return (filter (w `isPrefixOf`) ["language"])++completeHomeModuleOrFile = completeWord Nothing filenameWordBreakChars+                $ unionComplete (fmap (map simpleCompletion) . listHomeModules)+                            listFiles++unionComplete :: Monad m => (a -> m [b]) -> (a -> m [b]) -> a -> m [b]+unionComplete f1 f2 line = do+  cs1 <- f1 line+  cs2 <- f2 line+  return (cs1 ++ cs2)++wrapCompleter :: Monad m => String -> (String -> m [String]) -> CompletionFunc m+wrapCompleter breakChars = wrapCompleter' (`elem` breakChars)++wrapCompleter' :: Monad m => (Char -> Bool) -> (String -> m [String]) -> CompletionFunc m+wrapCompleter' breakPred fun = completeWord' Nothing breakPred+    $ fmap (map simpleCompletion . nubSort) . fun++wrapIdentCompleter :: Monad m => (String -> m [String]) -> CompletionFunc m+wrapIdentCompleter = wrapCompleter' word_break_chars_pred++wrapIdentCompleterMod :: Monad m => (String -> m [String]) -> CompletionFunc m+wrapIdentCompleterMod = wrapCompleter' go+  where+    go '.' = False -- Treated specially since it is a separator for module qualifiers+    go c = word_break_chars_pred c++wrapIdentCompleterWithModifier+  :: Monad m+  => String -> (Maybe Char -> String -> m [String]) -> CompletionFunc m+wrapIdentCompleterWithModifier modifChars fun = completeWordWithPrev Nothing word_break_chars+    $ \rest -> fmap (map simpleCompletion . nubSort) . fun (getModifier rest)+ where+  getModifier = find (`elem` modifChars)++-- | Return a list of visible module names for autocompletion.+-- (NB: exposed != visible)+allVisibleModules :: UnitState -> [ModuleName]+allVisibleModules unit_state = listVisibleModuleNames unit_state++completeExpression = completeQuotedWord (Just '\\') "\"" listFiles+                        completeIdentifier+++{-+Note [Tab-completion for :break]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In tab-completion for the `:break` command, only those+identifiers should be shown, that are accepted in the+`:break` command. Hence these identifiers must be++- defined in an interpreted module+- listed in a `ModBreaks` value as a possible breakpoint.++The identifiers may be qualified or unqualified.++To get all possible top-level breakpoints for tab-completion+with the correct qualification do:++1. Build a list called `bids_mod_breaks` of identifier names eligible+for setting breakpoints: For every interpreted module with the+correct module prefix read all identifier names from the `decls` field+of the `ModBreaks` array.++2. Build a list called `bids_inscopess` of identifiers in scope:+Take all RdrNames in scope, and filter by interpreted modules.+Fore each of these top-level identifiers add from the `ModBreaks`+arrays the available identifiers of the nested functions.++3.) Combine both lists, filter by the given prefix, and remove duplicates.+-}++-- -----------------------------------------------------------------------------+-- commands for debugger++sprintCmd, printCmd, forceCmd :: GHC.GhcMonad m => String -> m ()+sprintCmd = pprintClosureCommand False False+printCmd  = pprintClosureCommand True False+forceCmd  = pprintClosureCommand False True++stepCmd :: GhciMonad m => String -> m ()+stepCmd arg = withSandboxOnly ":step" $ step arg+  where+  step []         = doContinue (const True) GHC.SingleStep+  step expression = runStmt expression GHC.SingleStep >> return ()++stepLocalCmd :: GhciMonad m => String -> m ()+stepLocalCmd arg = withSandboxOnly ":steplocal" $ step arg+  where+  step expr+   | not (null expr) = stepCmd expr+   | otherwise = do+      mb_span <- getCurrentBreakSpan+      case mb_span of+        Nothing  -> stepCmd []+        Just (UnhelpfulSpan _) -> liftIO $ putStrLn (            -- #14690+           ":steplocal is not possible." +++           "\nCannot determine current top-level binding after " +++           "a break on error / exception.\nUse :stepmodule.")+        Just loc -> do+           md <- fromMaybe (panic "stepLocalCmd") <$> getCurrentBreakModule+           current_toplevel_decl <- enclosingTickSpan md loc+           doContinue (`isSubspanOf` RealSrcSpan current_toplevel_decl Strict.Nothing) GHC.SingleStep++stepModuleCmd :: GhciMonad m => String -> m ()+stepModuleCmd arg = withSandboxOnly ":stepmodule" $ step arg+  where+  step expr+   | not (null expr) = stepCmd expr+   | otherwise = do+      mb_span <- getCurrentBreakSpan+      case mb_span of+        Nothing  -> stepCmd []+        Just pan -> do+           let f some_span = srcSpanFileName_maybe pan == srcSpanFileName_maybe some_span+           doContinue f GHC.SingleStep++-- | Returns the span of the largest tick containing the srcspan given+enclosingTickSpan :: GhciMonad m => Module -> SrcSpan -> m RealSrcSpan+enclosingTickSpan _ (UnhelpfulSpan _) = panic "enclosingTickSpan UnhelpfulSpan"+enclosingTickSpan md (RealSrcSpan src _) = do+  ticks <- getTickArray md+  let line = srcSpanStartLine src+  massert (inRange (bounds ticks) line)+  let enclosing_spans = [ pan | (_,pan) <- ticks ! line+                               , realSrcSpanEnd pan >= realSrcSpanEnd src]+  return . minimumBy leftmostLargestRealSrcSpan $ enclosing_spans+ where++leftmostLargestRealSrcSpan :: RealSrcSpan -> RealSrcSpan -> Ordering+leftmostLargestRealSrcSpan = on compare realSrcSpanStart S.<> on (flip compare) realSrcSpanEnd++traceCmd :: GhciMonad m => String -> m ()+traceCmd arg+  = withSandboxOnly ":trace" $ tr arg+  where+  tr []         = doContinue (const True) GHC.RunAndLogSteps+  tr expression = runStmt expression GHC.RunAndLogSteps >>= setContinueExecResult >> return ()   -- DAP added++continueCmd :: GhciMonad m => String -> m ()                  -- #19157+continueCmd argLine = withSandboxOnly ":continue" $+  case contSwitch (words argLine) of+    Left sdoc   -> printForUser sdoc+    Right mbCnt -> doContinue' (const True) GHC.RunToCompletion mbCnt+    where+      contSwitch :: [String] -> Either SDoc (Maybe Int)+      contSwitch [ ] = Right Nothing+      contSwitch [x] = Just <$> getIgnoreCount x+      contSwitch  _  = Left $+          text "After ':continue' only one ignore count is allowed"++doContinue :: GhciMonad m => (SrcSpan -> Bool) -> SingleStep -> m ()+doContinue pre step = doContinue' pre step Nothing++doContinue' :: GhciMonad m => (SrcSpan -> Bool) -> SingleStep -> Maybe Int -> m ()+doContinue' pre step mbCnt= do+  runResult <- resume pre step mbCnt+  setContinueExecResult (Just runResult)   -- DAP added.+  _ <- afterRunStmt pre runResult+  return ()++abandonCmd :: GhciMonad m => String -> m ()+abandonCmd = noArgs $ withSandboxOnly ":abandon" $ do+  b <- GHC.abandon -- the prompt will change to indicate the new context+  when (not b) $ liftIO $ putStrLn "There is no computation running."++deleteCmd :: GhciMonad m => String -> m ()+deleteCmd argLine = withSandboxOnly ":delete" $ do+   deleteSwitch $ words argLine+   where+   deleteSwitch :: GhciMonad m => [String] -> m ()+   deleteSwitch [] =+      liftIO $ putStrLn "The delete command requires at least one argument."+   -- delete all break points+   deleteSwitch ("*":_rest) = discardActiveBreakPoints+   deleteSwitch idents = do+      mapM_ deleteOneBreak idents+      where+      deleteOneBreak :: GhciMonad m => String -> m ()+      deleteOneBreak str+         | all isDigit str = deleteBreak (read str)+         | otherwise = return ()++enableCmd :: GhciMonad m => String -> m ()+enableCmd argLine = withSandboxOnly ":enable" $ do+    enaDisaSwitch True $ words argLine++disableCmd :: GhciMonad m => String -> m ()+disableCmd argLine = withSandboxOnly ":disable" $ do+    enaDisaSwitch False $ words argLine++enaDisaSwitch :: GhciMonad m => Bool -> [String] -> m ()+enaDisaSwitch enaDisa [] =+    printForUser (text "The" <+> text strCmd <+>+                  text "command requires at least one argument.")+  where+    strCmd = if enaDisa then ":enable" else ":disable"+enaDisaSwitch enaDisa ("*" : _) = enaDisaAllBreaks enaDisa+enaDisaSwitch enaDisa idents = do+    mapM_ (enaDisaOneBreak enaDisa) idents+  where+    enaDisaOneBreak :: GhciMonad m => Bool -> String -> m ()+    enaDisaOneBreak enaDisa strId = do+      sdoc_loc <- checkEnaDisa enaDisa strId+      case sdoc_loc of+        Left sdoc -> printForUser sdoc+        Right loc -> enaDisaAssoc enaDisa (read strId, loc)++checkEnaDisa :: GhciMonad m => Bool -> String -> m (Either SDoc BreakLocation)+checkEnaDisa enaDisa strId = do+    sdoc_loc <- getBreakLoc strId+    pure $ sdoc_loc >>= checkEnaDisaState enaDisa strId++getBreakLoc :: GhciMonad m => String -> m (Either SDoc BreakLocation)+getBreakLoc strId = do+    st <- getGHCiState+    case readMaybe strId >>= flip IntMap.lookup (breaks st) of+      Nothing -> return $ Left (text "Breakpoint" <+> text strId <+>+                                text "not found")+      Just loc -> return $ Right loc++checkEnaDisaState :: Bool -> String -> BreakLocation -> Either SDoc BreakLocation+checkEnaDisaState enaDisa strId loc = do+    if breakEnabled loc == enaDisa+    then Left $+        text "Breakpoint" <+> text strId <+> text "already in desired state"+    else Right loc++enaDisaAssoc :: GhciMonad m => Bool -> (Int, BreakLocation) -> m ()+enaDisaAssoc enaDisa (intId, loc) = do+    st <- getGHCiState+    newLoc <- turnBreakOnOff enaDisa loc+    let new_breaks = IntMap.insert intId newLoc (breaks st)+    setGHCiState $ st { breaks = new_breaks }++enaDisaAllBreaks :: GhciMonad m => Bool -> m()+enaDisaAllBreaks enaDisa = do+    st <- getGHCiState+    mapM_ (enaDisaAssoc enaDisa) $ IntMap.assocs $ breaks st++historyCmd :: GhciMonad m => String -> m ()   -- DAP Modified+historyCmd arg+  | null arg        = history 20+  | all isDigit arg = history (read arg)+  | otherwise       = liftIO $ putStrLn "Syntax:  :history [num]"+  where+  history num = do+    resumes <- GHC.getResumeContext+    case resumes of+      [] -> liftIO $ putStrLn "Not stopped at a breakpoint"+      (r:_) -> do+        let hist = GHC.resumeHistory r+            (took,rest) = splitAt num hist+        case hist of+          [] -> liftIO $ putStrLn $+                   "Empty history. Perhaps you forgot to use :trace?"+          _  -> do+                 pans <- mapM GHC.getHistorySpan took+                 let nums  = map (printf "-%-3d:") [(1::Int)..]+                     names = map GHC.historyEnclosingDecls took+                 printForUser (vcat(zipWith3+                                 (\x y z -> x <+> y <+> z)+                                 (map text nums)+                                 (map (bold . hcat . punctuate colon . map text) names)+                                 (map (parens . ppr) pans)))+                 liftIO $ putStrLn $ if null rest then "<end of history>" else "..."+        setStackTraceResult r took   -- DAP added.++bold :: SDoc -> SDoc+bold c | do_bold   = text start_bold <> c <> text end_bold+       | otherwise = c++ignoreCmd  :: GhciMonad m => String -> m ()                     -- #19157+ignoreCmd argLine = withSandboxOnly ":ignore" $ do+    result <- ignoreSwitch (words argLine)+    case result of+      Left sdoc -> printForUser sdoc+      Right (loc, count)   -> do+        let breakInfo = GHC.BreakInfo (breakModule loc) (breakTick loc)+        setupBreakpoint breakInfo count++ignoreSwitch :: GhciMonad m => [String] -> m (Either SDoc (BreakLocation, Int))+ignoreSwitch [break, count] = do+    sdoc_loc <- getBreakLoc break+    pure $ (,) <$> sdoc_loc <*> getIgnoreCount count+ignoreSwitch _ = pure $ Left $ text "Syntax:  :ignore <breaknum> <count>"++getIgnoreCount :: String -> Either SDoc Int+getIgnoreCount str =+    case readMaybe str of+      Nothing              -> Left $ sdocIgnore <+> "is not numeric"+      Just cnt | cnt < 0   -> Left $ sdocIgnore <+> "must be >= 0"+               | otherwise -> Right cnt+    where+      sdocIgnore = text "Ignore count" <+> quotes (text str)++setupBreakpoint :: GhciMonad m => GHC.BreakInfo -> Int -> m()+setupBreakpoint loc count = do+    hsc_env <- GHC.getSession+    GHC.setupBreakpoint hsc_env loc count++backCmd :: GhciMonad m => String -> m ()+backCmd arg+  | null arg        = back 1+  | all isDigit arg = back (read arg)+  | otherwise       = liftIO $ putStrLn "Syntax:  :back [num]"+  where+  back num = withSandboxOnly ":back" $ do+      (names, _, pan, _) <- GHC.back num+      printForUser $ text "Logged breakpoint at" <+> ppr pan+      printTypeOfNames names+       -- run the command set with ":set stop <cmd>"+      st <- getGHCiState+      enqueueCommands [stop st]+      setBindingNames names      -- DAP added.++forwardCmd :: GhciMonad m => String -> m ()+forwardCmd arg+  | null arg        = forward 1+  | all isDigit arg = forward (read arg)+  | otherwise       = liftIO $ putStrLn "Syntax:  :forward [num]"+  where+  forward num = withSandboxOnly ":forward" $ do+      (names, ix, pan, _) <- GHC.forward num+      printForUser $ (if (ix == 0)+                        then text "Stopped at"+                        else text "Logged breakpoint at") <+> ppr pan+      printTypeOfNames names+       -- run the command set with ":set stop <cmd>"+      st <- getGHCiState+      enqueueCommands [stop st]+      setBindingNames names   -- DAP added.++-- handle the "break" command+breakCmd :: GhciMonad m => String -> m ()+breakCmd argLine = withSandboxOnly ":break" $ breakSwitch $ words argLine++breakSwitch :: GhciMonad m => [String] -> m ()+breakSwitch [] = do+   liftIO $ putStrLn "The break command requires at least one argument."+breakSwitch (arg1:rest)+   | looksLikeModuleName arg1 && not (null rest) = do+        md <- wantInterpretedModule arg1+        breakByModule md rest+   | all isDigit arg1 = do+        imports <- GHC.getContext+        case iiModules imports of+           (mn : _) -> do+              md <- lookupModuleName mn+              breakByModuleLine md (read arg1) rest+           [] -> do+              liftIO $ putStrLn "No modules are loaded with debugging support."+   | otherwise = do -- try parsing it as an identifier+        breakById arg1++breakByModule :: GhciMonad m => Module -> [String] -> m ()+breakByModule md (arg1:rest)+   | all isDigit arg1 = do  -- looks like a line number+        breakByModuleLine md (read arg1) rest+breakByModule _ _+   = breakSyntax++breakByModuleLine :: GhciMonad m => Module -> Int -> [String] -> m ()+breakByModuleLine md line args+   | [] <- args = findBreakAndSet md $ maybeToList . findBreakByLine line+   | [col] <- args, all isDigit col =+        findBreakAndSet md $ maybeToList . findBreakByCoord Nothing (line, read col)+   | otherwise = breakSyntax++-- Set a breakpoint for an identifier+-- See Note [Setting Breakpoints by Id]+breakById :: GhciMonad m => String -> m ()                          -- #3000+breakById inp = do+    let (mod_str, top_level, fun_str) = splitIdent inp+        mod_top_lvl = combineModIdent mod_str top_level+    mb_mod <- catch (lookupModuleInscope mod_top_lvl)+                    (\(_ :: SomeException) -> lookupModuleInGraph mod_str)+      -- If the top-level name is not in scope, `lookupModuleInscope` will+      -- throw an exception, then lookup the module name in the module graph.+    mb_err_msg <- validateBP mod_str fun_str mb_mod+    case mb_err_msg of+        Just err_msg -> printForUser $+          text "Cannot set breakpoint on" <+> quotes (text inp)+          <> text ":" <+> err_msg+        Nothing -> do+          -- No errors found, go and set the breakpoint+          mb_mod_info  <- GHC.getModuleInfo $ fromJust mb_mod+          let modBreaks = case mb_mod_info of+                (Just mod_info) -> GHC.modInfoModBreaks mod_info+                Nothing         -> emptyModBreaks+          findBreakAndSet (fromJust mb_mod) $ findBreakForBind fun_str modBreaks+  where+    -- Try to lookup the module for an identifier that is in scope.+    -- `parseName` throws an exception, if the identifier is not in scope+    lookupModuleInscope :: GhciMonad m => String -> m (Maybe Module)+    lookupModuleInscope mod_top_lvl = do+        names <- GHC.parseName mod_top_lvl+        pure $ Just $ NE.head $ GHC.nameModule <$> names++    -- Lookup the Module of a module name in the module graph+    lookupModuleInGraph :: GhciMonad m => String -> m (Maybe Module)+    lookupModuleInGraph mod_str = do+        graph <- GHC.getModuleGraph+        let hmods = ms_mod <$> GHC.mgModSummaries graph+        pure $ find ((== mod_str) . showModule) hmods++    -- Check validity of an identifier to set a breakpoint:+    --  1. The module of the identifier must exist+    --  2. the identifier must be in an interpreted module+    --  3. the ModBreaks array for module `mod` must have an entry+    --     for the function+    validateBP :: GhciMonad m => String -> String -> Maybe Module+                       -> m (Maybe SDoc)+    validateBP mod_str fun_str Nothing = pure $ Just $ quotes (text+        (combineModIdent mod_str (Prelude.takeWhile (/= '.') fun_str)))+        <+> text "not in scope"+    validateBP _ "" (Just _) = pure $ Just $ text "Function name is missing"+    validateBP _ fun_str (Just modl) = do+        isInterpr <- GHC.moduleIsInterpreted modl+        (_, decls) <- getModBreak modl+        mb_err_msg <- case isInterpr of+          False -> pure $ Just $ text "Module" <+> quotes (ppr modl)+                        <+> text "is not interpreted"+          True -> case fun_str `elem` (declPath <$> elems decls) of+                False -> pure $ Just $+                   text "No breakpoint found for" <+> quotes (text fun_str)+                   <+> "in module" <+> quotes (ppr modl)+                True  -> pure Nothing+        pure mb_err_msg++breakSyntax :: a+breakSyntax = throwGhcException $ CmdLineError ("Syntax: :break [<mod>.]<func>[.<func>]\n"+                                             ++ "        :break [<mod>] <line> [<column>]")++findBreakAndSet :: GhciMonad m+                => Module -> (TickArray -> [(Int, RealSrcSpan)]) -> m ()+findBreakAndSet md lookupTickTree = do+   tickArray <- getTickArray md+   case lookupTickTree tickArray of+      []  -> liftIO $ putStrLn $ "No breakpoints found at that location."+      some -> mapM_ breakAt some+ where+   breakAt (tick, pan) = do+         setBreakFlag md tick True+         (alreadySet, nm) <-+               recordBreak $ BreakLocation+                       { breakModule = md+                       , breakLoc = RealSrcSpan pan Strict.Nothing+                       , breakTick = tick+                       , onBreakCmd = ""+                       , breakEnabled = True+                       }+         printForUser $+            text "Breakpoint " <> ppr nm <>+            if alreadySet+               then text " was already set at " <> ppr pan+               else text " activated at " <> ppr pan++-- When a line number is specified, the current policy for choosing+-- the best breakpoint is this:+--    - the leftmost complete subexpression on the specified line, or+--    - the leftmost subexpression starting on the specified line, or+--    - the rightmost subexpression enclosing the specified line+--+findBreakByLine :: Int -> TickArray -> Maybe (BreakIndex,RealSrcSpan)+findBreakByLine line arr+  | not (inRange (bounds arr) line) = Nothing+  | otherwise =+    listToMaybe (sortBy (leftmostLargestRealSrcSpan `on` snd)  comp)   `mplus`+    listToMaybe (sortBy (compare `on` snd) incomp) `mplus`+    listToMaybe (sortBy (flip compare `on` snd) ticks)+  where+        ticks = arr ! line++        starts_here = [ (ix,pan) | (ix, pan) <- ticks,+                        GHC.srcSpanStartLine pan == line ]++        (comp, incomp) = partition ends_here starts_here+            where ends_here (_,pan) = GHC.srcSpanEndLine pan == line++-- The aim is to find the breakpoints for all the RHSs of the+-- equations corresponding to a binding.  So we find all breakpoints+-- for+--   (a) this binder only (it maybe a top-level or a nested declaration)+--   (b) that do not have an enclosing breakpoint+findBreakForBind :: String -> GHC.ModBreaks -> TickArray+                 -> [(BreakIndex,RealSrcSpan)]+findBreakForBind str_name modbreaks _ = filter (not . enclosed) ticks+  where+    ticks = [ (index, span)+            | (index, decls) <- assocs (GHC.modBreaks_decls modbreaks),+              str_name == declPath decls,+              RealSrcSpan span _ <- [GHC.modBreaks_locs modbreaks ! index] ]+    enclosed (_,sp0) = any subspan ticks+      where subspan (_,sp) = sp /= sp0 &&+                         realSrcSpanStart sp <= realSrcSpanStart sp0 &&+                         realSrcSpanEnd sp0 <= realSrcSpanEnd sp++findBreakByCoord :: Maybe FastString -> (Int,Int) -> TickArray+                 -> Maybe (BreakIndex,RealSrcSpan)+findBreakByCoord mb_file (line, col) arr+  | not (inRange (bounds arr) line) = Nothing+  | otherwise =+    listToMaybe (sortBy (flip compare `on` snd) contains +++                 sortBy (compare `on` snd) after_here)+  where+        ticks = arr ! line++        -- the ticks that span this coordinate+        contains = [ tick | tick@(_,pan) <- ticks, RealSrcSpan pan Strict.Nothing `spans` (line,col),+                            is_correct_file pan ]++        is_correct_file pan+                 | Just f <- mb_file = GHC.srcSpanFile pan == f+                 | otherwise         = True++        after_here = [ tick | tick@(_,pan) <- ticks,+                              GHC.srcSpanStartLine pan == line,+                              GHC.srcSpanStartCol pan >= col ]++-- For now, use ANSI bold on terminals that we know support it.+-- Otherwise, we add a line of carets under the active expression instead.+-- In particular, on Windows and when running the testsuite (which sets+-- TERM to vt100 for other reasons) we get carets.+-- We really ought to use a proper termcap/terminfo library.+do_bold :: Bool+do_bold = (`isPrefixOf` unsafePerformIO mTerm) `any` ["xterm", "linux"]+    where mTerm = System.Environment.getEnv "TERM"+                  `catchIO` \_ -> return "TERM not set"++start_bold :: String+start_bold = "\ESC[1m"+end_bold :: String+end_bold   = "\ESC[0m"++{-+Note [Setting Breakpoints by Id]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To set a breakpoint first check whether a ModBreaks array contains a+breakpoint with the given function name:+In `:break M.foo` `M` may be a module name or a local alias of an import+statement. To lookup a breakpoint in the ModBreaks, the effective module+name is needed. Even if a module called `M` exists, `M` may still be+a local alias. To get the module name, parse the top-level identifier with+`GHC.parseName`. If this succeeds, extract the module name from the+returned value. If it fails, catch the exception and assume `M` is a real+module name.++The names of nested functions are stored in `ModBreaks.modBreaks_decls`.+-}++-----------------------------------------------------------------------------+-- :where++whereCmd :: GHC.GhcMonad m => String -> m ()+whereCmd = noArgs $ do+  mstrs <- getCallStackAtCurrentBreakpoint+  case mstrs of+    Nothing -> return ()+    Just strs -> liftIO $ putStrLn (renderStack strs)++-----------------------------------------------------------------------------+-- :list++listCmd :: GhciMonad m => String -> m ()+listCmd "" = do+   mb_span <- getCurrentBreakSpan+   case mb_span of+      Nothing ->+          printForUser $ text "Not stopped at a breakpoint; nothing to list"+      Just (RealSrcSpan pan _) ->+          listAround pan True+      Just pan@(UnhelpfulSpan _) ->+          do resumes <- GHC.getResumeContext+             case resumes of+                 [] -> panic "No resumes"+                 (r:_) ->+                     do let traceIt = case GHC.resumeHistory r of+                                      [] -> text "rerunning with :trace,"+                                      _ -> empty+                            doWhat = traceIt <+> text ":back then :list"+                        printForUser (text "Unable to list source for" <+>+                                      ppr pan+                                   $$ text "Try" <+> doWhat)+listCmd str = list2 (words str)++list2 :: GhciMonad m => [String] -> m ()+list2 [arg] | all isDigit arg = do+    imports <- GHC.getContext+    case iiModules imports of+        [] -> liftIO $ putStrLn "No module to list"+        (mn : _) -> do+          md <- lookupModuleName mn+          listModuleLine md (read arg)+list2 [arg1,arg2] | looksLikeModuleName arg1, all isDigit arg2 = do+        md <- wantInterpretedModule arg1+        listModuleLine md (read arg2)+list2 [arg] = do+        wantNameFromInterpretedModule noCanDo arg $ \name -> do+        let loc = GHC.srcSpanStart (GHC.nameSrcSpan name)+        case loc of+            RealSrcLoc l _ ->+               do tickArray <- assert (isExternalName name) $+                               getTickArray (GHC.nameModule name)+                  let mb_span = findBreakByCoord (Just (GHC.srcLocFile l))+                                        (GHC.srcLocLine l, GHC.srcLocCol l)+                                        tickArray+                  case mb_span of+                    Nothing       -> listAround (realSrcLocSpan l) False+                    Just (_, pan) -> listAround pan False+            UnhelpfulLoc _ ->+                  noCanDo name $ text "can't find its location: " <>+                                 ppr loc+    where+        noCanDo n why = printForUser $+            text "cannot list source code for " <> ppr n <> text ": " <> why+list2  _other =+        liftIO $ putStrLn "syntax:  :list [<line> | <module> <line> | <identifier>]"++listModuleLine :: GHC.GhcMonad m => Module -> Int -> m ()+listModuleLine modl line = do+   graph <- GHC.getModuleGraph+   let this = GHC.mgLookupModule graph modl+   case this of+     Nothing -> panic "listModuleLine"+     Just summ -> do+           let filename = expectJust "listModuleLine" (ml_hs_file (GHC.ms_location summ))+               loc = mkRealSrcLoc (mkFastString (filename)) line 0+           listAround (realSrcLocSpan loc) False++-- | list a section of a source file around a particular SrcSpan.+-- If the highlight flag is True, also highlight the span using+-- start_bold\/end_bold.++-- GHC files are UTF-8, so we can implement this by:+-- 1) read the file in as a BS and syntax highlight it as before+-- 2) convert the BS to String using utf-string, and write it out.+-- It would be better if we could convert directly between UTF-8 and the+-- console encoding, of course.+listAround :: MonadIO m => RealSrcSpan -> Bool -> m ()+listAround pan do_highlight = do+      contents <- liftIO $ BS.readFile (unpackFS file)+      -- Drop carriage returns to avoid duplicates, see #9367.+      let ls  = BS.split '\n' $ BS.filter (/= '\r') contents+          ls' = take (line2 - line1 + 1 + pad_before + pad_after) $+                        drop (line1 - 1 - pad_before) $ ls+          fst_line = max 1 (line1 - pad_before)+          line_nos = [ fst_line .. ]++          highlighted | do_highlight = zipWith highlight line_nos ls'+                      | otherwise    = [\p -> BS.concat[p,l] | l <- ls']++          bs_line_nos = [ BS.pack (show l ++ "  ") | l <- line_nos ]+          prefixed = zipWith ($) highlighted bs_line_nos+          output   = BS.intercalate (BS.pack "\n") prefixed++      let utf8Decoded = utf8DecodeByteString output+      liftIO $ putStrLn utf8Decoded+  where+        file  = GHC.srcSpanFile pan+        line1 = GHC.srcSpanStartLine pan+        col1  = GHC.srcSpanStartCol pan - 1+        line2 = GHC.srcSpanEndLine pan+        col2  = GHC.srcSpanEndCol pan - 1++        pad_before | line1 == 1 = 0+                   | otherwise  = 1+        pad_after = 1++        highlight | do_bold   = highlight_bold+                  | otherwise = highlight_carets++        highlight_bold no line prefix+          | no == line1 && no == line2+          = let (a,r) = BS.splitAt col1 line+                (b,c) = BS.splitAt (col2-col1) r+            in+            BS.concat [prefix, a,BS.pack start_bold,b,BS.pack end_bold,c]+          | no == line1+          = let (a,b) = BS.splitAt col1 line in+            BS.concat [prefix, a, BS.pack start_bold, b]+          | no == line2+          = let (a,b) = BS.splitAt col2 line in+            BS.concat [prefix, a, BS.pack end_bold, b]+          | otherwise   = BS.concat [prefix, line]++        highlight_carets no line prefix+          | no == line1 && no == line2+          = BS.concat [prefix, line, nl, indent, BS.replicate col1 ' ',+                                         BS.replicate (col2-col1) '^']+          | no == line1+          = BS.concat [indent, BS.replicate (col1 - 2) ' ', BS.pack "vv", nl,+                                         prefix, line]+          | no == line2+          = BS.concat [prefix, line, nl, indent, BS.replicate col2 ' ',+                                         BS.pack "^^"]+          | otherwise   = BS.concat [prefix, line]+         where+           indent = BS.pack ("  " ++ replicate (length (show no)) ' ')+           nl = BS.singleton '\n'+++-- --------------------------------------------------------------------------+-- Tick arrays++getTickArray :: GhciMonad m => Module -> m TickArray+getTickArray modl = do+   st <- getGHCiState+   let arrmap = tickarrays st+   case lookupModuleEnv arrmap modl of+      Just arr -> return arr+      Nothing  -> do+        (ticks, _) <- getModBreak modl+        let arr = mkTickArray (assocs ticks)+        setGHCiState st{tickarrays = extendModuleEnv arrmap modl arr}+        return arr++discardTickArrays :: GhciMonad m => m ()+discardTickArrays = modifyGHCiState (\st -> st {tickarrays = emptyModuleEnv})++mkTickArray :: [(BreakIndex,SrcSpan)] -> TickArray+mkTickArray ticks+  = accumArray (flip (:)) [] (1, max_line)+        [ (line, (nm,pan)) | (nm,RealSrcSpan pan _) <- ticks, line <- srcSpanLines pan ]+    where+        max_line = foldr max 0 [ GHC.srcSpanEndLine sp | (_, RealSrcSpan sp _) <- ticks ]+        srcSpanLines pan = [ GHC.srcSpanStartLine pan ..  GHC.srcSpanEndLine pan ]++-- don't reset the counter back to zero?+discardActiveBreakPoints :: GhciMonad m => m ()+discardActiveBreakPoints = do+   st <- getGHCiState+   mapM_ (turnBreakOnOff False) $ breaks st+   setGHCiState $ st { breaks = IntMap.empty }++discardInterfaceCache :: GhciMonad m => m ()+discardInterfaceCache =+   void (liftIO . iface_clearCache . ifaceCache =<< getGHCiState)++clearHPTs :: GhciMonad m => m ()+clearHPTs = do+  let pruneHomeUnitEnv hme = hme { homeUnitEnv_hpt = emptyHomePackageTable }+      discardMG hsc = hsc { hsc_mod_graph = GHC.emptyMG }+  modifySession (discardMG . discardIC . hscUpdateHUG (unitEnv_map pruneHomeUnitEnv))+++-- The unused package warning doesn't make sense once the targets get out of+-- sync with the package flags. See #21110+-- Therefore if it's turned on, the warnings are issued until the module context+-- changes (via :load or :cd), at which stage the package flags are not going to change+-- but the loaded modules will probably not use all the specified packages so the+-- warning becomes spurious. At that point the warning is silently disabled.+disableUnusedPackages :: GhciMonad m => m ()+disableUnusedPackages = newDynFlags False ["-Wno-unused-packages"]++deleteBreak :: GhciMonad m => Int -> m ()+deleteBreak identity = do+   st <- getGHCiState+   let oldLocations = breaks st+   case IntMap.lookup identity oldLocations of+       Nothing -> printForUser (text "Breakpoint" <+> ppr identity <+>+                                text "does not exist")+       Just loc -> do+           _ <- (turnBreakOnOff False) loc+           let rest = IntMap.delete identity oldLocations+           setGHCiState $ st { breaks = rest }++turnBreakOnOff :: GhciMonad m => Bool -> BreakLocation -> m BreakLocation+turnBreakOnOff onOff loc+  | onOff == breakEnabled loc = return loc+  | otherwise = do+      setBreakFlag (breakModule loc) (breakTick loc)  onOff+      return loc { breakEnabled = onOff }++getModBreak :: GHC.GhcMonad m+            => Module -> m (Array Int SrcSpan, Array Int [String])+getModBreak m = do+   mod_info      <- fromMaybe (panic "getModBreak") <$> GHC.getModuleInfo m+   let modBreaks  = GHC.modInfoModBreaks mod_info+   let ticks      = GHC.modBreaks_locs  modBreaks+   let decls      = GHC.modBreaks_decls modBreaks+   return (ticks, decls)++setBreakFlag :: GhciMonad m => Module -> Int -> Bool ->m ()+setBreakFlag  md ix enaDisa = do+  let enaDisaToCount True = breakOn+      enaDisaToCount False = breakOff+  setupBreakpoint (GHC.BreakInfo md ix) $ enaDisaToCount enaDisa++-- ---------------------------------------------------------------------------+-- User code exception handling++-- This is the exception handler for exceptions generated by the+-- user's code and exceptions coming from children sessions;+-- it normally just prints out the exception.  The+-- handler must be recursive, in case showing the exception causes+-- more exceptions to be raised.+--+-- Bugfix: if the user closed stdout or stderr, the flushing will fail,+-- raising another exception.  We therefore don't put the recursive+-- handler around the flushing operation, so if stderr is closed+-- GHCi will just die gracefully rather than going into an infinite loop.+handler :: GhciMonad m => SomeException -> m Bool+handler exception = do+  flushInterpBuffers+  withSignalHandlers $+     ghciHandle handler (showException exception >> return False)++showException :: MonadIO m => SomeException -> m ()+showException se =+  liftIO $ case fromException se of+           -- omit the location for CmdLineError:+           Just (CmdLineError s)    -> putException s+           -- ditto:+           Just other_ghc_ex        -> putException (show other_ghc_ex)+           Nothing                  ->+               case fromException se of+               Just UserInterrupt -> putException "Interrupted."+               _                  -> putException ("*** Exception: " ++ show se)+  where+    putException = hPutStrLn stderr++failIfExprEvalMode :: GhciMonad m => m ()+failIfExprEvalMode = do+  s <- getGHCiState+  when (ghc_e s) $+    liftIO (exitWith (ExitFailure 1))++-- | When in expression evaluation mode (ghc -e), we want to exit immediately.+-- Otherwis, just print out the message.+printErrAndMaybeExit :: (GhciMonad m, MonadIO m, HasLogger m) => SourceError -> m ()+printErrAndMaybeExit = (>> failIfExprEvalMode) . printGhciException++-----------------------------------------------------------------------------+-- recursive exception handlers++-- Don't forget to unblock async exceptions in the handler, or if we're+-- in an exception loop (eg. let a = error a in a) the ^C exception+-- may never be delivered.  Thanks to Marcin for pointing out the bug.++ghciHandle :: (HasLogger m, ExceptionMonad m) => (SomeException -> m a) -> m a -> m a+ghciHandle h m = mask $ \restore -> do+                 -- Force dflags to avoid leaking the associated HscEnv+                 !log <- getLogger+                 catch (restore (GHC.prettyPrintGhcErrors log m)) $ \e -> restore (h e)++ghciTry :: ExceptionMonad m => m a -> m (Either SomeException a)+ghciTry m = fmap Right m `catch` \e -> return $ Left e++tryBool :: ExceptionMonad m => m a -> m Bool+tryBool m = do+    r <- ghciTry m+    case r of+      Left _  -> return False+      Right _ -> return True++-- ----------------------------------------------------------------------------+-- Utils++lookupModule :: GHC.GhcMonad m => String -> m Module+lookupModule mName = lookupModuleName (GHC.mkModuleName mName)++lookupModuleName :: GHC.GhcMonad m => ModuleName -> m Module+lookupModuleName mName = GHC.lookupQualifiedModule NoPkgQual mName++isMainUnitModule :: Module -> Bool+isMainUnitModule m = GHC.moduleUnit m == mainUnit++showModule :: Module -> String+showModule = moduleNameString . moduleName++-- Return a String with the declPath of the function of a breakpoint.+-- See Note [Field modBreaks_decls] in GHC.ByteCode.Types+declPath :: [String] -> String+declPath = intercalate "."++-- | Optionally show a fixity declaration like @infixr 4 #@+--+-- We always display the fixity of terms with symbolic names (like <$>).+-- For other terms we only display the fixity if it has been set to a+-- value other than the default infixl 9.+--+-- We have no way of distinguishing between a fixity that has been+-- manually set to infixl 9 and a fixity that has assumed infixl 9 as+-- the default, so we choose to not display the fixity in both cases+-- (for terms with non-symbolic names).+--+-- See #19200.+showFixity :: TyThing -> Fixity -> SDoc+showFixity thing fixity+    | fixity /= GHC.defaultFixity || isSymOcc (getOccName thing)+        = ppr fixity <+> pprInfixName (GHC.getName thing)+    | otherwise = empty++-- TODO: won't work if home dir is encoded.+-- (changeDirectory may not work either in that case.)+expandPath :: MonadIO m => String -> m String+expandPath = liftIO . expandPathIO++expandPathIO :: String -> IO String+expandPathIO p =+  case dropWhile isSpace p of+   ('~':d) -> do+        tilde <- getHomeDirectory -- will fail if HOME not defined+        return (tilde ++ '/':d)+   other ->+        return other++wantInterpretedModule :: GHC.GhcMonad m => String -> m Module+wantInterpretedModule str = wantInterpretedModuleName (GHC.mkModuleName str)++wantInterpretedModuleName :: GHC.GhcMonad m => ModuleName -> m Module+wantInterpretedModuleName modname = do+   modl <- lookupModuleName modname+   let str = moduleNameString modname+   home_unit <- hsc_home_unit <$> GHC.getSession+   unless (isHomeModule home_unit modl) $+      throwGhcException (CmdLineError ("module '" ++ str ++ "' is from another package;\nthis command requires an interpreted module"))+   is_interpreted <- GHC.moduleIsInterpreted modl+   when (not is_interpreted) $+       throwGhcException (CmdLineError ("module '" ++ str ++ "' is not interpreted; try \':add *" ++ str ++ "' first"))+   return modl++wantNameFromInterpretedModule :: GHC.GhcMonad m+                              => (Name -> SDoc -> m ())+                              -> String+                              -> (Name -> m ())+                              -> m ()+wantNameFromInterpretedModule noCanDo str and_then =+  handleSourceError printGhciException $ do+    n NE.:| _ <- GHC.parseName str+    let modl = assert (isExternalName n) $ GHC.nameModule n+    if not (GHC.isExternalName n)+       then noCanDo n $ ppr n <>+                        text " is not defined in an interpreted module"+       else do+    is_interpreted <- GHC.moduleIsInterpreted modl+    if not is_interpreted+       then noCanDo n $ text "module " <> ppr modl <>+                        text " is not interpreted"+       else and_then n++clearCaches :: GhciMonad m => m ()+clearCaches = discardActiveBreakPoints+              >> discardInterfaceCache+              >> disableUnusedPackages+              >> clearHPTs++++-- Split up a string with an eventually qualified declaration name into 3 components+--   1. module name+--   2. top-level decl+--   3. full-name of the eventually nested decl, but without module qualification+-- eg  "foo"           = ("", "foo", "foo")+--     "A.B.C.foo"     = ("A.B.C", "foo", "foo")+--     "M.N.foo.bar"   = ("M.N", "foo", "foo.bar")+splitIdent :: String -> (String, String, String)+splitIdent [] = ("", "", "")+splitIdent inp@(a : _)+    | (isUpper a) = case fixs of+        []            -> (inp, "", "")+        (i1 : [] )    -> (upto i1, from i1, from i1)+        (i1 : i2 : _) -> (upto i1, take (i2 - i1 - 1) (from i1), from i1)+    | otherwise = case ixs of+        []            -> ("", inp, inp)+        (i1 : _)      -> ("", upto i1, inp)+  where+    ixs = elemIndices '.' inp        -- indices of '.' in whole input+    fixs = dropWhile isNextUc ixs    -- indices of '.' in function names              --+    isNextUc ix = isUpper $ safeInp !! (ix+1)+    safeInp = inp ++ " "+    upto i = take i inp+    from i = drop (i + 1) inp++-- Qualify an identifier name with a module name+-- combineModIdent "A" "foo"  =  "A.foo"+-- combineModIdent ""  "foo"  =  "foo"+combineModIdent :: String -> String -> String+combineModIdent mod ident+          | null mod   = ident+          | null ident = mod+          | otherwise  = mod ++ "." ++ ident+++------------------------------------------------------------------------------------------------+--  DAP Utility+------------------------------------------------------------------------------------------------++-- |+--+setStackTraceResult :: GhciMonad m => Resume -> [GHC.History] -> m ()+setStackTraceResult r hs = do+  ctxMVar <- dapContextGHCiState <$> getGHCiState+  ctx <- liftIO $ takeMVar ctxMVar+  liftIO $ putMVar ctxMVar ctx {DAP.stackTraceResultDAPContext = Just (r, hs)}+++-- |+--+setBindingNames :: GhciMonad m => [Name] -> m ()+setBindingNames names = do+  ctxMVar <- dapContextGHCiState <$> getGHCiState+  ctx <- liftIO $ takeMVar ctxMVar+  liftIO $ putMVar ctxMVar ctx {DAP.bindingNamesDAPContext = names}+++-- |+--+setContinueExecResult :: GhciMonad m => Maybe GHC.ExecResult -> m (Maybe GHC.ExecResult)+setContinueExecResult res = do+  ctxMVar <- dapContextGHCiState  <$> getGHCiState+  ctx <- liftIO $ takeMVar ctxMVar+  liftIO $ putMVar ctxMVar ctx{DAP.continueExecResultDAPContext = res}+  return res+++
+ app-ghc-9.10/GHCi/UI/Exception.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE BangPatterns #-}++module GHCi.UI.Exception(printGhciException, GHCiMessage(..)) where++import GHC.Prelude++import GHC.Driver.Config.Diagnostic+import GHC.Driver.Errors+import GHC.Driver.Errors.Types+import GHC.Driver.Session++import GHC.Iface.Errors.Ppr+import GHC.Iface.Errors.Types++import qualified GHC.LanguageExtensions as LangExt++import GHC.Tc.Errors.Ppr+import GHC.Tc.Errors.Types++import GHC.Types.Error+import GHC.Types.SourceError++import GHC.Unit.State++import GHC.Utils.Logger+import GHC.Utils.Outputable++import Control.Monad.IO.Class+++-- | Print the all diagnostics in a 'SourceError'.  Specialised for GHCi error reporting+-- for some error messages.+printGhciException :: (HasLogger m, MonadIO m, HasDynFlags m) => SourceError -> m ()+printGhciException err = do+  dflags <- getDynFlags+  logger <- getLogger+  let !diag_opts = initDiagOpts dflags+      !print_config = initPrintConfig dflags+  liftIO $ printMessages logger print_config diag_opts (GHCiMessage <$> (srcErrorMessages err))+++newtype GHCiMessage = GHCiMessage { _getGhciMessage :: GhcMessage }++instance Diagnostic GHCiMessage where+  type DiagnosticOpts GHCiMessage = DiagnosticOpts GhcMessage++  diagnosticMessage opts (GHCiMessage msg) = ghciDiagnosticMessage opts msg++  diagnosticReason (GHCiMessage msg) = diagnosticReason msg++  diagnosticHints (GHCiMessage msg) = ghciDiagnosticHints msg++  diagnosticCode (GHCiMessage msg)  = diagnosticCode msg+++-- | Modifications to hint messages which we want to display in GHCi.+ghciDiagnosticHints :: GhcMessage -> [GhcHint]+ghciDiagnosticHints msg = map modifyHintForGHCi (diagnosticHints msg)+  where+    modifyHintForGHCi :: GhcHint -> GhcHint+    modifyHintForGHCi = \case+      SuggestExtension extHint -> SuggestExtension $ modifyExtHintForGHCi extHint+      hint -> hint+    modifyExtHintForGHCi :: LanguageExtensionHint -> LanguageExtensionHint+    modifyExtHintForGHCi = \case+      SuggestSingleExtension    doc ext  -> SuggestSingleExtension    (suggestSetExt [ext] doc False) ext+      SuggestExtensionInOrderTo doc ext  -> SuggestExtensionInOrderTo (suggestSetExt [ext] doc False) ext+      SuggestAnyExtension       doc exts -> SuggestAnyExtension       (suggestSetExt exts  doc True ) exts+      SuggestExtensions         doc exts -> SuggestExtensions         (suggestSetExt exts  doc False) exts+    -- Suggest enabling extension with :set -X<ext>+    -- SuggestAnyExtension will be on multiple lines so the user can select which to enable without editing+    suggestSetExt :: [LangExt.Extension] -> SDoc -> Bool -> SDoc+    suggestSetExt exts doc enable_any = doc $$ hang header 2 exts_cmds+      where+        header = text "You may enable" <+> which <+> text "language extension" <> plural exts <+> text "in GHCi with:"+        which+          | [ _ext ] <- exts+          = text "this"+          | otherwise+          = if enable_any+            then text "these"+            else text "all of these"+        exts_cmds+          | enable_any+          = vcat $ map (\ext -> text ":set -X" <> ppr ext) exts+          | otherwise+          = text ":set" <> hcat (map (\ext -> text " -X" <> ppr ext) exts)++-- Modifications to error messages which we want to display in GHCi+ghciDiagnosticMessage :: GhcMessageOpts -> GhcMessage -> DecoratedSDoc+ghciDiagnosticMessage ghc_opts msg =+  case msg of+    GhcTcRnMessage tc_msg ->+      case tcRnMessage (tcMessageOpts ghc_opts) tc_msg of+        Nothing -> diagnosticMessage ghc_opts msg+        Just sdoc -> sdoc+    GhcDriverMessage  (DriverInterfaceError err) ->+      case ghciInterfaceError err of+        Just sdoc -> mkSimpleDecorated sdoc+        Nothing -> diagnosticMessage ghc_opts msg+    GhcDriverMessage {} -> diagnosticMessage ghc_opts msg+    GhcPsMessage  {} -> diagnosticMessage ghc_opts msg+    GhcDsMessage  {} -> diagnosticMessage ghc_opts msg+    GhcUnknownMessage  {} -> diagnosticMessage ghc_opts msg+  where+    tcRnMessage tc_opts tc_msg =+      case tc_msg of+        TcRnInterfaceError err -> mkSimpleDecorated <$> (ghciInterfaceError err)+        TcRnMessageWithInfo unit_state msg_with_info ->+          case msg_with_info of+           TcRnMessageDetailed err_info wrapped_msg+             -> messageWithInfoDiagnosticMessage unit_state err_info+                  (tcOptsShowContext tc_opts)+                  <$> tcRnMessage tc_opts wrapped_msg+        TcRnWithHsDocContext ctxt wrapped_msg ->+          messageWithHsDocContext tc_opts ctxt <$> tcRnMessage tc_opts wrapped_msg+        _ -> Nothing++    opts = tcOptsIfaceOpts (tcMessageOpts ghc_opts)++    ghciInterfaceError (Can'tFindInterface err looking_for) =+      hangNotEmpty (lookingForHerald looking_for) 2 <$> ghciMissingInterfaceErrorDiagnostic err+    ghciInterfaceError _ = Nothing++    ghciMissingInterfaceErrorDiagnostic reason =+      case reason of+        CantFindErr us module_or_interface cfi -> Just (pprWithUnitState us $ cantFindErrorX pkg_hidden_hint may_show_locations module_or_interface cfi)+        _ -> Nothing+      where++        may_show_locations = mayShowLocations ":set -v" (ifaceShowTriedFiles opts)++        pkg_hidden_hint = pkgHiddenHint hidden_msg (ifaceBuildingCabalPackage opts)+          where+            hidden_msg pkg =+              text "You can run" <+>+              quotes (text ":set -package " <> ppr (unitPackageName pkg)) <+>+              text "to expose it." $$+              text "(Note: this unloads all the modules in the current scope.)"
+ app-ghc-9.10/GHCi/UI/Info.hs view
@@ -0,0 +1,410 @@+{-# LANGUAGE LambdaCase          #-}+{-# LANGUAGE RankNTypes          #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns        #-}+{-# LANGUAGE BangPatterns #-}++{-# OPTIONS -fno-warn-name-shadowing #-}++-- | Get information on modules, expressions, and identifiers+module GHCi.UI.Info+    ( ModInfo(..)+    , SpanInfo(..)+    , spanInfoFromRealSrcSpan+    , collectInfo+    , findLoc+    , findNameUses+    , findType+    , getModInfo+    ) where++import           Control.Exception+import           Control.Monad+import           Control.Monad.Catch as MC+import           Control.Monad.Trans.Class+import           Control.Monad.Trans.Except+import           Control.Monad.Trans.Maybe+import           Data.Data+import           Data.Function+import           Data.List (find, sortBy)+import           Data.Map.Strict   (Map)+import qualified Data.Map.Strict   as M+import           Data.Maybe+import           Data.Time+import           Prelude           hiding (mod,(<>))+import           System.Directory++import           GHC.Hs.Syn.Type+import           GHC.Driver.Session (HasDynFlags(..))+import           GHC.Data.FastString+import           GHC+import           GHC.Driver.Monad+import           GHC.Driver.Env+import           GHC.Driver.Ppr+import           GHC.Types.Name+import           GHC.Types.Name.Reader+import           GHC.Types.Name.Set+import           GHC.Utils.Outputable+import           GHC.Types.SrcLoc+import           GHC.Types.Var+import qualified GHC.Data.Strict as Strict++-- | Info about a module. This information is generated every time a+-- module is loaded.+data ModInfo = ModInfo+    { modinfoSummary    :: !ModSummary+      -- ^ Summary generated by GHC. Can be used to access more+      -- information about the module.+    , modinfoSpans      :: [SpanInfo]+      -- ^ Generated set of information about all spans in the+      -- module that correspond to some kind of identifier for+      -- which there will be type info and/or location info.+    , modinfoRdrEnv     :: !(Strict.Maybe IfGlobalRdrEnv)+      -- ^ What's in scope in the module.+    , modinfoLastUpdate :: !UTCTime+      -- ^ The timestamp of the file used to generate this record.+    }++-- | Type of some span of source code. Most of these fields are+-- unboxed but Haddock doesn't show that.+data SpanInfo = SpanInfo+    { spaninfoSrcSpan   :: {-# UNPACK #-} !RealSrcSpan+      -- ^ The span we associate information with+    , spaninfoType      :: !(Maybe Type)+      -- ^ The 'Type' associated with the span+    , spaninfoVar       :: !(Maybe Id)+      -- ^ The actual 'Var' associated with the span, if+      -- any. This can be useful for accessing a variety of+      -- information about the identifier such as module,+      -- locality, definition location, etc.+    }++instance Outputable SpanInfo where+  ppr (SpanInfo s t i) = ppr s <+> ppr t <+> ppr i++-- | Test whether second span is contained in (or equal to) first span.+-- This is basically 'containsSpan' for 'SpanInfo'+containsSpanInfo :: SpanInfo -> SpanInfo -> Bool+containsSpanInfo = containsSpan `on` spaninfoSrcSpan++-- | Filter all 'SpanInfo' which are contained in 'SpanInfo'+spaninfosWithin :: [SpanInfo] -> SpanInfo -> [SpanInfo]+spaninfosWithin spans' si = filter (si `containsSpanInfo`) spans'++-- | Construct a 'SpanInfo' from a 'RealSrcSpan' and optionally a+-- 'Type' and an 'Id' (for 'spaninfoType' and 'spaninfoVar'+-- respectively)+spanInfoFromRealSrcSpan :: RealSrcSpan -> Maybe Type -> Maybe Id -> SpanInfo+spanInfoFromRealSrcSpan spn mty mvar =+    SpanInfo spn mty mvar++-- | Convenience wrapper around 'spanInfoFromRealSrcSpan' which needs+-- only a 'RealSrcSpan'+spanInfoFromRealSrcSpan' :: RealSrcSpan -> SpanInfo+spanInfoFromRealSrcSpan' s = spanInfoFromRealSrcSpan s Nothing Nothing++-- | Convenience wrapper around 'srcSpanFile' which results in a 'FilePath'+srcSpanFilePath :: RealSrcSpan -> FilePath+srcSpanFilePath = unpackFS . srcSpanFile++-- | Try to find the location of the given identifier at the given+-- position in the module.+findLoc :: GhcMonad m+        => Map ModuleName ModInfo+        -> RealSrcSpan+        -> String+        -> ExceptT SDoc m (ModInfo,Name,SrcSpan)+findLoc infos span0 string = do+    name  <- maybeToExceptT "Couldn't guess that module name. Does it exist?" $+             guessModule infos (srcSpanFilePath span0)++    info  <- maybeToExceptT "No module info for current file! Try loading it?" $+             MaybeT $ pure $ M.lookup name infos++    name' <- findName infos span0 info string++    case getSrcSpan name' of+        UnhelpfulSpan{} -> do+            throwE ("Found a name, but no location information." <+>+                    "The module is:" <+>+                    maybe "<unknown>" (ppr . moduleName)+                          (nameModule_maybe name'))++        span' -> return (info,name',span')++-- | Find any uses of the given identifier in the codebase.+findNameUses :: (GhcMonad m)+             => Map ModuleName ModInfo+             -> RealSrcSpan+             -> String+             -> ExceptT SDoc m [SrcSpan]+findNameUses infos span0 string =+    locToSpans <$> findLoc infos span0 string+  where+    locToSpans (modinfo,name',span') =+        stripSurrounding (span' : map toSrcSpan spans)+      where+        toSrcSpan s = RealSrcSpan (spaninfoSrcSpan s) Strict.Nothing+        spans = filter ((== Just name') . fmap getName . spaninfoVar)+                       (modinfoSpans modinfo)++-- | Filter out redundant spans which surround/contain other spans.+stripSurrounding :: [SrcSpan] -> [SrcSpan]+stripSurrounding xs = filter (not . isRedundant) xs+  where+    isRedundant x = any (x `strictlyContains`) xs++    (RealSrcSpan s1 _) `strictlyContains` (RealSrcSpan s2 _)+         = s1 /= s2 && s1 `containsSpan` s2+    _                `strictlyContains` _ = False++-- | Try to resolve the name located at the given position, or+-- otherwise resolve based on the current module's scope.+findName :: GhcMonad m+         => Map ModuleName ModInfo+         -> RealSrcSpan+         -> ModInfo+         -> String+         -> ExceptT SDoc m Name+findName infos span0 mi string =+    case resolveName (modinfoSpans mi) (spanInfoFromRealSrcSpan' span0) of+      Nothing -> tryExternalModuleResolution+      Just name ->+        case getSrcSpan name of+          UnhelpfulSpan {} -> tryExternalModuleResolution+          RealSrcSpan   {} -> return (getName name)+  where+    rdrs = modInfo_rdrs mi+    tryExternalModuleResolution =+      case find (matchName $ mkFastString string) rdrs of+        Nothing -> throwE "Couldn't resolve to any modules."+        Just imported -> resolveNameFromModule infos imported++    matchName :: FastString -> Name -> Bool+    matchName str name =+      str ==+      occNameFS (getOccName name)++-- | Try to resolve the name from another (loaded) module's exports.+resolveNameFromModule :: GhcMonad m+                      => Map ModuleName ModInfo+                      -> Name+                      -> ExceptT SDoc m Name+resolveNameFromModule infos name = do+     modL <- maybe (throwE $ "No module for" <+> ppr name) return $+             nameModule_maybe name++     info <- maybe (throwE (ppr (moduleUnit modL) <> ":" <>+                            ppr modL)) return $+             M.lookup (moduleName modL) infos++     let all_names = modInfo_rdrs info++     maybe (throwE "No matching export in any local modules.") return $+         find (matchName name) all_names+  where+    matchName :: Name -> Name -> Bool+    matchName x y = occNameFS (getOccName x) ==+                    occNameFS (getOccName y)++-- | Try to resolve the type display from the given span.+resolveName :: [SpanInfo] -> SpanInfo -> Maybe Var+resolveName spans' si = listToMaybe $ mapMaybe spaninfoVar $+                        reverse spans' `spaninfosWithin` si++-- | Try to find the type of the given span.+findType :: GhcMonad m+         => Map ModuleName ModInfo+         -> RealSrcSpan+         -> String+         -> ExceptT SDoc m (ModInfo, Type)+findType infos span0 string = do+    name  <- maybeToExceptT "Couldn't guess that module name. Does it exist?" $+             guessModule infos (srcSpanFilePath span0)++    info  <- maybeToExceptT "No module info for current file! Try loading it?" $+             MaybeT $ pure $ M.lookup name infos++    case resolveType (modinfoSpans info) (spanInfoFromRealSrcSpan' span0) of+        Nothing -> (,) info <$> lift (exprType TM_Inst string)+        Just ty -> return (info, ty)+  where+    -- | Try to resolve the type display from the given span.+    resolveType :: [SpanInfo] -> SpanInfo -> Maybe Type+    resolveType spans' si = listToMaybe $ mapMaybe spaninfoType $+                            reverse spans' `spaninfosWithin` si++-- | Guess a module name from a file path.+guessModule :: GhcMonad m+            => Map ModuleName ModInfo -> FilePath -> MaybeT m ModuleName+guessModule infos fp = do+    target <- lift $ guessTarget fp Nothing Nothing+    case targetId target of+        TargetModule mn  -> return mn+        TargetFile fp' _ -> guessModule' fp'+  where+    guessModule' :: GhcMonad m => FilePath -> MaybeT m ModuleName+    guessModule' fp' = case findModByFp fp' of+        Just mn -> return mn+        Nothing -> do+            fp'' <- liftIO (makeRelativeToCurrentDirectory fp')++            target' <- lift $ guessTarget fp'' Nothing Nothing+            case targetId target' of+                TargetModule mn -> return mn+                _               -> MaybeT . pure $ findModByFp fp''++    findModByFp :: FilePath -> Maybe ModuleName+    findModByFp fp' = fst <$> find ((Just fp' ==) . mifp) (M.toList infos)+      where+        mifp :: (ModuleName, ModInfo) -> Maybe FilePath+        mifp = ml_hs_file . ms_location . modinfoSummary . snd+++-- | Collect type info data for the loaded modules.+collectInfo :: (GhcMonad m) => Map ModuleName ModInfo -> [ModuleName]+               -> m (Map ModuleName ModInfo)+collectInfo ms loaded = do+    df <- getDynFlags+    unit_state <- hsc_units <$> getSession+    liftIO (filterM cacheInvalid loaded) >>= \case+        [] -> return ms+        invalidated -> do+            liftIO (putStrLn ("Collecting type info for " +++                              show (length invalidated) +++                              " module(s) ... "))++            foldM (go df unit_state) ms invalidated+  where+    go df unit_state m name = do { info <- getModInfo name; return (M.insert name info m) }+                   `MC.catch`+                   (\(e :: SomeException) -> do+                         liftIO $ putStrLn+                                $ showSDocForUser df unit_state alwaysQualify+                                $ "Error while getting type info from" <+>+                                  ppr name <> ":" <+> text (show e)+                         return m)++    cacheInvalid name = case M.lookup name ms of+        Nothing -> return True+        Just mi -> do+            let fp = srcFilePath (modinfoSummary mi)+                last' = modinfoLastUpdate mi+            current <- getModificationTime fp+            exists <- doesFileExist fp+            if exists+                then return $ current /= last'+                else return True++-- | Get the source file path from a ModSummary.+-- If the .hs file is missing, and the .o file exists,+-- we return the .o file path.+srcFilePath :: ModSummary -> FilePath+srcFilePath modSum = fromMaybe obj_fp src_fp+    where+        src_fp = ml_hs_file ms_loc+        obj_fp = ml_obj_file ms_loc+        ms_loc = ms_location modSum++-- | Get info about the module: summary, types, etc.+getModInfo :: (GhcMonad m) => ModuleName -> m ModInfo+getModInfo name = do+    m <- getModSummary name+    p <- parseModule m+    typechecked <- typecheckModule p+    let allTypes = processAllTypeCheckedModule typechecked+        module_info = tm_checked_module_info typechecked+        !rdr_env = case modInfoRdrEnv module_info of+          Just rdrs -> Strict.Just rdrs+            -- NB: this has already been deeply forced; no need to do that again.+            -- See test case T15369 and Note [Forcing GREInfo] in GHC.Types.GREInfo.+          Nothing   -> Strict.Nothing+    ts <- liftIO $ getModificationTime $ srcFilePath m+    return $+      ModInfo+        { modinfoSummary    = m+        , modinfoSpans      = allTypes+        , modinfoRdrEnv     = rdr_env+        , modinfoLastUpdate = ts+        }++-- | Get the 'Name's from the 'GlobalRdrEnv' of the 'ModInfo', if any.+modInfo_rdrs :: ModInfo -> [Name]+modInfo_rdrs mi =+  case modinfoRdrEnv mi of+    Strict.Nothing  -> []+    Strict.Just env -> map greName $ globalRdrEnvElts env++-- | Get ALL source spans in the module.+processAllTypeCheckedModule :: TypecheckedModule -> [SpanInfo]+processAllTypeCheckedModule tcm+  = mapMaybe toSpanInfo+  $ sortBy cmpSpan+  $ catMaybes (bts ++ ets ++ pts)+  where+    bts = map getTypeLHsBind $ listifyAllSpans tcs+    ets = map getTypeLHsExpr $ listifyAllSpans tcs+    pts = map getTypeLPat    $ listifyAllSpans tcs++    tcs = tm_typechecked_source tcm++    -- | Extract 'Id', 'SrcSpan', and 'Type' for 'LHsBind's+    getTypeLHsBind :: LHsBind GhcTc -> Maybe (Maybe Id,SrcSpan,Type)+    getTypeLHsBind (L _spn FunBind{fun_id = pid,fun_matches = MG _ _})+        = Just (Just (unLoc pid), getLocA pid,varType (unLoc pid))+    getTypeLHsBind _ = Nothing++    -- | Extract 'Id', 'SrcSpan', and 'Type' for 'LHsExpr's+    getTypeLHsExpr :: LHsExpr GhcTc -> Maybe (Maybe Id,SrcSpan,Type)+    getTypeLHsExpr e = Just (mid, getLocA e, lhsExprType e)+      where+        mid :: Maybe Id+        mid | HsVar _ (L _ i) <- unwrapVar (unLoc e) = Just i+            | otherwise                              = Nothing++        unwrapVar (XExpr (WrapExpr (HsWrap _ var))) = var+        unwrapVar e'                                = e'++    -- | Extract 'Id', 'SrcSpan', and 'Type' for 'LPats's+    getTypeLPat :: LPat GhcTc -> Maybe (Maybe Id,SrcSpan,Type)+    getTypeLPat (L spn pat) = Just (getMaybeId pat,locA spn,hsPatType pat)+      where+        getMaybeId :: Pat GhcTc -> Maybe Id+        getMaybeId (VarPat _ (L _ vid)) = Just vid+        getMaybeId _                        = Nothing++    -- | Get ALL source spans in the source.+    listifyAllSpans :: Typeable a => TypecheckedSource -> [LocatedA a]+    listifyAllSpans = everythingAllSpans (++) [] ([] `mkQ` (\x -> [x | p x]))+      where+        p (L spn _) = isGoodSrcSpan (locA spn)++    -- | Variant of @syb@'s @everything@ (which summarises all nodes+    -- in top-down, left-to-right order) with a stop-condition on 'NameSet's+    -- and 'OverLitTc'+    everythingAllSpans :: (r -> r -> r) -> r -> GenericQ r -> GenericQ r+    everythingAllSpans k z f x+      | (False `mkQ` (const True :: NameSet -> Bool)) x = z+      -- Exception for OverLitTc: we have SrcSpans in the ol_witness field,+      -- but it's there only for HIE file info (see Note [Source locations for implicit function calls]).+      -- T16804 fails without this.+      | (False `mkQ` (const True :: OverLitTc -> Bool)) x = z+      | otherwise = foldl k (f x) (gmapQ (everythingAllSpans k z f) x)++    cmpSpan (_,a,_) (_,b,_)+      | a `isSubspanOf` b = LT+      | b `isSubspanOf` a = GT+      | otherwise         = EQ++    -- | Pretty print the types into a 'SpanInfo'.+    toSpanInfo :: (Maybe Id,SrcSpan,Type) -> Maybe SpanInfo+    toSpanInfo (n,RealSrcSpan spn _,typ)+        = Just $ spanInfoFromRealSrcSpan spn (Just typ) n+    toSpanInfo _ = Nothing++-- helper stolen from @syb@ package+type GenericQ r = forall a. Data a => a -> r++mkQ :: (Typeable a, Typeable b) => r -> (b -> r) -> a -> r+(r `mkQ` br) a = maybe r br (cast a)
+ app-ghc-9.10/GHCi/UI/Monad.hs view
@@ -0,0 +1,612 @@+{-# LANGUAGE FlexibleInstances, DeriveFunctor, DerivingVia #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-----------------------------------------------------------------------------+--+-- Monadery code used in InteractiveUI+--+-- (c) The GHC Team 2005-2006+--+-----------------------------------------------------------------------------++module GHCi.UI.Monad (+        GHCi(..), startGHCi,+        GHCiState(..), GhciMonad(..),+        GHCiOption(..), isOptionSet, setOption, unsetOption,+        Command(..), CommandResult(..), cmdSuccess,+        CmdExecOutcome(..),+        LocalConfigBehaviour(..),+        PromptFunction,+        BreakLocation(..),+        TickArray,+        extractDynFlags, getDynFlags,++        runStmt, runDecls, runDecls', resume, recordBreak, revertCAFs,+        ActionStats(..), runAndPrintStats, runWithStats, printStats,++        printForUserNeverQualify,+        printForUserModInfo, printForUserGlobalRdrEnv,+        printForUser, printForUserPartWay, prettyLocations,++        compileGHCiExpr,+        initInterpBuffering,+        turnOffBuffering, turnOffBuffering_,+        flushInterpBuffers,+        runInternal,+        mkEvalWrapper,++        -- DAP added.+        dapLookupMaxBreakLocation+    ) where++import GHCi.UI.Info (ModInfo)+import qualified GHC+import GHC.Driver.Monad hiding (liftIO)+import GHC.Utils.Outputable+import qualified GHC.Driver.Ppr as Ppr+import GHC.Types.Name.Occurrence+import GHC.Types.Name.Reader+import GHC.Driver.Session+import GHC.Data.FastString+import GHC.Driver.Env+import GHC.Types.SrcLoc+import GHC.Types.SafeHaskell+import GHC.Driver.Make (ModIfaceCache(..))+import GHC.Unit+import GHC.Types.Name.Reader as RdrName (mkOrig)+import qualified GHC.Types.Name.Ppr as Ppr (mkNamePprCtx)+import GHC.Builtin.Names (gHC_INTERNAL_GHCI_HELPERS)+import GHC.Runtime.Interpreter+import GHC.Runtime.Context+import GHCi.RemoteTypes+import GHCi.UI.Exception (printGhciException)+import GHC.Hs (ImportDecl, GhcPs, GhciLStmt, LHsDecl)+import GHC.Hs.Utils+import GHC.Utils.Misc+import GHC.Utils.Logger++import GHC.Utils.Exception hiding (uninterruptibleMask, mask, catch)+import Numeric+import Data.Array+import Data.IORef+import Data.Time+import System.Environment+import System.IO+import Control.Monad+import Prelude hiding ((<>))++import System.Console.Haskeline (CompletionFunc, InputT)+import Control.Monad.Catch as MC+import Control.Monad.Trans.Class+import Control.Monad.Trans.Reader+import Control.Monad.IO.Class+import Data.Map.Strict (Map)+import qualified Data.IntMap.Strict as IntMap+import qualified GHC.Data.EnumSet as EnumSet+import qualified GHC.LanguageExtensions as LangExt++-- DAP add.+import qualified GHCi.DAP.Type as DAP+import Control.Concurrent+import GHC.Types.SourceError+++-----------------------------------------------------------------------------+-- GHCi monad++data GHCiState = GHCiState+     {+        progname       :: String,+        args           :: [String],+        evalWrapper    :: ForeignHValue, -- ^ of type @IO a -> IO a@+        prompt         :: PromptFunction,+        prompt_cont    :: PromptFunction,+        editor         :: String,+        stop           :: String,+        multiMode      :: Bool,+        localConfig    :: LocalConfigBehaviour,+        options        :: [GHCiOption],+        line_number    :: !Int,         -- ^ input line+        break_ctr      :: !Int,+        breaks         :: !(IntMap.IntMap BreakLocation),+        tickarrays     :: ModuleEnv TickArray,+            -- ^ 'tickarrays' caches the 'TickArray' for loaded modules,+            -- so that we don't rebuild it each time the user sets+            -- a breakpoint.+        ghci_commands  :: [Command],+            -- ^ available ghci commands+        ghci_macros    :: [Command],+            -- ^ user-defined macros+        last_command   :: Maybe Command,+            -- ^ @:@ at the GHCi prompt repeats the last command, so we+            -- remember it here+        cmd_wrapper    :: InputT GHCi CommandResult -> InputT GHCi (Maybe Bool),+            -- ^ The command wrapper is run for each command or statement.+            -- The 'Bool' value denotes whether the command is successful and+            -- 'Nothing' means to exit GHCi.+        cmdqueue       :: [String],++        remembered_ctx :: [InteractiveImport],+            -- ^ The imports that the user has asked for, via import+            -- declarations and :module commands.  This list is+            -- persistent over :reloads (but any imports for modules+            -- that are not loaded are temporarily ignored).  After a+            -- :load, all the home-package imports are stripped from+            -- this list.+            --+            -- See bugs #2049, #1873, #1360++        transient_ctx  :: [InteractiveImport],+            -- ^ An import added automatically after a :load, usually of+            -- the most recently compiled module.  May be empty if+            -- there are no modules loaded.  This list is replaced by+            -- :load, :reload, and :add.  In between it may be modified+            -- by :module.++        extra_imports  :: [ImportDecl GhcPs],+            -- ^ These are "always-on" imports, added to the+            -- context regardless of what other imports we have.+            -- This is useful for adding imports that are required+            -- by setGHCiMonad.  Be careful adding things here:+            -- you can create ambiguities if these imports overlap+            -- with other things in scope.+            --+            -- NB. although this is not currently used by GHCi itself,+            -- it was added to support other front-ends that are based+            -- on the GHCi code.  Potentially we could also expose+            -- this functionality via GHCi commands.++        prelude_imports :: [ImportDecl GhcPs],+            -- ^ These imports are added to the context when+            -- -XImplicitPrelude is on and we don't have a *-module+            -- in the context.  They can also be overridden by another+            -- import for the same module, e.g.+            -- "import Prelude hiding (map)"++        ghc_e :: Bool, -- ^ True if this is 'ghc -e' (or runghc)++        short_help :: String,+            -- ^ help text to display to a user+        long_help  :: String,+        lastErrorLocations :: IORef [(FastString, Int)],++        mod_infos  :: !(Map ModuleName ModInfo),++        flushStdHandles :: ForeignHValue,+            -- ^ @hFlush stdout; hFlush stderr@ in the interpreter+        noBuffering :: ForeignHValue,+            -- ^ @hSetBuffering NoBuffering@ for stdin/stdout/stderr+        ifaceCache :: ModIfaceCache,+        dapContextGHCiState :: DAP.MVarDAPContext    -- DAP added.+     }++type TickArray = Array Int [(GHC.BreakIndex,RealSrcSpan)]++-- | A GHCi command+data Command+   = Command+   { cmdName           :: String+     -- ^ Name of GHCi command (e.g. "exit")+   , cmdAction         :: String -> InputT GHCi CmdExecOutcome+     -- ^ The 'CmdExecOutcome' value denotes whether to exit GHCi cleanly or error out+   , cmdHidden         :: Bool+     -- ^ Commands which are excluded from default completion+     -- and @:help@ summary. This is usually set for commands not+     -- useful for interactive use but rather for IDEs.+   , cmdCompletionFunc :: CompletionFunc GHCi+     -- ^ 'CompletionFunc' for arguments+   }++-- | Used to denote GHCi command execution result. Specifically, used to+-- distinguish between two ghci execution modes - "REPL" and "Expression+-- evaluation mode (ghc -e)". When in "REPL" mode, we don't want to exit+-- GHCi session when error occurs, (which is when we use "CmdSuccess").+-- Otherwise, when in expression evaluation mode, all command failures+-- should lead to GHCi session termination (with ExitFailure 1) which is+-- when "CmdFailure" is used(this is useful when executing scripts).+-- "CleanExit" is used to signal end of GHCi session (for example, when+-- ":quit" command is called).+data CmdExecOutcome+  = CleanExit+  | CmdSuccess+  | CmdFailure++data CommandResult+   = CommandComplete+   { cmdInput :: String+   , cmdResult :: Either SomeException (Maybe Bool)+   , cmdStats :: ActionStats+   }+   | CommandIncomplete+     -- ^ Unterminated multiline command+   deriving Show++cmdSuccess :: MonadThrow m => CommandResult -> m (Maybe Bool)+cmdSuccess CommandComplete{ cmdResult = Left e } = throwM e+cmdSuccess CommandComplete{ cmdResult = Right r } = return r+cmdSuccess CommandIncomplete = return $ Just True++type PromptFunction = [String]+                   -> Int+                   -> GHCi SDoc++data GHCiOption+        = ShowTiming            -- show time/allocs after evaluation+        | ShowType              -- show the type of expressions+        | RevertCAFs            -- revert CAFs after every evaluation+        | Multiline             -- use multiline commands+        | CollectInfo           -- collect and cache information about+                                -- modules after load+        deriving Eq++-- | Treatment of ./.ghci files.  For now we either load or+-- ignore.  But later we could implement a "safe mode" where+-- only safe operations are performed.+--+data LocalConfigBehaviour+  = SourceLocalConfig+  | IgnoreLocalConfig+  deriving (Eq)++data BreakLocation+   = BreakLocation+   { breakModule :: !GHC.Module+   , breakLoc    :: !SrcSpan+   , breakTick   :: {-# UNPACK #-} !Int+   , breakEnabled:: !Bool+   , onBreakCmd  :: String+   }++instance Eq BreakLocation where+  loc1 == loc2 = breakModule loc1 == breakModule loc2 &&+                 breakTick loc1   == breakTick loc2++prettyLocations :: IntMap.IntMap BreakLocation -> SDoc+prettyLocations  locs =+    case  IntMap.null locs of+      True  -> text "No active breakpoints."+      False -> vcat $ map (\(i, loc) -> brackets (int i) <+> ppr loc) $ IntMap.toAscList locs++instance Outputable BreakLocation where+   ppr loc = (ppr $ breakModule loc) <+> ppr (breakLoc loc) <+> pprEnaDisa <+>+                if null (onBreakCmd loc)+                   then empty+                   else doubleQuotes (text (onBreakCmd loc))+      where pprEnaDisa = case breakEnabled loc of+                True  -> text "enabled"+                False -> text "disabled"++recordBreak+  :: GhciMonad m => BreakLocation -> m (Bool{- was already present -}, Int)+recordBreak brkLoc = do+   st <- getGHCiState+   let oldmap = breaks st+       oldActiveBreaks = IntMap.assocs oldmap+   -- don't store the same break point twice+   case [ nm | (nm, loc) <- oldActiveBreaks, loc == brkLoc ] of+     (nm:_) -> return (True, nm)+     [] -> do+      let oldCounter = break_ctr st+          newCounter = oldCounter + 1+      setGHCiState $ st { break_ctr = newCounter,+                          breaks = IntMap.insert oldCounter brkLoc oldmap+                        }+      return (False, oldCounter)++newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> Ghc a }+    deriving (Functor)+    deriving (MonadThrow, MonadCatch, MonadMask) via (ReaderT (IORef GHCiState) Ghc)++reflectGHCi :: (Session, IORef GHCiState) -> GHCi a -> IO a+reflectGHCi (s, gs) m = unGhc (unGHCi m gs) s++startGHCi :: GHCi a -> GHCiState -> Ghc a+startGHCi g state = do ref <- liftIO $ newIORef state; unGHCi g ref++instance Applicative GHCi where+    pure a = GHCi $ \_ -> pure a+    (<*>) = ap++instance Monad GHCi where+  (GHCi m) >>= k  =  GHCi $ \s -> m s >>= \a -> unGHCi (k a) s++class GhcMonad m => GhciMonad m where+  getGHCiState    :: m GHCiState+  setGHCiState    :: GHCiState -> m ()+  modifyGHCiState :: (GHCiState -> GHCiState) -> m ()+  reifyGHCi       :: ((Session, IORef GHCiState) -> IO a) -> m a++instance GhciMonad GHCi where+  getGHCiState      = GHCi $ \r -> liftIO $ readIORef r+  setGHCiState s    = GHCi $ \r -> liftIO $ writeIORef r s+  modifyGHCiState f = GHCi $ \r -> liftIO $ modifyIORef' r f+  reifyGHCi f       = GHCi $ \r -> reifyGhc $ \s -> f (s, r)++instance GhciMonad (InputT GHCi) where+  getGHCiState    = lift getGHCiState+  setGHCiState    = lift . setGHCiState+  modifyGHCiState = lift . modifyGHCiState+  reifyGHCi       = lift . reifyGHCi++liftGhc :: Ghc a -> GHCi a+liftGhc m = GHCi $ \_ -> m++instance MonadIO GHCi where+  liftIO = liftGhc . liftIO++instance HasDynFlags GHCi where+  getDynFlags = getSessionDynFlags++instance HasLogger GHCi where+  getLogger = hsc_logger <$> getSession++instance GhcMonad GHCi where+  setSession s' = liftGhc $ setSession s'+  getSession    = liftGhc $ getSession+++instance HasDynFlags (InputT GHCi) where+  getDynFlags = lift getDynFlags++instance HasLogger (InputT GHCi) where+  getLogger = lift getLogger++instance GhcMonad (InputT GHCi) where+  setSession = lift . setSession+  getSession = lift getSession++isOptionSet :: GhciMonad m => GHCiOption -> m Bool+isOptionSet opt+ = do st <- getGHCiState+      return $! (opt `elem` options st)++setOption :: GhciMonad m => GHCiOption -> m ()+setOption opt+ = do st <- getGHCiState+      setGHCiState (st{ options = opt : filter (/= opt) (options st) })++unsetOption :: GhciMonad m => GHCiOption -> m ()+unsetOption opt+ = do st <- getGHCiState+      setGHCiState (st{ options = filter (/= opt) (options st) })++printForUserNeverQualify :: GhcMonad m => SDoc -> m ()+printForUserNeverQualify doc = do+  dflags <- GHC.getInteractiveDynFlags+  liftIO $ Ppr.printForUser dflags stdout neverQualify AllTheWay doc++printForUserModInfo :: GhcMonad m => GHC.ModuleInfo -> SDoc -> m ()+printForUserModInfo info = printForUserGlobalRdrEnv (GHC.modInfoRdrEnv info)++printForUserGlobalRdrEnv :: (GhcMonad m, Outputable info)+                         => Maybe (GlobalRdrEnvX info) -> SDoc -> m ()+printForUserGlobalRdrEnv mb_rdr_env doc = do+  dflags <- GHC.getInteractiveDynFlags+  name_ppr_ctx <- mkNamePprCtxFromGlobalRdrEnv dflags mb_rdr_env+  liftIO $ Ppr.printForUser dflags stdout name_ppr_ctx AllTheWay doc+    where+      mkNamePprCtxFromGlobalRdrEnv _ Nothing = GHC.getNamePprCtx+      mkNamePprCtxFromGlobalRdrEnv dflags (Just rdr_env) =+        withSession $ \ hsc_env ->+        let unit_env = hsc_unit_env hsc_env+            ptc = initPromotionTickContext dflags+        in  return $ Ppr.mkNamePprCtx ptc unit_env rdr_env++printForUser :: GhcMonad m => SDoc -> m ()+printForUser doc = do+  name_ppr_ctx <- GHC.getNamePprCtx+  dflags <- GHC.getInteractiveDynFlags+  liftIO $ Ppr.printForUser dflags stdout name_ppr_ctx AllTheWay doc++printForUserPartWay :: GhcMonad m => SDoc -> m ()+printForUserPartWay doc = do+  name_ppr_ctx <- GHC.getNamePprCtx+  dflags <- GHC.getInteractiveDynFlags+  liftIO $ Ppr.printForUser dflags stdout name_ppr_ctx DefaultDepth doc++-- | Run a single Haskell expression+runStmt+  :: GhciMonad m+  => GhciLStmt GhcPs -> String -> GHC.SingleStep -> m (Maybe GHC.ExecResult)+runStmt stmt stmt_text step = do+  st <- getGHCiState+  GHC.handleSourceError (\e -> do GHC.printException e; dapSaveRunStmtDeclException e; return Nothing) $ do    -- DAP modified.+    let opts = GHC.execOptions+                  { GHC.execSourceFile = progname st+                  , GHC.execLineNumber = line_number st+                  , GHC.execSingleStep = step+                  , GHC.execWrap = \fhv -> EvalApp (EvalThis (evalWrapper st))+                                                   (EvalThis fhv) }+    Just <$> GHC.execStmt' stmt stmt_text opts++runDecls :: GhciMonad m => String -> m (Maybe [GHC.Name])+runDecls decls = do+  st <- getGHCiState+  reifyGHCi $ \x ->+    withProgName (progname st) $+    withArgs (args st) $+      reflectGHCi x $ do+        GHC.handleSourceError (\e -> do printGhciException e+                                        dapSaveRunStmtDeclException e;         -- DAP added.+                                        return Nothing) $ do+          r <- GHC.runDeclsWithLocation (progname st) (line_number st) decls+          return (Just r)++runDecls' :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe [GHC.Name])+runDecls' decls = do+  st <- getGHCiState+  reifyGHCi $ \x ->+    withProgName (progname st) $+    withArgs (args st) $+    reflectGHCi x $+      GHC.handleSourceError+        (\e -> do printGhciException e+                  return Nothing)+        (Just <$> GHC.runParsedDecls decls)++resume :: GhciMonad m => (SrcSpan -> Bool) -> GHC.SingleStep -> Maybe Int -> m GHC.ExecResult+resume canLogSpan step mbIgnoreCnt = do+  st <- getGHCiState+  reifyGHCi $ \x ->+    withProgName (progname st) $+    withArgs (args st) $+      reflectGHCi x $ do+        GHC.resumeExec canLogSpan step mbIgnoreCnt++-- --------------------------------------------------------------------------+-- timing & statistics++data ActionStats = ActionStats+  { actionAllocs :: Maybe Integer+  , actionElapsedTime :: Double+  } deriving Show++runAndPrintStats+  :: GhciMonad m+  => (a -> Maybe Integer)+  -> m a+  -> m (ActionStats, Either SomeException a)+runAndPrintStats getAllocs action = do+  result <- runWithStats getAllocs action+  case result of+    (stats, Right{}) -> do+      showTiming <- isOptionSet ShowTiming+      when showTiming $ do+        dflags  <- getDynFlags+        liftIO $ printStats dflags stats+    _ -> return ()+  return result++runWithStats+  :: ExceptionMonad m+  => (a -> Maybe Integer) -> m a -> m (ActionStats, Either SomeException a)+runWithStats getAllocs action = do+  t0 <- liftIO getCurrentTime+  result <- MC.try action+  let allocs = either (const Nothing) getAllocs result+  t1 <- liftIO getCurrentTime+  let elapsedTime = realToFrac $ t1 `diffUTCTime` t0+  return (ActionStats allocs elapsedTime, result)++printStats :: DynFlags -> ActionStats -> IO ()+printStats dflags ActionStats{actionAllocs = mallocs, actionElapsedTime = secs}+   = do let secs_str = showFFloat (Just 2) secs+        putStrLn (Ppr.showSDoc dflags (+                 parens (text (secs_str "") <+> text "secs" <> comma <+>+                         case mallocs of+                           Nothing -> empty+                           Just allocs ->+                             text (separateThousands allocs) <+> text "bytes")))+  where+    separateThousands n = reverse . separate . reverse . show $ n+      where separate n'+              | n' `lengthAtMost` 3 = n'+              | otherwise           = take 3 n' ++ "," ++ separate (drop 3 n')++-----------------------------------------------------------------------------+-- reverting CAFs++revertCAFs :: GhciMonad m => m ()+revertCAFs = do+  interp <- hscInterp <$> GHC.getSession+  liftIO $ interpCmd interp RtsRevertCAFs+  s <- getGHCiState+  when (not (ghc_e s)) turnOffBuffering+     -- Have to turn off buffering again, because we just+     -- reverted stdout, stderr & stdin to their defaults.+++-----------------------------------------------------------------------------+-- To flush buffers for the *interpreted* computation we need+-- to refer to *its* stdout/stderr handles++-- | Compile "hFlush stdout; hFlush stderr" once, so we can use it repeatedly+initInterpBuffering :: Ghc (ForeignHValue, ForeignHValue)+initInterpBuffering = do+  let mkHelperExpr :: OccName -> Ghc ForeignHValue+      mkHelperExpr occ =+        GHC.compileParsedExprRemote+        $ GHC.nlHsVar $ RdrName.mkOrig gHC_INTERNAL_GHCI_HELPERS occ+  nobuf <- mkHelperExpr $ mkVarOccFS (fsLit "disableBuffering")+  flush <- mkHelperExpr $ mkVarOccFS (fsLit "flushAll")+  return (nobuf, flush)++-- | Invoke "hFlush stdout; hFlush stderr" in the interpreter+flushInterpBuffers :: GhciMonad m => m ()+flushInterpBuffers = do+  st <- getGHCiState+  interp <- hscInterp <$> GHC.getSession+  liftIO $ evalIO interp (flushStdHandles st)++-- | Turn off buffering for stdin, stdout, and stderr in the interpreter+turnOffBuffering :: GhciMonad m => m ()+turnOffBuffering = do+  st <- getGHCiState+  turnOffBuffering_ (noBuffering st)++turnOffBuffering_ :: GhcMonad m => ForeignHValue -> m ()+turnOffBuffering_ fhv = do+  interp <- hscInterp <$> getSession+  liftIO $ evalIO interp fhv++mkEvalWrapper :: GhcMonad m => String -> [String] ->  m ForeignHValue+mkEvalWrapper progname' args' =+  runInternal $ GHC.compileParsedExprRemote+  $ evalWrapper' `GHC.mkHsApp` nlHsString progname'+                 `GHC.mkHsApp` nlList (map nlHsString args')+  where+    nlHsString = nlHsLit . mkHsString+    evalWrapper' =+      GHC.nlHsVar $ RdrName.mkOrig gHC_INTERNAL_GHCI_HELPERS (mkVarOccFS (fsLit "evalWrapper"))++-- | Run a 'GhcMonad' action to compile an expression for internal usage.+runInternal :: GhcMonad m => m a -> m a+runInternal =+    withTempSession mkTempSession+  where+    mkTempSession = hscUpdateFlags (\dflags -> dflags+      { -- Running GHCi's internal expression is incompatible with -XSafe.+          -- We temporarily disable any Safe Haskell settings while running+          -- GHCi internal expressions. (see #12509)+        safeHaskell = Sf_None,+          -- Disable dumping of any data during evaluation of GHCi's internal+          -- expressions. (#17500)+        dumpFlags = EnumSet.empty+      }+        -- RebindableSyntax can wreak havoc with GHCi in several ways+          -- (see #13385 and #14342 for examples), so we temporarily+          -- disable it too.+          `xopt_unset` LangExt.RebindableSyntax+          -- We heavily depend on -fimplicit-import-qualified to compile expr+          -- with fully qualified names without imports.+          `gopt_set` Opt_ImplicitImportQualified+      )++compileGHCiExpr :: GhcMonad m => String -> m ForeignHValue+compileGHCiExpr expr = runInternal $ GHC.compileExprRemote expr+++------------------------------------------------------------------------------------------------+--  DAP Utility+------------------------------------------------------------------------------------------------++-- |+--+dapSaveRunStmtDeclException :: GhciMonad m => SourceError -> m SourceError+dapSaveRunStmtDeclException res = do+  mvarCtx <- dapContextGHCiState <$> getGHCiState++  ctx <- liftIO $ takeMVar mvarCtx+  liftIO $ putMVar mvarCtx ctx{DAP.runStmtDeclExceptionDAPContext = Just res}++  return res+++-- |+--+dapLookupMaxBreakLocation :: GhciMonad m => m (Maybe (Int, BreakLocation))+dapLookupMaxBreakLocation = do+  newSt <- getGHCiState+  return $ IntMap.lookupMax (breaks newSt)++
+ app-ghc-9.10/GHCi/Util.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE MagicHash, UnboxedTuples #-}++-- | Utilities for GHCi.+module GHCi.Util where++-- NOTE: Avoid importing GHC modules here, because the primary purpose+-- of this module is to not use UnboxedTuples in a module that imports+-- lots of other modules.  See issue#13101 for more info.++import GHC.Exts+import GHC.Types++anyToPtr :: a -> IO (Ptr ())+anyToPtr x =+  IO (\s -> case anyToAddr# x s of+              (# s', addr #) -> (# s', Ptr addr #)) :: IO (Ptr ())
− app-ghc-9.4/GHCMain.hs
@@ -1,1135 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NondecreasingIndentation #-}-{-# LANGUAGE TupleSections #-}-{-# OPTIONS -fno-warn-incomplete-patterns -optc-DNON_POSIX_SOURCE #-}------------------------------------------------------------------------------------- GHC Driver program------ (c) The University of Glasgow 2005-----------------------------------------------------------------------------------module GHCMain (ghcMain) where    -- DAP Modified---- The official GHC API-import qualified GHC-import GHC              (parseTargetFiles,  Ghc, GhcMonad(..), Backend (..),-                          LoadHowMuch(..) )--import GHC.Driver.CmdLine-import GHC.Driver.Env-import GHC.Driver.Errors-import GHC.Driver.Phases-import GHC.Driver.Session-import GHC.Driver.Ppr-import GHC.Driver.Pipeline  ( oneShot, compileFile )-import GHC.Driver.MakeFile  ( doMkDependHS )-import GHC.Driver.Backpack  ( doBackpack )-import GHC.Driver.Plugins-import GHC.Driver.Config.Logger (initLogFlags)-import GHC.Driver.Config.Diagnostic--import GHC.Platform-import GHC.Platform.Ways-import GHC.Platform.Host--#if defined(HAVE_INTERNAL_INTERPRETER)-import GHCi.UI              ( interactiveUI, ghciWelcomeMsg, GhciSettings )  -- DAP Modified-#endif--import GHC.Runtime.Loader   ( loadFrontendPlugin )--import GHC.Unit.Env-import GHC.Unit (UnitId, homeUnitDepends)-import GHC.Unit.Home.ModInfo (emptyHomePackageTable)-import GHC.Unit.Module ( ModuleName, mkModuleName )-import GHC.Unit.Module.ModIface-import GHC.Unit.State  ( pprUnits, pprUnitsSimple )-import GHC.Unit.Finder ( findImportedModule, FindResult(..) )-import qualified GHC.Unit.State as State-import GHC.Unit.Types  ( IsBootInterface(..) )--import GHC.Types.Basic     ( failed )-import GHC.Types.SrcLoc-import GHC.Types.SourceError-import GHC.Types.Unique.Supply-import GHC.Types.PkgQual--import GHC.Utils.Error-import GHC.Utils.Misc-import GHC.Utils.Panic-import GHC.Utils.Outputable as Outputable-import GHC.Utils.Monad       ( liftIO, mapMaybeM )-import GHC.Utils.Binary        ( openBinMem, put_ )-import GHC.Utils.Logger--import GHC.Settings.Config-import GHC.Settings.Constants-import GHC.Settings.IO--import GHC.HandleEncoding-import GHC.Data.FastString-import GHC.SysTools.BaseDir--import GHC.Iface.Load-import GHC.Iface.Recomp.Binary ( fingerprintBinMem )--import GHC.Tc.Utils.Monad      ( initIfaceCheck )-import System.FilePath---- Standard Haskell libraries-import System.IO-import System.Environment-import System.Exit-import Control.Monad-import Control.Monad.Trans.Class-import Control.Monad.Trans.Except (throwE, runExceptT)-import Data.Char-import Data.List ( isPrefixOf, partition, intercalate, (\\) )-import qualified Data.Set as Set-import qualified Data.Map as Map-import Data.Maybe-import Prelude-import GHC.ResponseFile (expandResponse)-import Data.Bifunctor-import GHC.Data.Graph.Directed-import qualified Data.List.NonEmpty as NE---- DAP add-import qualified GHC.Paths---------------------------------------------------------------------------------- ToDo:---- time commands when run with -v--- user ways--- Win32 support: proper signal handling--- reading the package configuration file is too slow--- -K<size>---------------------------------------------------------------------------------- GHC's command-line interface--ghcMain :: GhciSettings -> IO ()    -- DAP Modified-ghcMain setting = do                -- DAP Modified-   hSetBuffering stdout LineBuffering-   hSetBuffering stderr LineBuffering--   configureHandleEncoding-   GHC.defaultErrorHandler defaultFatalMessager defaultFlushOut $ do-    -- 1. extract the -B flag from the args-    argv0 <- getArgs--    let (minusB_args, argv1) = partition ("-B" `isPrefixOf`) argv0-        mbMinusB | null minusB_args = Just GHC.Paths.libdir       -- DAP Modified-                 | otherwise = Just (drop 2 (last minusB_args))--    let argv2 = map (mkGeneralLocated "on the commandline") argv1--    -- 2. Parse the "mode" flags (--make, --interactive etc.)-    (mode, units, argv3, flagWarnings) <- parseModeFlags argv2--    -- If all we want to do is something like showing the version number-    -- then do it now, before we start a GHC session etc. This makes-    -- getting basic information much more resilient.--    -- In particular, if we wait until later before giving the version-    -- number then bootstrapping gets confused, as it tries to find out-    -- what version of GHC it's using before package.conf exists, so-    -- starting the session fails.-    case mode of-        Left preStartupMode ->-            do case preStartupMode of-                   ShowSupportedExtensions   -> showSupportedExtensions mbMinusB-                   ShowVersion               -> showVersion-                   ShowNumVersion            -> putStrLn cProjectVersion-                   ShowOptions isInteractive -> showOptions isInteractive-        Right postStartupMode ->-            -- start our GHC session-            GHC.runGhc mbMinusB $ do--            dflags <- GHC.getSessionDynFlags--            case postStartupMode of-                Left preLoadMode ->-                    liftIO $ do-                        case preLoadMode of-                            ShowInfo               -> showInfo dflags-                            ShowGhcUsage           -> showGhcUsage  dflags-                            ShowGhciUsage          -> showGhciUsage dflags-                            PrintWithDynFlags f    -> putStrLn (f dflags)-                Right postLoadMode ->-                    main' setting postLoadMode units dflags argv3 flagWarnings          -- DAP Modified--main' :: GhciSettings -> PostLoadMode -> [String] -> DynFlags -> [Located String] -> [Warn]   -- DAP Modified-      -> Ghc ()-main' setting postLoadMode units dflags0 args flagWarnings = do                         -- DAP Modified-  let args' = case postLoadMode of-                DoRun -> takeWhile (\arg -> unLoc arg /= "--") args-                _     -> args--  -- set the default GhcMode, backend and GhcLink.  The backend-  -- can be further adjusted on a module by module basis, using only-  -- the -fllvm and -fasm flags.  If the default backend is not-  -- LLVM or NCG, -fllvm and -fasm have no effect.-  let dflt_backend = backend dflags0-      (mode, bcknd, link)-         = case postLoadMode of-               DoInteractive   -> (CompManager, Interpreter,  LinkInMemory)-               DoEval _        -> (CompManager, Interpreter,  LinkInMemory)-               DoRun           -> (CompManager, Interpreter,  LinkInMemory)-               DoMake          -> (CompManager, dflt_backend, LinkBinary)-               DoBackpack      -> (CompManager, dflt_backend, LinkBinary)-               DoMkDependHS    -> (MkDepend,    dflt_backend, LinkBinary)-               DoAbiHash       -> (OneShot,     dflt_backend, LinkBinary)-               _               -> (OneShot,     dflt_backend, LinkBinary)--  let dflags1 = dflags0{ ghcMode   = mode,-                         backend   = bcknd,-                         ghcLink   = link,-                         verbosity = case postLoadMode of-                                         DoEval _ -> 0-                                         DoRun    -> 0-                                         _other   -> 1-                        }--      -- turn on -fimplicit-import-qualified for GHCi now, so that it-      -- can be overridden from the command-line-      -- XXX: this should really be in the interactive DynFlags, but-      -- we don't set that until later in interactiveUI-      -- We also set -fignore-optim-changes and -fignore-hpc-changes,-      -- which are program-level options. Again, this doesn't really-      -- feel like the right place to handle this, but we don't have-      -- a great story for the moment.-      dflags2  | DoInteractive <- postLoadMode = def_ghci_flags-               | DoEval _      <- postLoadMode = def_ghci_flags-               | DoRun         <- postLoadMode = def_ghci_flags-               | otherwise                     = dflags1-        where def_ghci_flags = dflags1 `gopt_set` Opt_ImplicitImportQualified-                                       `gopt_set` Opt_IgnoreOptimChanges-                                       `gopt_set` Opt_IgnoreHpcChanges--  logger1 <- getLogger-  let logger2 = setLogFlags logger1 (initLogFlags dflags2)--        -- The rest of the arguments are "dynamic"-        -- Leftover ones are presumably files-  (dflags3, fileish_args, dynamicFlagWarnings) <--      GHC.parseDynamicFlags logger2 dflags2 args'--  let dflags4 = case bcknd of-                Interpreter | not (gopt Opt_ExternalInterpreter dflags3) ->-                    let platform = targetPlatform dflags3-                        dflags3a = dflags3 { targetWays_ = hostFullWays }-                        dflags3b = foldl gopt_set dflags3a-                                 $ concatMap (wayGeneralFlags platform)-                                             hostFullWays-                        dflags3c = foldl gopt_unset dflags3b-                                 $ concatMap (wayUnsetGeneralFlags platform)-                                             hostFullWays-                    in dflags3c-                _ ->-                    dflags3--  let logger4 = setLogFlags logger2 (initLogFlags dflags4)--  GHC.prettyPrintGhcErrors logger4 $ do--  let flagWarnings' = flagWarnings ++ dynamicFlagWarnings--  handleSourceError (\e -> do-       GHC.printException e-       liftIO $ exitWith (ExitFailure 1)) $ do-         liftIO $ handleFlagWarnings logger4 (initDiagOpts dflags4) flagWarnings'--  liftIO $ showBanner postLoadMode dflags4--  let (dflags5, srcs, objs) = parseTargetFiles dflags4 (map unLoc fileish_args)--  -- we've finished manipulating the DynFlags, update the session-  _ <- GHC.setSessionDynFlags dflags5-  dflags6 <- GHC.getSessionDynFlags-  hsc_env <- GHC.getSession-  logger <- getLogger--        ---------------- Display configuration ------------  case verbosity dflags6 of-    v | v == 4 -> liftIO $ dumpUnitsSimple hsc_env-      | v >= 5 -> liftIO $ dumpUnits       hsc_env-      | otherwise -> return ()--  liftIO $ initUniqSupply (initialUnique dflags6) (uniqueIncrement dflags6)-        ---------------- Final sanity checking ------------  liftIO $ checkOptions postLoadMode dflags6 srcs objs units--  ---------------- Do the business ------------  handleSourceError (\e -> do-       GHC.printException e-       liftIO $ exitWith (ExitFailure 1)) $ do-    case postLoadMode of-       ShowInterface f        -> liftIO $ showIface logger-                                                    (hsc_dflags hsc_env)-                                                    (hsc_units  hsc_env)-                                                    (hsc_NC     hsc_env)-                                                    f-       DoMake                 -> doMake units srcs-       DoMkDependHS           -> doMkDependHS (map fst srcs)-       StopBefore p           -> liftIO (oneShot hsc_env p srcs)-       DoInteractive          -> ghciUI setting units srcs Nothing                       -- DAP Modified-       DoEval exprs           -> ghciUI setting units srcs $ Just $ reverse exprs        -- DAP Modified-       DoRun                  -> doRun setting units srcs args                           -- DAP Modified-       DoAbiHash              -> abiHash (map fst srcs)-       ShowPackages           -> liftIO $ showUnits hsc_env-       DoFrontend f           -> doFrontend f srcs-       DoBackpack             -> doBackpack (map fst srcs)--  liftIO $ dumpFinalStats logger--doRun :: GhciSettings -> [String] -> [(FilePath, Maybe Phase)] -> [Located String] -> Ghc ()    -- DAP Modified-doRun setting units srcs args = do-    dflags <- getDynFlags-    let mainFun = fromMaybe "main" (mainFunIs dflags)-    ghciUI setting units srcs (Just ["System.Environment.withArgs " ++ show args' ++ " (Control.Monad.void " ++ mainFun ++ ")"])-  where-    args' = drop 1 $ dropWhile (/= "--") $ map unLoc args--ghciUI :: GhciSettings -> [String] -> [(FilePath, Maybe Phase)] -> Maybe [String] -> Ghc ()    -- DAP Modified-#if !defined(HAVE_INTERNAL_INTERPRETER)-ghciUI _ _ _ _ =        -- DAP Modified-  throwGhcException (CmdLineError "not built for interactive use")-#else-ghciUI st units srcs maybe_expr = do               -- DAP Modified-  hs_srcs <- case NE.nonEmpty units of-    Just ne_units -> do-      initMulti ne_units-    Nothing -> do-      case srcs of-        [] -> return []-        _  -> do-          s <- initMake srcs-          return $ map (uncurry (,Nothing,)) s-  interactiveUI st hs_srcs maybe_expr             -- DAP Modified-#endif----- -------------------------------------------------------------------------------- Option sanity checks---- | Ensure sanity of options.------ Throws 'UsageError' or 'CmdLineError' if not.-checkOptions :: PostLoadMode -> DynFlags -> [(String,Maybe Phase)] -> [String] -> [String] -> IO ()-     -- Final sanity checking before kicking off a compilation (pipeline).-checkOptions mode dflags srcs objs units = do-     -- Complain about any unknown flags-   let unknown_opts = [ f | (f@('-':_), _) <- srcs ]-   when (notNull unknown_opts) (unknownFlagsErr unknown_opts)--   when (not (Set.null (rtsWays (ways dflags)))-         && isInterpretiveMode mode) $-        hPutStrLn stderr ("Warning: -debug, -threaded and -ticky are ignored by GHCi")--        -- -prof and --interactive are not a good combination-   when ((fullWays (ways dflags) /= hostFullWays)-         && isInterpretiveMode mode-         && not (gopt Opt_ExternalInterpreter dflags)) $-      do throwGhcException (UsageError-              "-fexternal-interpreter is required when using --interactive with a non-standard way (-prof, -static, or -dynamic).")-        -- -ohi sanity check-   if (isJust (outputHi dflags) &&-      (isCompManagerMode mode || srcs `lengthExceeds` 1))-        then throwGhcException (UsageError "-ohi can only be used when compiling a single source file")-        else do--   if (isJust (dynOutputHi dflags) &&-      (isCompManagerMode mode || srcs `lengthExceeds` 1))-     then throwGhcException (UsageError "-dynohi can only be used when compiling a single source file")-     else do--        -- -o sanity checking-   if (srcs `lengthExceeds` 1 && isJust (outputFile dflags)-         && not (isLinkMode mode))-        then throwGhcException (UsageError "can't apply -o to multiple source files")-        else do--   let not_linking = not (isLinkMode mode) || isNoLink (ghcLink dflags)--   when (not_linking && not (null objs)) $-        hPutStrLn stderr ("Warning: the following files would be used as linker inputs, but linking is not being done: " ++ unwords objs)--        -- Check that there are some input files-        -- (except in the interactive case)-   if null srcs && (null objs || not_linking) && needsInputsMode mode && null units-        then throwGhcException (UsageError "no input files" )-        else do--   case mode of-      StopBefore StopC | backend dflags /= ViaC-        -> throwGhcException $ UsageError $-           "the option -C is only available with an unregisterised GHC"-      StopBefore StopAs | ghcLink dflags == NoLink-        -> throwGhcException $ UsageError $-           "the options -S and -fno-code are incompatible. Please omit -S"--      _ -> return ()--     -- Verify that output files point somewhere sensible.-   verifyOutputFiles dflags---- Compiler output options---- Called to verify that the output files point somewhere valid.------ The assumption is that the directory portion of these output--- options will have to exist by the time 'verifyOutputFiles'--- is invoked.------ We create the directories for -odir, -hidir, -outputdir etc. ourselves if--- they don't exist, so don't check for those here (#2278).-verifyOutputFiles :: DynFlags -> IO ()-verifyOutputFiles dflags = do-  let ofile = outputFile dflags-  when (isJust ofile) $ do-     let fn = fromJust ofile-     flg <- doesDirNameExist fn-     when (not flg) (nonExistentDir "-o" fn)-  let ohi = outputHi dflags-  when (isJust ohi) $ do-     let hi = fromJust ohi-     flg <- doesDirNameExist hi-     when (not flg) (nonExistentDir "-ohi" hi)- where-   nonExistentDir flg dir =-     throwGhcException (CmdLineError ("error: directory portion of " ++-                             show dir ++ " does not exist (used with " ++-                             show flg ++ " option.)"))---------------------------------------------------------------------------------- GHC modes of operation--type Mode = Either PreStartupMode PostStartupMode-type PostStartupMode = Either PreLoadMode PostLoadMode--data PreStartupMode-  = ShowVersion                          -- ghc -V/--version-  | ShowNumVersion                       -- ghc --numeric-version-  | ShowSupportedExtensions              -- ghc --supported-extensions-  | ShowOptions Bool {- isInteractive -} -- ghc --show-options--showVersionMode, showNumVersionMode, showSupportedExtensionsMode, showOptionsMode :: Mode-showVersionMode             = mkPreStartupMode ShowVersion-showNumVersionMode          = mkPreStartupMode ShowNumVersion-showSupportedExtensionsMode = mkPreStartupMode ShowSupportedExtensions-showOptionsMode             = mkPreStartupMode (ShowOptions False)--mkPreStartupMode :: PreStartupMode -> Mode-mkPreStartupMode = Left--isShowVersionMode :: Mode -> Bool-isShowVersionMode (Left ShowVersion) = True-isShowVersionMode _ = False--isShowNumVersionMode :: Mode -> Bool-isShowNumVersionMode (Left ShowNumVersion) = True-isShowNumVersionMode _ = False--data PreLoadMode-  = ShowGhcUsage                           -- ghc -?-  | ShowGhciUsage                          -- ghci -?-  | ShowInfo                               -- ghc --info-  | PrintWithDynFlags (DynFlags -> String) -- ghc --print-foo--showGhcUsageMode, showGhciUsageMode, showInfoMode :: Mode-showGhcUsageMode = mkPreLoadMode ShowGhcUsage-showGhciUsageMode = mkPreLoadMode ShowGhciUsage-showInfoMode = mkPreLoadMode ShowInfo--printSetting :: String -> Mode-printSetting k = mkPreLoadMode (PrintWithDynFlags f)-    where f dflags = fromMaybe (panic ("Setting not found: " ++ show k))-                   $ lookup k (compilerInfo dflags)--mkPreLoadMode :: PreLoadMode -> Mode-mkPreLoadMode = Right . Left--isShowGhcUsageMode :: Mode -> Bool-isShowGhcUsageMode (Right (Left ShowGhcUsage)) = True-isShowGhcUsageMode _ = False--isShowGhciUsageMode :: Mode -> Bool-isShowGhciUsageMode (Right (Left ShowGhciUsage)) = True-isShowGhciUsageMode _ = False--data PostLoadMode-  = ShowInterface FilePath  -- ghc --show-iface-  | DoMkDependHS            -- ghc -M-  | StopBefore StopPhase    -- ghc -E | -C | -S-                            -- StopBefore StopLn is the default-  | DoMake                  -- ghc --make-  | DoBackpack              -- ghc --backpack foo.bkp-  | DoInteractive           -- ghc --interactive-  | DoEval [String]         -- ghc -e foo -e bar => DoEval ["bar", "foo"]-  | DoRun                   -- ghc --run-  | DoAbiHash               -- ghc --abi-hash-  | ShowPackages            -- ghc --show-packages-  | DoFrontend ModuleName   -- ghc --frontend Plugin.Module--doMkDependHSMode, doMakeMode, doInteractiveMode, doRunMode,-  doAbiHashMode, showUnitsMode :: Mode-doMkDependHSMode = mkPostLoadMode DoMkDependHS-doMakeMode = mkPostLoadMode DoMake-doInteractiveMode = mkPostLoadMode DoInteractive-doRunMode = mkPostLoadMode DoRun-doAbiHashMode = mkPostLoadMode DoAbiHash-showUnitsMode = mkPostLoadMode ShowPackages--showInterfaceMode :: FilePath -> Mode-showInterfaceMode fp = mkPostLoadMode (ShowInterface fp)--stopBeforeMode :: StopPhase -> Mode-stopBeforeMode phase = mkPostLoadMode (StopBefore phase)--doEvalMode :: String -> Mode-doEvalMode str = mkPostLoadMode (DoEval [str])--doFrontendMode :: String -> Mode-doFrontendMode str = mkPostLoadMode (DoFrontend (mkModuleName str))--doBackpackMode :: Mode-doBackpackMode = mkPostLoadMode DoBackpack--mkPostLoadMode :: PostLoadMode -> Mode-mkPostLoadMode = Right . Right--isDoInteractiveMode :: Mode -> Bool-isDoInteractiveMode (Right (Right DoInteractive)) = True-isDoInteractiveMode _ = False--isStopLnMode :: Mode -> Bool-isStopLnMode (Right (Right (StopBefore NoStop))) = True-isStopLnMode _ = False--isDoMakeMode :: Mode -> Bool-isDoMakeMode (Right (Right DoMake)) = True-isDoMakeMode _ = False--isDoEvalMode :: Mode -> Bool-isDoEvalMode (Right (Right (DoEval _))) = True-isDoEvalMode _ = False--#if defined(HAVE_INTERNAL_INTERPRETER)-isInteractiveMode :: PostLoadMode -> Bool-isInteractiveMode DoInteractive = True-isInteractiveMode _             = False-#endif---- isInterpretiveMode: byte-code compiler involved-isInterpretiveMode :: PostLoadMode -> Bool-isInterpretiveMode DoInteractive = True-isInterpretiveMode (DoEval _)    = True-isInterpretiveMode _             = False--needsInputsMode :: PostLoadMode -> Bool-needsInputsMode DoMkDependHS    = True-needsInputsMode (StopBefore _)  = True-needsInputsMode DoMake          = True-needsInputsMode _               = False---- True if we are going to attempt to link in this mode.--- (we might not actually link, depending on the GhcLink flag)-isLinkMode :: PostLoadMode -> Bool-isLinkMode (StopBefore NoStop) = True-isLinkMode DoMake              = True-isLinkMode DoRun               = True-isLinkMode DoInteractive       = True-isLinkMode (DoEval _)          = True-isLinkMode _                   = False--isCompManagerMode :: PostLoadMode -> Bool-isCompManagerMode DoRun         = True-isCompManagerMode DoMake        = True-isCompManagerMode DoInteractive = True-isCompManagerMode (DoEval _)    = True-isCompManagerMode _             = False---- -------------------------------------------------------------------------------- Parsing the mode flag--parseModeFlags :: [Located String]-               -> IO (Mode, [String],-                      [Located String],-                      [Warn])-parseModeFlags args = do-  ((leftover, errs1, warns), (mModeFlag, units, errs2, flags')) <--        processCmdLineP mode_flags (Nothing, [], [], []) args-  let mode = case mModeFlag of-             Nothing     -> doMakeMode-             Just (m, _) -> m--  -- See Note [Handling errors when parsing command-line flags]-  unless (null errs1 && null errs2) $ throwGhcException $ errorsToGhcException $-      map (("on the commandline", )) $ map (unLoc . errMsg) errs1 ++ errs2--  return (mode, units, flags' ++ leftover, warns)--type ModeM = CmdLineP (Maybe (Mode, String), [String], [String], [Located String])-  -- mode flags sometimes give rise to new DynFlags (eg. -C, see below)-  -- so we collect the new ones and return them.--mode_flags :: [Flag ModeM]-mode_flags =-  [  ------- help / version -----------------------------------------------    defFlag "?"                     (PassFlag (setMode showGhcUsageMode))-  , defFlag "-help"                 (PassFlag (setMode showGhcUsageMode))-  , defFlag "V"                     (PassFlag (setMode showVersionMode))-  , defFlag "-version"              (PassFlag (setMode showVersionMode))-  , defFlag "-numeric-version"      (PassFlag (setMode showNumVersionMode))-  , defFlag "-info"                 (PassFlag (setMode showInfoMode))-  , defFlag "-show-options"         (PassFlag (setMode showOptionsMode))-  , defFlag "-supported-languages"  (PassFlag (setMode showSupportedExtensionsMode))-  , defFlag "-supported-extensions" (PassFlag (setMode showSupportedExtensionsMode))-  , defFlag "-show-packages"        (PassFlag (setMode showUnitsMode))-  ] ++-  [ defFlag k'                      (PassFlag (setMode (printSetting k)))-  | k <- ["Project version",-          "Project Git commit id",-          "Booter version",-          "Stage",-          "Build platform",-          "Host platform",-          "Target platform",-          "Have interpreter",-          "Object splitting supported",-          "Have native code generator",-          "Support SMP",-          "Unregisterised",-          "Tables next to code",-          "RTS ways",-          "Leading underscore",-          "Debug on",-          "LibDir",-          "Global Package DB",-          "C compiler flags",-          "C compiler link flags",-          "ld flags"],-    let k' = "-print-" ++ map (replaceSpace . toLower) k-        replaceSpace ' ' = '-'-        replaceSpace c   = c-  ] ++-      ------- interfaces -----------------------------------------------------  [ defFlag "-show-iface"  (HasArg (\f -> setMode (showInterfaceMode f)-                                               "--show-iface"))--      ------- primary modes -------------------------------------------------  , defFlag "c"            (PassFlag (\f -> do setMode (stopBeforeMode NoStop) f-                                               addFlag "-no-link" f))-  , defFlag "M"            (PassFlag (setMode doMkDependHSMode))-  , defFlag "E"            (PassFlag (setMode (stopBeforeMode StopPreprocess )))-  , defFlag "C"            (PassFlag (setMode (stopBeforeMode StopC)))-  , defFlag "S"            (PassFlag (setMode (stopBeforeMode StopAs)))-  , defFlag "-run"         (PassFlag (setMode doRunMode))-  , defFlag "-make"        (PassFlag (setMode doMakeMode))-  , defFlag "unit"         (SepArg   (\s -> addUnit s "-unit"))-  , defFlag "-backpack"    (PassFlag (setMode doBackpackMode))-  , defFlag "-interactive" (PassFlag (setMode doInteractiveMode))-  , defFlag "-abi-hash"    (PassFlag (setMode doAbiHashMode))-  , defFlag "e"            (SepArg   (\s -> setMode (doEvalMode s) "-e"))-  , defFlag "-frontend"    (SepArg   (\s -> setMode (doFrontendMode s) "-frontend"))-  ]--addUnit :: String -> String -> EwM ModeM ()-addUnit unit_str _arg = liftEwM $ do-  (mModeFlag, units, errs, flags') <- getCmdLineState-  putCmdLineState (mModeFlag, unit_str:units, errs, flags')--setMode :: Mode -> String -> EwM ModeM ()-setMode newMode newFlag = liftEwM $ do-    (mModeFlag, units, errs, flags') <- getCmdLineState-    let (modeFlag', errs') =-            case mModeFlag of-            Nothing -> ((newMode, newFlag), errs)-            Just (oldMode, oldFlag) ->-                case (oldMode, newMode) of-                    -- -c/--make are allowed together, and mean --make -no-link-                    _ |  isStopLnMode oldMode && isDoMakeMode newMode-                      || isStopLnMode newMode && isDoMakeMode oldMode ->-                      ((doMakeMode, "--make"), [])--                    -- If we have both --help and --interactive then we-                    -- want showGhciUsage-                    _ | isShowGhcUsageMode oldMode &&-                        isDoInteractiveMode newMode ->-                            ((showGhciUsageMode, oldFlag), [])-                      | isShowGhcUsageMode newMode &&-                        isDoInteractiveMode oldMode ->-                            ((showGhciUsageMode, newFlag), [])--                    -- If we have both -e and --interactive then -e always wins-                    _ | isDoEvalMode oldMode &&-                        isDoInteractiveMode newMode ->-                            ((oldMode, oldFlag), [])-                      | isDoEvalMode newMode &&-                        isDoInteractiveMode oldMode ->-                            ((newMode, newFlag), [])--                    -- Otherwise, --help/--version/--numeric-version always win-                      | isDominantFlag oldMode -> ((oldMode, oldFlag), [])-                      | isDominantFlag newMode -> ((newMode, newFlag), [])-                    -- We need to accumulate eval flags like "-e foo -e bar"-                    (Right (Right (DoEval esOld)),-                     Right (Right (DoEval [eNew]))) ->-                        ((Right (Right (DoEval (eNew : esOld))), oldFlag),-                         errs)-                    -- Saying e.g. --interactive --interactive is OK-                    _ | oldFlag == newFlag -> ((oldMode, oldFlag), errs)--                    -- --interactive and --show-options are used together-                    (Right (Right DoInteractive), Left (ShowOptions _)) ->-                      ((Left (ShowOptions True),-                        "--interactive --show-options"), errs)-                    (Left (ShowOptions _), (Right (Right DoInteractive))) ->-                      ((Left (ShowOptions True),-                        "--show-options --interactive"), errs)-                    -- Otherwise, complain-                    _ -> let err = flagMismatchErr oldFlag newFlag-                         in ((oldMode, oldFlag), err : errs)-    putCmdLineState (Just modeFlag', units, errs', flags')-  where isDominantFlag f = isShowGhcUsageMode   f ||-                           isShowGhciUsageMode  f ||-                           isShowVersionMode    f ||-                           isShowNumVersionMode f--flagMismatchErr :: String -> String -> String-flagMismatchErr oldFlag newFlag-    = "cannot use `" ++ oldFlag ++  "' with `" ++ newFlag ++ "'"--addFlag :: String -> String -> EwM ModeM ()-addFlag s flag = liftEwM $ do-  (m, units, e, flags') <- getCmdLineState-  putCmdLineState (m, units, e, mkGeneralLocated loc s : flags')-    where loc = "addFlag by " ++ flag ++ " on the commandline"---- ------------------------------------------------------------------------------- Run --make mode--doMake :: [String] -> [(String, Maybe Phase)] -> Ghc ()-doMake units targets = do-  hs_srcs <- case NE.nonEmpty units of-    Just ne_units -> do-      initMulti ne_units-    Nothing -> do-      s <- initMake targets-      return $ map (uncurry (,Nothing,)) s-  case hs_srcs of-    [] -> return ()-    _  -> do-      targets' <- mapM (\(src, uid, phase) -> GHC.guessTarget src uid phase) hs_srcs-      GHC.setTargets targets'-      ok_flag <- GHC.load LoadAllTargets-      when (failed ok_flag) (liftIO $ exitWith (ExitFailure 1))--initMake :: [(String,Maybe Phase)] -> Ghc [(String, Maybe Phase)]-initMake srcs  = do-    let (hs_srcs, non_hs_srcs) = partition isHaskellishTarget srcs--    hsc_env <- GHC.getSession--    -- if we have no haskell sources from which to do a dependency-    -- analysis, then just do one-shot compilation and/or linking.-    -- This means that "ghc Foo.o Bar.o -o baz" links the program as-    -- we expect.-    if (null hs_srcs)-       then liftIO (oneShot hsc_env NoStop srcs) >> return []-       else do--    o_files <- mapMaybeM (\x -> liftIO $ compileFile hsc_env NoStop x)-                 non_hs_srcs-    dflags <- GHC.getSessionDynFlags-    let dflags' = dflags { ldInputs = map (FileOption "") o_files-                                      ++ ldInputs dflags }-    _ <- GHC.setSessionDynFlags dflags'-    return hs_srcs---- Strip out any ["+RTS", ..., "-RTS"] sequences in the command string list.-removeRTS :: [String] -> [String]-removeRTS ("+RTS" : xs)  =-  case dropWhile (/= "-RTS") xs of-    [] -> []-    (_ : ys) -> removeRTS ys-removeRTS (y:ys)         = y : removeRTS ys-removeRTS []             = []--initMulti :: NE.NonEmpty String -> Ghc ([(String, Maybe UnitId, Maybe Phase)])-initMulti unitArgsFiles  = do-  hsc_env <- GHC.getSession-  let logger = hsc_logger hsc_env-  initial_dflags <- GHC.getSessionDynFlags--  dynFlagsAndSrcs <- forM unitArgsFiles $ \f -> do-    when (verbosity initial_dflags > 2) (liftIO $ print f)-    args <- liftIO $ expandResponse [f]-    (dflags2, fileish_args, warns) <- parseDynamicFlagsCmdLine initial_dflags (map (mkGeneralLocated f) (removeRTS args))-    handleSourceError (\e -> do-       GHC.printException e-       liftIO $ exitWith (ExitFailure 1)) $ do-         liftIO $ handleFlagWarnings logger (initDiagOpts dflags2) warns--    let (dflags3, srcs, objs) = parseTargetFiles dflags2 (map unLoc fileish_args)-        dflags4 = offsetDynFlags dflags3--    let (hs_srcs, non_hs_srcs) = partition isHaskellishTarget srcs--    -- This is dubious as the whole unit environment won't be set-up correctly, but-    -- that doesn't matter for what we use it for (linking and oneShot)-    let dubious_hsc_env = hscSetFlags dflags4 hsc_env-    -- if we have no haskell sources from which to do a dependency-    -- analysis, then just do one-shot compilation and/or linking.-    -- This means that "ghc Foo.o Bar.o -o baz" links the program as-    -- we expect.-    if (null hs_srcs)-       then liftIO (oneShot dubious_hsc_env NoStop srcs) >> return (dflags4, [])-       else do--    o_files <- mapMaybeM (\x -> liftIO $ compileFile dubious_hsc_env NoStop x)-                 non_hs_srcs-    let dflags5 = dflags4 { ldInputs = map (FileOption "") o_files-                                      ++ ldInputs dflags4 }--    liftIO $ checkOptions DoMake dflags5 srcs objs []--    pure (dflags5, hs_srcs)--  let-    unitDflags = NE.map fst dynFlagsAndSrcs-    srcs = NE.map (\(dflags, lsrcs) -> map (uncurry (,Just $ homeUnitId_ dflags,)) lsrcs) dynFlagsAndSrcs-    (hs_srcs, _non_hs_srcs) = unzip (map (partition (\(file, _uid, phase) -> isHaskellishTarget (file, phase))) (NE.toList srcs))--  checkDuplicateUnits initial_dflags (NE.toList (NE.zip unitArgsFiles unitDflags))--  let (initial_home_graph, mainUnitId) = createUnitEnvFromFlags unitDflags-      home_units = unitEnv_keys initial_home_graph--  home_unit_graph <- forM initial_home_graph $ \homeUnitEnv -> do-    let cached_unit_dbs = homeUnitEnv_unit_dbs homeUnitEnv-        hue_flags = homeUnitEnv_dflags homeUnitEnv-        dflags = homeUnitEnv_dflags homeUnitEnv-    (dbs,unit_state,home_unit,mconstants) <- liftIO $ State.initUnits logger hue_flags cached_unit_dbs home_units--    updated_dflags <- liftIO $ updatePlatformConstants dflags mconstants-    pure $ HomeUnitEnv-      { homeUnitEnv_units = unit_state-      , homeUnitEnv_unit_dbs = Just dbs-      , homeUnitEnv_dflags = updated_dflags-      , homeUnitEnv_hpt = emptyHomePackageTable-      , homeUnitEnv_home_unit = Just home_unit-      }--  checkUnitCycles initial_dflags home_unit_graph--  let dflags = homeUnitEnv_dflags $ unitEnv_lookup mainUnitId home_unit_graph-  unitEnv <- assertUnitEnvInvariant <$> (liftIO $ initUnitEnv mainUnitId home_unit_graph (ghcNameVersion dflags) (targetPlatform dflags))-  let final_hsc_env = hsc_env { hsc_unit_env = unitEnv }--  GHC.setSession final_hsc_env--  -- if we have no haskell sources from which to do a dependency-  -- analysis, then just do one-shot compilation and/or linking.-  -- This means that "ghc Foo.o Bar.o -o baz" links the program as-  -- we expect.-  if (null hs_srcs)-      then do-        liftIO $ hPutStrLn stderr $ "Multi Mode can not be used for one-shot mode."-        liftIO $ exitWith (ExitFailure 1)-      else do--{--  o_files <- liftIO $ mapMaybeM-                (\(src, uid, mphase) ->-                  compileFile (hscSetActiveHomeUnit (ue_unitHomeUnit (fromJust uid) unitEnv) final_hsc_env) NoStop (src, mphase)-                )-                (concat non_hs_srcs)-                -}--  -- MP: This should probably modify dflags for each unit?-  --let dflags' = dflags { ldInputs = map (FileOption "") o_files-  --                                  ++ ldInputs dflags }-  return $ concat hs_srcs---- | Check that we don't have multiple units with the same UnitId.--checkUnitCycles :: DynFlags -> UnitEnvGraph HomeUnitEnv -> Ghc ()-checkUnitCycles dflags graph = processSCCs sccs-  where-    mkNode :: (UnitId, HomeUnitEnv) -> Node UnitId UnitId-    mkNode (uid, hue) = DigraphNode uid uid (homeUnitDepends (homeUnitEnv_units hue))-    nodes = map mkNode (unitEnv_elts graph)--    sccs = stronglyConnCompFromEdgedVerticesOrd nodes--    processSCCs [] = return ()-    processSCCs (AcyclicSCC _: other_sccs) = processSCCs other_sccs-    processSCCs (CyclicSCC uids: _) = throwGhcException $ CmdLineError $ showSDoc dflags (cycle_err uids)---    cycle_err uids =-      hang (text "Units form a dependency cycle:")-           2-           (one_err uids)--    one_err uids = vcat $-                    (map (\uid -> text "-" <+> ppr uid <+> text "depends on") start)-                    ++ [text "-" <+> ppr final]-      where-        start = init uids-        final = last uids--checkDuplicateUnits :: DynFlags -> [(FilePath, DynFlags)] -> Ghc ()-checkDuplicateUnits dflags flags =-  unless (null duplicate_ids)-         (throwGhcException $ CmdLineError $ showSDoc dflags multi_err)--  where-    uids = map (second homeUnitId_) flags-    deduplicated_uids = ordNubOn snd uids-    duplicate_ids = Set.fromList (map snd uids \\ map snd deduplicated_uids)--    duplicate_flags = filter (flip Set.member duplicate_ids . snd) uids--    one_err (fp, home_uid) = text "-" <+> ppr home_uid <+> text "defined in" <+> text fp--    multi_err =-      hang (text "Multiple units with the same unit-id:")-           2-           (vcat (map one_err duplicate_flags))---offsetDynFlags :: DynFlags -> DynFlags-offsetDynFlags dflags =-  dflags { hiDir = c hiDir-         , objectDir  = c objectDir-         , stubDir = c stubDir-         , hieDir  = c hieDir-         , dumpDir = c dumpDir  }--  where-    c f = augment_maybe (f dflags)--    augment_maybe Nothing = Nothing-    augment_maybe (Just f) = Just (augment f)-    augment f | isRelative f, Just offset <- workingDirectory dflags = offset </> f-              | otherwise = f---createUnitEnvFromFlags :: NE.NonEmpty DynFlags -> (HomeUnitGraph, UnitId)-createUnitEnvFromFlags unitDflags =-  let-    newInternalUnitEnv dflags = mkHomeUnitEnv dflags emptyHomePackageTable Nothing-    unitEnvList = NE.map (\dflags -> (homeUnitId_ dflags, newInternalUnitEnv dflags)) unitDflags-    activeUnit = fst $ NE.head unitEnvList-  in-    (unitEnv_new (Map.fromList (NE.toList (unitEnvList))), activeUnit)---- ------------------------------------------------------------------------------ Various banners and verbosity output.--showBanner :: PostLoadMode -> DynFlags -> IO ()-showBanner _postLoadMode dflags = do-   let verb = verbosity dflags--#if defined(HAVE_INTERNAL_INTERPRETER)-   -- Show the GHCi banner-   when (isInteractiveMode _postLoadMode && verb >= 1) $ putStrLn ghciWelcomeMsg-#endif--   -- Display details of the configuration in verbose mode-   when (verb >= 2) $-    do hPutStr stderr "Glasgow Haskell Compiler, Version "-       hPutStr stderr cProjectVersion-       hPutStr stderr ", stage "-       hPutStr stderr cStage-       hPutStr stderr " booted by GHC version "-       hPutStrLn stderr cBooterVersion---- We print out a Read-friendly string, but a prettier one than the--- Show instance gives us-showInfo :: DynFlags -> IO ()-showInfo dflags = do-        let sq x = " [" ++ x ++ "\n ]"-        putStrLn $ sq $ intercalate "\n ," $ map show $ compilerInfo dflags---- TODO use GHC.Utils.Error once that is disentangled from all the other GhcMonad stuff?-showSupportedExtensions :: Maybe String -> IO ()-showSupportedExtensions m_top_dir = do-  res <- runExceptT $ do-    top_dir <- lift (tryFindTopDir m_top_dir) >>= \case-      Nothing -> throwE $ SettingsError_MissingData "Could not find the top directory, missing -B flag"-      Just dir -> pure dir-    initSettings top_dir-  arch_os <- case res of-    Right s -> pure $ platformArchOS $ sTargetPlatform s-    Left (SettingsError_MissingData msg) -> do-      hPutStrLn stderr $ "WARNING: " ++ show msg-      hPutStrLn stderr $ "cannot know target platform so guessing target == host (native compiler)."-      pure hostPlatformArchOS-    Left (SettingsError_BadData msg) -> do-      hPutStrLn stderr msg-      exitWith $ ExitFailure 1-  mapM_ putStrLn $ supportedLanguagesAndExtensions arch_os--showVersion :: IO ()-showVersion = putStrLn (cProjectName ++ ", version " ++ cProjectVersion)--showOptions :: Bool -> IO ()-showOptions isInteractive = putStr (unlines availableOptions)-    where-      availableOptions = concat [-        flagsForCompletion isInteractive,-        map ('-':) (getFlagNames mode_flags)-        ]-      getFlagNames opts         = map flagName opts--showGhcUsage :: DynFlags -> IO ()-showGhcUsage = showUsage False--showGhciUsage :: DynFlags -> IO ()-showGhciUsage = showUsage True--showUsage :: Bool -> DynFlags -> IO ()-showUsage ghci dflags = do-  let usage_path = if ghci then ghciUsagePath dflags-                           else ghcUsagePath dflags-  usage <- readFile usage_path-  progName <- getProgName-  dump progName usage-  where-    dump progName xs = case xs of-      ""        -> return ()-      '$':'$':s -> putStr progName >> dump progName s-      c:s       -> putChar c >> dump progName s--dumpFinalStats :: Logger -> IO ()-dumpFinalStats logger = do-  when (logHasDumpFlag logger Opt_D_faststring_stats) $ dumpFastStringStats logger--  when (logHasDumpFlag logger Opt_D_dump_faststrings) $ do-    fss <- getFastStringTable-    let ppr_table         = fmap ppr_segment (fss `zip` [0..])-        ppr_segment (s,n) = hang (text "Segment" <+> int n) 2 (vcat (fmap ppr_bucket (s `zip` [0..])))-        ppr_bucket  (b,n) = hang (text "Bucket" <+> int n) 2 (vcat (fmap ftext b))-    putDumpFileMaybe logger Opt_D_dump_faststrings "FastStrings" FormatText (vcat ppr_table)--dumpFastStringStats :: Logger -> IO ()-dumpFastStringStats logger = do-  segments <- getFastStringTable-  hasZ <- getFastStringZEncCounter-  let buckets = concat segments-      bucketsPerSegment = map length segments-      entriesPerBucket = map length buckets-      entries = sum entriesPerBucket-      msg = text "FastString stats:" $$ nest 4 (vcat-        [ text "segments:         " <+> int (length segments)-        , text "buckets:          " <+> int (sum bucketsPerSegment)-        , text "entries:          " <+> int entries-        , text "largest segment:  " <+> int (maximum bucketsPerSegment)-        , text "smallest segment: " <+> int (minimum bucketsPerSegment)-        , text "longest bucket:   " <+> int (maximum entriesPerBucket)-        , text "has z-encoding:   " <+> (hasZ `pcntOf` entries)-        ])-        -- we usually get more "has z-encoding" than "z-encoded", because-        -- when we z-encode a string it might hash to the exact same string,-        -- which is not counted as "z-encoded".  Only strings whose-        -- Z-encoding is different from the original string are counted in-        -- the "z-encoded" total.-  putMsg logger msg-  where-   x `pcntOf` y = int ((x * 100) `quot` y) Outputable.<> char '%'--showUnits, dumpUnits, dumpUnitsSimple :: HscEnv -> IO ()-showUnits       hsc_env = putStrLn (showSDoc (hsc_dflags hsc_env) (pprUnits (hsc_units hsc_env)))-dumpUnits       hsc_env = putMsg (hsc_logger hsc_env) (pprUnits (hsc_units hsc_env))-dumpUnitsSimple hsc_env = putMsg (hsc_logger hsc_env) (pprUnitsSimple (hsc_units hsc_env))---- -------------------------------------------------------------------------------- Frontend plugin support--doFrontend :: ModuleName -> [(String, Maybe Phase)] -> Ghc ()-doFrontend modname srcs = do-    hsc_env <- getSession-    (frontend_plugin, _pkgs, _deps) <- liftIO $ loadFrontendPlugin hsc_env modname -- TODO do these need to recorded?-    frontend frontend_plugin-      (reverse $ frontendPluginOpts (hsc_dflags hsc_env)) srcs---- -------------------------------------------------------------------------------- ABI hash support--{--        ghc --abi-hash Data.Foo System.Bar--Generates a combined hash of the ABI for modules Data.Foo and-System.Bar.  The modules must already be compiled, and appropriate -i-options may be necessary in order to find the .hi files.--This is used by Cabal for generating the ComponentId for a-package.  The ComponentId must change when the visible ABI of-the package changes, so during registration Cabal calls ghc --abi-hash-to get a hash of the package's ABI.--}---- | Print ABI hash of input modules.------ The resulting hash is the MD5 of the GHC version used (#5328,--- see 'hiVersion') and of the existing ABI hash from each module (see--- 'mi_mod_hash').-abiHash :: [String] -- ^ List of module names-        -> Ghc ()-abiHash strs = do-  hsc_env <- getSession-  let dflags    = hsc_dflags hsc_env--  liftIO $ do--  let find_it str = do-         let modname = mkModuleName str-         r <- findImportedModule hsc_env modname NoPkgQual-         case r of-           Found _ m -> return m-           _error    -> throwGhcException $ CmdLineError $ showSDoc dflags $-                          cannotFindModule hsc_env modname r--  mods <- mapM find_it strs--  let get_iface modl = loadUserInterface NotBoot (text "abiHash") modl-  ifaces <- initIfaceCheck (text "abiHash") hsc_env $ mapM get_iface mods--  bh <- openBinMem (3*1024) -- just less than a block-  put_ bh hiVersion-    -- package hashes change when the compiler version changes (for now)-    -- see #5328-  mapM_ (put_ bh . mi_mod_hash . mi_final_exts) ifaces-  f <- fingerprintBinMem bh--  putStrLn (showPpr dflags f)---- -------------------------------------------------------------------------------- Util--unknownFlagsErr :: [String] -> a-unknownFlagsErr fs = throwGhcException $ UsageError $ concatMap oneError fs-  where-    oneError f =-        "unrecognised flag: " ++ f ++ "\n" ++-        (case match f (nubSort allNonDeprecatedFlags) of-            [] -> ""-            suggs -> "did you mean one of:\n" ++ unlines (map ("  " ++) suggs))-    -- fixes #11789-    -- If the flag contains '=',-    -- this uses both the whole and the left side of '=' for comparing.-    match f allFlags-        | elem '=' f =-              let (flagsWithEq, flagsWithoutEq) = partition (elem '=') allFlags-                  fName = takeWhile (/= '=') f-              in (fuzzyMatch f flagsWithEq) ++ (fuzzyMatch fName flagsWithoutEq)-        | otherwise = fuzzyMatch f allFlags
− app-ghc-9.4/GHCi/GhcApiCompat.hs
@@ -1,78 +0,0 @@-module GHCi.GhcApiCompat (-    module GHC.Runtime.Heap.Inspect-  , module GHC.Unit-  , module GHC.Driver.Monad-  , module GHC.Unit.Module-  , module GHC.Utils.Outputable-  , module GHC.Utils.Exception-  , module GHC.Runtime.Debugger-  , module GHC.Data.FastString-  , module GHC.Runtime.Eval.Types-  , module GHC.Core.DataCon-  , module GHC.Types.TyThing.Ppr-  , module GHC.Driver.Session-  , module GHC.Types.Name.Reader-  , module GHC.Types.SourceError-  , module GHC.Driver.Ppr-  , module GHC.Types.TyThing-  , module GHC.Unit.Module.ModSummary-  , module GHC.Driver.Env.Types-  , module GHC.Runtime.Context-  , module GHC.Types.BreakInfo-  , module GHC.Types.FieldLabel-  , CMC.catch-  , pprTypeForUser-  , ic_rn_gbl_env-  , parseName-  , fls2fs-) where--import GHC.Runtime.Heap.Inspect-import GHC.Unit-import GHC.Driver.Monad-import GHC.Unit.Module-import GHC.Utils.Outputable-import GHC.Utils.Exception hiding (catch)-import GHC.Runtime.Debugger-import GHC.Data.FastString-import GHC.Runtime.Eval.Types-import GHC.Core.DataCon-import GHC.Types.TyThing.Ppr-import GHC.Driver.Session-import GHC.Types.Name.Reader-import GHC.Types.SourceError-import GHC.Driver.Ppr-import GHC.Types.TyThing-import GHC.Unit.Module.ModSummary-import GHC.Driver.Env.Types-import GHC.Runtime.Context-import GHC.Types.BreakInfo-import GHC.Core.TyCo.Ppr-import GHC.Core.Type-import GHC.Types.FieldLabel-import qualified Control.Monad.Catch as CMC-import qualified GHC as G---- |-------pprTypeForUser :: Type -> SDoc-pprTypeForUser = pprSigmaType---- |-------ic_rn_gbl_env :: InteractiveContext -> GlobalRdrEnv-ic_rn_gbl_env = igre_env . ic_gre_cache---- |-------parseName :: GhcMonad m => String -> m [G.Name]-parseName = G.parseName---- |-------fls2fs :: FieldLabelString -> FastString-fls2fs = id
− app-ghc-9.4/GHCi/Leak.hs
@@ -1,80 +0,0 @@-{-# LANGUAGE RecordWildCards, LambdaCase #-}-module GHCi.Leak-  ( LeakIndicators-  , getLeakIndicators-  , checkLeakIndicators-  ) where--import Control.Monad-import Data.Bits-import Foreign.Ptr (ptrToIntPtr, intPtrToPtr)-import GHC-import GHC.Ptr (Ptr (..))-import GHCi.Util-import GHC.Driver.Env-import GHC.Driver.Ppr-import GHC.Utils.Outputable-import GHC.Unit.Module.ModDetails-import GHC.Unit.Home.ModInfo-import GHC.Platform (target32Bit)-import GHC.Linker.Types-import Prelude-import System.Mem-import System.Mem.Weak-import GHC.Types.Unique.DFM---- Checking for space leaks in GHCi. See #15111, and the--- -fghci-leak-check flag.--data LeakIndicators = LeakIndicators [LeakModIndicators]--data LeakModIndicators = LeakModIndicators-  { leakMod :: Weak HomeModInfo-  , leakIface :: Weak ModIface-  , leakDetails :: Weak ModDetails-  , leakLinkable :: Maybe (Weak Linkable)-  }---- | Grab weak references to some of the data structures representing--- the currently loaded modules.-getLeakIndicators :: HscEnv -> IO LeakIndicators-getLeakIndicators hsc_env =-  fmap LeakIndicators $-    forM (eltsUDFM (hsc_HPT hsc_env)) $ \hmi@HomeModInfo{..} -> do-      leakMod <- mkWeakPtr hmi Nothing-      leakIface <- mkWeakPtr hm_iface Nothing-      leakDetails <- mkWeakPtr hm_details Nothing-      leakLinkable <- mapM (`mkWeakPtr` Nothing) hm_linkable-      return $ LeakModIndicators{..}---- | Look at the LeakIndicators collected by an earlier call to--- `getLeakIndicators`, and print messasges if any of them are still--- alive.-checkLeakIndicators :: DynFlags -> LeakIndicators -> IO ()-checkLeakIndicators dflags (LeakIndicators leakmods)  = do-  performGC-  forM_ leakmods $ \LeakModIndicators{..} -> do-    deRefWeak leakMod >>= \case-      Nothing -> return ()-      Just hmi ->-        report ("HomeModInfo for " ++-          showSDoc dflags (ppr (mi_module (hm_iface hmi)))) (Just hmi)-    deRefWeak leakIface >>= \case-      Nothing -> return ()-      Just miface -> report ("ModIface:" ++ moduleNameString (moduleName (mi_module miface))) (Just miface)-    deRefWeak leakDetails >>= report "ModDetails"-    forM_ leakLinkable $ \l -> deRefWeak l >>= report "Linkable"- where-  report :: String -> Maybe a -> IO ()-  report _ Nothing = return ()-  report msg (Just a) = do-    addr <- anyToPtr a-    putStrLn ("-fghci-leak-check: " ++ msg ++ " is still alive at " ++-              show (maskTagBits addr))--  tagBits-    | target32Bit (targetPlatform dflags) = 2-    | otherwise = 3--  maskTagBits :: Ptr a -> Ptr a-  maskTagBits p = intPtrToPtr (ptrToIntPtr p .&. complement (shiftL 1 tagBits - 1))
− app-ghc-9.4/GHCi/UI.hs
@@ -1,4759 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE NondecreasingIndentation #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE TypeFamilies #-}--{-# OPTIONS -fno-warn-name-shadowing #-}--- This module does a lot of it------------------------------------------------------------------------------------- GHC Interactive User Interface------ (c) The GHC Team 2005-2006-----------------------------------------------------------------------------------module GHCi.UI (-        interactiveUI,-        GhciSettings(..),-        defaultGhciSettings,-        ghciCommands,-        ghciWelcomeMsg,-        -- DAP add.-        getLoadedModules,-        breakCmd,-        deleteCmd,-        backCmd,-        forwardCmd,-        historyCmd,-        traceCmd,-        stepCmd,-        stepLocalCmd,-        runStmt,-        toBreakIdAndLocation,-        forceCmd,-        setContext,-        keepGoing-    ) where---- GHCi-import qualified GHCi.UI.Monad as GhciMonad ( args, runStmt, runDecls' )-import GHCi.UI.Monad hiding ( args, runStmt )-import GHCi.UI.Tags-import GHCi.UI.Info-import GHC.Runtime.Debugger---- The GHC interface-import GHC.Runtime.Interpreter-import GHCi.RemoteTypes-import GHCi.BreakArray( breakOn, breakOff )-import GHC.ByteCode.Types-import GHC.Core.DataCon-import GHC.Core.ConLike-import GHC.Core.PatSyn-import GHC.Driver.Errors-import GHC.Driver.Phases-import GHC.Driver.Session as DynFlags-import GHC.Driver.Ppr hiding (printForUser)-import GHC.Utils.Error hiding (traceCmd)-import GHC.Driver.Monad ( modifySession )-import GHC.Driver.Make ( newIfaceCache, ModIfaceCache(..) )-import GHC.Driver.Config.Parser (initParserOpts)-import GHC.Driver.Config.Diagnostic-import qualified GHC-import GHC ( LoadHowMuch(..), Target(..),  TargetId(..),-             Resume, SingleStep, Ghc,-             GetDocsFailure(..), putLogMsgM, pushLogHookM,-             getModuleGraph, handleSourceError, ms_mod )-import GHC.Driver.Main (hscParseModuleWithLocation, hscParseStmtWithLocation)-import GHC.Hs.ImpExp-import GHC.Hs-import GHC.Driver.Env-import GHC.Runtime.Context-import GHC.Types.TyThing-import GHC.Types.TyThing.Ppr-import GHC.Core.TyCo.Ppr-import GHC.Types.SafeHaskell ( getSafeMode )-import GHC.Types.SourceError ( SourceError )-import GHC.Types.Name-import GHC.Types.Var ( varType )-import GHC.Iface.Syntax ( showToHeader )-import GHC.Builtin.Names-import GHC.Builtin.Types( stringTyCon_RDR )-import GHC.Types.Name.Reader as RdrName ( getGRE_NameQualifier_maybes, getRdrName )-import GHC.Types.SrcLoc as SrcLoc-import qualified GHC.Parser.Lexer as Lexer-import GHC.Parser.Header ( toArgs )-import GHC.Types.PkgQual--import GHC.Unit-import GHC.Unit.Finder as Finder-import GHC.Unit.Module.Graph (filterToposortToModules)-import GHC.Unit.Module.ModSummary--import GHC.Data.StringBuffer-import GHC.Utils.Outputable-import GHC.Utils.Logger---- Other random utilities-import GHC.Types.Basic hiding ( isTopLevel )-import GHC.Settings.Config-import GHC.Data.Graph.Directed-import GHC.Utils.Encoding-import GHC.Data.FastString-import qualified GHC.Linker.Loader as Loader-import GHC.Data.Maybe ( orElse, expectJust )-import GHC.Types.Name.Set-import GHC.Utils.Panic hiding ( showException, try )-import GHC.Utils.Panic.Plain-import GHC.Utils.Misc-import qualified GHC.LanguageExtensions as LangExt-import GHC.Data.Bag (unitBag)-import qualified GHC.Data.Strict as Strict---- Haskell Libraries-import System.Console.Haskeline as Haskeline--import Control.Applicative hiding (empty)-import Control.DeepSeq (deepseq)-import Control.Monad as Monad-import Control.Monad.Catch as MC-import Control.Monad.IO.Class-import Control.Monad.Trans.Class-import Control.Monad.Trans.Except--import Data.Array-import qualified Data.ByteString.Char8 as BS-import Data.Char-import Data.Function-import Data.IORef ( IORef, modifyIORef, newIORef, readIORef, writeIORef )-import Data.List ( elemIndices, find, group, intercalate, intersperse,-                   isPrefixOf, isSuffixOf, nub, partition, sort, sortBy, (\\) )-import qualified Data.Set as S-import Data.Maybe-import qualified Data.Map as M-import Data.IntMap.Strict (IntMap)-import qualified Data.IntMap.Strict as IntMap-import Data.Time.LocalTime ( getZonedTime )-import Data.Time.Format ( formatTime, defaultTimeLocale )-import Data.Version ( showVersion )-import Prelude hiding ((<>))--import GHC.Utils.Exception as Exception hiding (catch, mask, handle)-import Foreign hiding (void)-import GHC.Stack hiding (SrcLoc(..))-import GHC.Unit.Env-import GHC.Unit.Home.ModInfo--import System.Directory-import System.Environment-import System.Exit ( exitWith, ExitCode(..) )-import System.FilePath-import System.Info-import System.IO-import System.IO.Error-import System.IO.Unsafe ( unsafePerformIO )-import System.Process-import Text.Printf-import Text.Read ( readMaybe )-import Text.Read.Lex (isSymbolChar)--import Unsafe.Coerce--#if !defined(mingw32_HOST_OS)-import System.Posix hiding ( getEnv )-#else-import qualified System.Win32-#endif--import GHC.IO.Exception ( IOErrorType(InvalidArgument) )-import GHC.IO.Handle ( hFlushAll )-import GHC.TopHandler ( topHandler )--import GHCi.Leak-import qualified GHC.Unit.Module.Graph as GHC----------------------------------------------------------------------------------- DAP--------------------------------------------------------------------------------import qualified GHCi.DAP.Type as DAP-import Control.Concurrent---------------------------------------------------------------------------------data GhciSettings = GhciSettings {-        availableCommands :: [Command],-        shortHelpText     :: String,-        fullHelpText      :: String,-        defPrompt         :: PromptFunction,-        defPromptCont     :: PromptFunction,-        dapContextGhciSettings :: DAP.MVarDAPContext-    }--defaultGhciSettings :: DAP.MVarDAPContext -> GhciSettings-defaultGhciSettings dapCtx =-    GhciSettings {-        availableCommands = ghciCommands,-        shortHelpText     = defShortHelpText,-        defPrompt         = default_prompt,-        defPromptCont     = default_prompt_cont,-        fullHelpText      = defFullHelpText,-        dapContextGhciSettings = dapCtx-    }--ghciWelcomeMsg :: String-ghciWelcomeMsg = "GHCi, version " ++ cProjectVersion ++-                 ": https://www.haskell.org/ghc/  :? for help"--ghciCommands :: [Command]-ghciCommands = map mkCmd [-  -- Hugs users are accustomed to :e, so make sure it doesn't overlap-  ("?",         keepGoing help,                 noCompletion),-  ("add",       keepGoingPaths addModule,       completeFilename),-  ("abandon",   keepGoing abandonCmd,           noCompletion),-  ("break",     keepGoing breakCmd,             completeBreakpoint),-  ("back",      keepGoing backCmd,              noCompletion),-  ("browse",    keepGoing' (browseCmd False),   completeModule),-  ("browse!",   keepGoing' (browseCmd True),    completeModule),-  ("cd",        keepGoingMulti' changeDirectory,     completeFilename),-  ("check",     keepGoing' checkModule,         completeHomeModule),-  ("continue",  keepGoing continueCmd,          noCompletion),-  ("cmd",       keepGoing cmdCmd,               completeExpression),-  ("ctags",     keepGoing createCTagsWithLineNumbersCmd, completeFilename),-  ("ctags!",    keepGoing createCTagsWithRegExesCmd, completeFilename),-  ("def",       keepGoing (defineMacro False),  completeExpression),-  ("def!",      keepGoing (defineMacro True),   completeExpression),-  ("delete",    keepGoing deleteCmd,            noCompletion),-  ("disable",   keepGoing disableCmd,           noCompletion),-  ("doc",       keepGoing' docCmd,              completeIdentifier),-  ("edit",      keepGoingMulti' editFile,            completeFilename),-  ("enable",    keepGoing enableCmd,            noCompletion),-  ("etags",     keepGoing createETagsFileCmd,   completeFilename),-  ("force",     keepGoing forceCmd,             completeExpression),-  ("forward",   keepGoing forwardCmd,           noCompletion),-  ("help",      keepGoingMulti help,                 noCompletion),-  ("history",   keepGoingMulti historyCmd,           noCompletion),-  ("info",      keepGoingMulti' (info False),        completeIdentifier),-  ("info!",     keepGoingMulti' (info True),         completeIdentifier),-  ("issafe",    keepGoing' isSafeCmd,           completeModule),-  ("ignore",    keepGoing ignoreCmd,            noCompletion),-  ("kind",      keepGoingMulti' (kindOfType False),  completeIdentifier),-  ("kind!",     keepGoingMulti' (kindOfType True),   completeIdentifier),-  ("load",      keepGoingPaths loadModule_,     completeHomeModuleOrFile),-  ("load!",     keepGoingPaths loadModuleDefer, completeHomeModuleOrFile),-  ("list",      keepGoing' listCmd,             noCompletion),-  ("module",    keepGoing moduleCmd,            completeSetModule),-  ("main",      keepGoing runMain,              completeFilename),-  ("print",     keepGoing printCmd,             completeExpression),-  ("quit",      quit,                           noCompletion),-  ("reload",    keepGoingMulti' reloadModule,   noCompletion),-  ("reload!",   keepGoingMulti' reloadModuleDefer,   noCompletion),-  ("run",       keepGoing runRun,               completeFilename),-  ("script",    keepGoing' scriptCmd,           completeFilename),-  ("set",       keepGoingMulti setCmd,          completeSetOptions),-  ("seti",      keepGoingMulti setiCmd,         completeSeti),-  ("show",      keepGoingMulti' showCmd,        completeShowOptions),-  ("showi",     keepGoing showiCmd,             completeShowiOptions),-  ("sprint",    keepGoing sprintCmd,            completeExpression),-  ("step",      keepGoing stepCmd,              completeIdentifier),-  ("steplocal", keepGoing stepLocalCmd,         completeIdentifier),-  ("stepmodule",keepGoing stepModuleCmd,        completeIdentifier),-  ("type",      keepGoingMulti' typeOfExpr,          completeExpression),-  ("trace",     keepGoing traceCmd,             completeExpression),-  ("unadd",     keepGoingPaths unAddModule,     completeFilename),-  ("undef",     keepGoing undefineMacro,        completeMacro),-  ("unset",     keepGoing unsetOptions,         completeSetOptions),-  ("where",     keepGoing whereCmd,             noCompletion),-  ("instances", keepGoing' instancesCmd,        completeExpression)-  ] ++ map mkCmdHidden [ -- hidden commands-  ("all-types", keepGoing' allTypesCmd),-  ("complete",  keepGoing completeCmd),-  ("loc-at",    keepGoing' locAtCmd),-  ("type-at",   keepGoing' typeAtCmd),-  ("uses",      keepGoing' usesCmd)-  ]- where-  mkCmd (n,a,c) = Command { cmdName = n-                          , cmdAction = a-                          , cmdHidden = False-                          , cmdCompletionFunc = c-                          }--  mkCmdHidden (n,a) = Command { cmdName = n-                              , cmdAction = a-                              , cmdHidden = True-                              , cmdCompletionFunc = noCompletion-                              }---- We initialize readline (in the interactiveUI function) to use--- word_break_chars as the default set of completion word break characters.--- This can be overridden for a particular command (for example, filename--- expansion shouldn't consider '/' to be a word break) by setting the third--- entry in the Command tuple above.------ NOTE: in order for us to override the default correctly, any custom entry--- must be a SUBSET of word_break_chars.-word_break_chars :: String-word_break_chars = spaces ++ specials ++ symbols--word_break_chars_pred :: Char -> Bool-word_break_chars_pred '.' = False-word_break_chars_pred c = c `elem` (spaces ++ specials) || isSymbolChar c--symbols, specials, spaces :: String-symbols = "!#$%&*+/<=>?@\\^|-~"-specials = "(),;[]`{}"-spaces = " \t\n"--flagWordBreakChars :: String-flagWordBreakChars = " \t\n"---keepGoing :: (String -> GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)-keepGoing a str = keepGoing' (lift . a) str--keepGoingMulti :: (String -> GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)-keepGoingMulti a str = keepGoingMulti' (lift . a) str--keepGoing' :: GhciMonad m => (a -> m ()) -> a -> m CmdExecOutcome-keepGoing' a str = do-  in_multi <- inMultiMode-  if in_multi-    then-      liftIO $ hPutStrLn stderr "Command is not supported (yet) in multi-mode"-    else-      a str-  return CmdSuccess---- For commands which are actually support in multi-mode, initially just :reload-keepGoingMulti' :: GhciMonad m => (String -> m ()) -> String -> m CmdExecOutcome-keepGoingMulti' a str = a str >> return CmdSuccess--inMultiMode :: GhciMonad m => m Bool-inMultiMode = multiMode <$> getGHCiState--keepGoingPaths :: ([FilePath] -> InputT GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)-keepGoingPaths a str- = do case toArgsNoLoc str of-          Left err -> liftIO $ hPutStrLn stderr err >> return CmdSuccess-          Right args -> keepGoing' a args--defShortHelpText :: String-defShortHelpText = "use :? for help.\n"--defFullHelpText :: String-defFullHelpText =-  " Commands available from the prompt:\n" ++-  "\n" ++-  "   <statement>                 evaluate/run <statement>\n" ++-  "   :                           repeat last command\n" ++-  "   :{\\n ..lines.. \\n:}\\n       multiline command\n" ++-  "   :add [*]<module> ...        add module(s) to the current target set\n" ++-  "   :browse[!] [[*]<mod>]       display the names defined by module <mod>\n" ++-  "                               (!: more details; *: all top-level names)\n" ++-  "   :cd <dir>                   change directory to <dir>\n" ++-  "   :cmd <expr>                 run the commands returned by <expr>::IO String\n" ++-  "   :complete <dom> [<rng>] <s> list completions for partial input string\n" ++-  "   :ctags[!] [<file>]          create tags file <file> for Vi (default: \"tags\")\n" ++-  "                               (!: use regex instead of line number)\n" ++-  "   :def[!] <cmd> <expr>        define command :<cmd> (later defined command has\n" ++-  "                               precedence, ::<cmd> is always a builtin command)\n" ++-  "                               (!: redefine an existing command name)\n" ++-  "   :doc <name>                 display docs for the given name (experimental)\n" ++-  "   :edit <file>                edit file\n" ++-  "   :edit                       edit last module\n" ++-  "   :etags [<file>]             create tags file <file> for Emacs (default: \"TAGS\")\n" ++-  "   :help, :?                   display this list of commands\n" ++-  "   :info[!] [<name> ...]       display information about the given names\n" ++-  "                               (!: do not filter instances)\n" ++-  "   :instances <type>           display the class instances available for <type>\n" ++-  "   :issafe [<mod>]             display safe haskell information of module <mod>\n" ++-  "   :kind[!] <type>             show the kind of <type>\n" ++-  "                               (!: also print the normalised type)\n" ++-  "   :load[!] [*]<module> ...    load module(s) and their dependents\n" ++-  "                               (!: defer type errors)\n" ++-  "   :main [<arguments> ...]     run the main function with the given arguments\n" ++-  "   :module [+/-] [*]<mod> ...  set the context for expression evaluation\n" ++-  "   :quit                       exit GHCi\n" ++-  "   :reload[!]                  reload the current module set\n" ++-  "                               (!: defer type errors)\n" ++-  "   :run function [<arguments> ...] run the function with the given arguments\n" ++-  "   :script <file>              run the script <file>\n" ++-  "   :type <expr>                show the type of <expr>\n" ++-  "   :type +d <expr>             show the type of <expr>, defaulting type variables\n" ++-  "   :unadd <module> ...         remove module(s) from the current target set\n" ++-  "   :undef <cmd>                undefine user-defined command :<cmd>\n" ++-  "   ::<cmd>                     run the builtin command\n" ++-  "   :!<command>                 run the shell command <command>\n" ++-  "\n" ++-  " -- Commands for debugging:\n" ++-  "\n" ++-  "   :abandon                    at a breakpoint, abandon current computation\n" ++-  "   :back [<n>]                 go back in the history N steps (after :trace)\n" ++-  "   :break [<mod>] <l> [<col>]  set a breakpoint at the specified location\n" ++-  "   :break <name>               set a breakpoint on the specified function\n" ++-  "   :continue [<count>]         resume after a breakpoint [and set break ignore count]\n" ++-  "   :delete <number> ...        delete the specified breakpoints\n" ++-  "   :delete *                   delete all breakpoints\n" ++-  "   :disable <number> ...       disable the specified breakpoints\n" ++-  "   :disable *                  disable all breakpoints\n" ++-  "   :enable <number> ...        enable the specified breakpoints\n" ++-  "   :enable *                   enable all breakpoints\n" ++-  "   :force <expr>               print <expr>, forcing unevaluated parts\n" ++-  "   :forward [<n>]              go forward in the history N step s(after :back)\n" ++-  "   :history [<n>]              after :trace, show the execution history\n" ++-  "   :ignore <breaknum> <count>  for break <breaknum> set break ignore <count>\n" ++-  "   :list                       show the source code around current breakpoint\n" ++-  "   :list <identifier>          show the source code for <identifier>\n" ++-  "   :list [<module>] <line>     show the source code around line number <line>\n" ++-  "   :print [<name> ...]         show a value without forcing its computation\n" ++-  "   :sprint [<name> ...]        simplified version of :print\n" ++-  "   :step                       single-step after stopping at a breakpoint\n"++-  "   :step <expr>                single-step into <expr>\n"++-  "   :steplocal                  single-step within the current top-level binding\n"++-  "   :stepmodule                 single-step restricted to the current module\n"++-  "   :trace                      trace after stopping at a breakpoint\n"++-  "   :trace <expr>               evaluate <expr> with tracing on (see :history)\n"++--  "\n" ++-  " -- Commands for changing settings:\n" ++-  "\n" ++-  "   :set <option> ...           set options\n" ++-  "   :seti <option> ...          set options for interactive evaluation only\n" ++-  "   :set local-config { source | ignore }\n" ++-  "                               set whether to source .ghci in current dir\n" ++-  "                               (loading untrusted config is a security issue)\n" ++-  "   :set args <arg> ...         set the arguments returned by System.Environment.getArgs\n" ++-  "   :set prog <progname>        set the value returned by System.Environment.getProgName\n" ++-  "   :set prompt <prompt>        set the prompt used in GHCi\n" ++-  "   :set prompt-cont <prompt>   set the continuation prompt used in GHCi\n" ++-  "   :set prompt-function <expr> set the function to handle the prompt\n" ++-  "   :set prompt-cont-function <expr>\n" ++-  "                               set the function to handle the continuation prompt\n" ++-  "   :set editor <cmd>           set the command used for :edit\n" ++-  "   :set stop [<n>] <cmd>       set the command to run when a breakpoint is hit\n" ++-  "   :unset <option> ...         unset options\n" ++-  "\n" ++-  "  Options for ':set' and ':unset':\n" ++-  "\n" ++-  "    +m            allow multiline commands\n" ++-  "    +r            revert top-level expressions after each evaluation\n" ++-  "    +s            print timing/memory stats after each evaluation\n" ++-  "    +t            print type after evaluation\n" ++-  "    +c            collect type/location info after loading modules\n" ++-  "    -<flags>      most GHC command line flags can also be set here\n" ++-  "                         (eg. -v2, -XFlexibleInstances, etc.)\n" ++-  "                    for GHCi-specific flags, see User's Guide,\n"++-  "                    Flag reference, Interactive-mode options\n" ++-  "\n" ++-  " -- Commands for displaying information:\n" ++-  "\n" ++-  "   :show bindings              show the current bindings made at the prompt\n" ++-  "   :show breaks                show the active breakpoints\n" ++-  "   :show context               show the breakpoint context\n" ++-  "   :show imports               show the current imports\n" ++-  "   :show linker                show current linker state\n" ++-  "   :show modules               show the currently loaded modules\n" ++-  "   :show packages              show the currently active package flags\n" ++-  "   :show paths                 show the currently active search paths\n" ++-  "   :show language              show the currently active language flags\n" ++-  "   :show targets               show the current set of targets\n" ++-  "   :show <setting>             show value of <setting>, which is one of\n" ++-  "                                  [args, prog, editor, stop]\n" ++-  "   :showi language             show language flags for interactive evaluation\n" ++-  "\n" ++-  " The User's Guide has more information. An online copy can be found here:\n" ++-  "\n" ++-  "   https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html\n" ++-  "\n"--findEditor :: IO String-findEditor = do-    getEnv "VISUAL" <|> getEnv "EDITOR" <|> defaultEditor-  where-    defaultEditor = do-#if defined(mingw32_HOST_OS)-      win <- System.Win32.getWindowsDirectory-      return (win </> "notepad.exe")-#else-      return ""-#endif--default_progname, default_stop :: String-default_progname = "<interactive>"-default_stop = ""--default_prompt, default_prompt_cont :: PromptFunction-default_prompt = generatePromptFunctionFromString "ghci> "-default_prompt_cont = generatePromptFunctionFromString "ghci| "--default_args :: [String]-default_args = []--interactiveUI :: GhciSettings -> [(FilePath, Maybe UnitId, Maybe Phase)] -> Maybe [String]-              -> Ghc ()-interactiveUI config srcs maybe_exprs = do-   -- This is a HACK to make sure dynflags are not overwritten when setting-   -- options. When GHCi is made properly multi component it should be removed.-   modifySession (\env -> hscSetActiveUnitId (hscActiveUnitId env) env)-   -- HACK! If we happen to get into an infinite loop (eg the user-   -- types 'let x=x in x' at the prompt), then the thread will block-   -- on a blackhole, and become unreachable during GC.  The GC will-   -- detect that it is unreachable and send it the NonTermination-   -- exception.  However, since the thread is unreachable, everything-   -- it refers to might be finalized, including the standard Handles.-   -- This sounds like a bug, but we don't have a good solution right-   -- now.-   _ <- liftIO $ newStablePtr stdin-   _ <- liftIO $ newStablePtr stdout-   _ <- liftIO $ newStablePtr stderr--    -- Initialise buffering for the *interpreted* I/O system-   (nobuffering, flush) <- runInternal initInterpBuffering--   -- The initial set of DynFlags used for interactive evaluation is the same-   -- as the global DynFlags, plus -XExtendedDefaultRules and-   -- -XNoMonomorphismRestriction.-   -- See Note [Changing language extensions for interactive evaluation] #10857-   dflags <- getDynFlags-   let dflags' = (xopt_set_unlessExplSpec-                      LangExt.ExtendedDefaultRules xopt_set)-               . (xopt_set_unlessExplSpec-                      LangExt.MonomorphismRestriction xopt_unset)-               $ dflags-   GHC.setInteractiveDynFlags dflags'-   _ <- GHC.setProgramDynFlags-               -- Set Opt_KeepGoing so that :reload loads as much as-               -- possible-               (gopt_set dflags Opt_KeepGoing)--   -- Update the LogAction. Ensure we don't override the user's log action lest-   -- we break -ddump-json (#14078)-   lastErrLocationsRef <- liftIO $ newIORef []-   pushLogHookM (ghciLogAction lastErrLocationsRef)--   when (isNothing maybe_exprs) $ do-        -- Only for GHCi (not runghc and ghc -e):--        -- Turn buffering off for the compiled program's stdout/stderr-        turnOffBuffering_ nobuffering-        -- Turn buffering off for GHCi's stdout-        liftIO $ hFlush stdout-        liftIO $ hSetBuffering stdout NoBuffering-        -- We don't want the cmd line to buffer any input that might be-        -- intended for the program, so unbuffer stdin.-        liftIO $ hSetBuffering stdin NoBuffering-        liftIO $ hSetBuffering stderr NoBuffering-#if defined(mingw32_HOST_OS)-        -- On Unix, stdin will use the locale encoding.  The IO library-        -- doesn't do this on Windows (yet), so for now we use UTF-8,-        -- for consistency with GHC 6.10 and to make the tests work.-        liftIO $ hSetEncoding stdin utf8-#endif--   default_editor <- liftIO $ findEditor-   eval_wrapper <- mkEvalWrapper default_progname default_args-   let prelude_import = simpleImportDecl preludeModuleName-   hsc_env <- GHC.getSession-   let in_multi = length (hsc_all_home_unit_ids hsc_env) > 1-   empty_cache <- liftIO newIfaceCache-   startGHCi (runGHCi srcs maybe_exprs)-        GHCiState{ progname           = default_progname,-                   args               = default_args,-                   evalWrapper        = eval_wrapper,-                   prompt             = defPrompt config,-                   prompt_cont        = defPromptCont config,-                   stop               = default_stop,-                   editor             = default_editor,-                   options            = [],-                   multiMode          = in_multi,-                   localConfig        = SourceLocalConfig,-                   -- We initialize line number as 0, not 1, because we use-                   -- current line number while reporting errors which is-                   -- incremented after reading a line.-                   line_number        = 0,-                   break_ctr          = 0,-                   breaks             = IntMap.empty,-                   tickarrays         = emptyModuleEnv,-                   ghci_commands      = availableCommands config,-                   ghci_macros        = [],-                   last_command       = Nothing,-                   cmd_wrapper        = (cmdSuccess =<<),-                   cmdqueue           = [],-                   remembered_ctx     = [],-                   transient_ctx      = [],-                   extra_imports      = [],-                   prelude_imports    = [prelude_import],-                   ghc_e              = isJust maybe_exprs,-                   short_help         = shortHelpText config,-                   long_help          = fullHelpText config,-                   lastErrorLocations = lastErrLocationsRef,-                   mod_infos          = M.empty,-                   flushStdHandles    = flush,-                   noBuffering        = nobuffering,-                   ifaceCache = empty_cache,-                   dapContextGHCiState = dapContextGhciSettings config-                 }--   return ()--{--Note [Changing language extensions for interactive evaluation]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-GHCi maintains two sets of options:--- The "loading options" apply when loading modules-- The "interactive options" apply when evaluating expressions and commands-    typed at the GHCi prompt.--The loading options are mostly created in ghc/Main.hs:main' from the command-line flags. In the function ghc/GHCi/UI.hs:interactiveUI the loading options-are copied to the interactive options.--These interactive options (but not the loading options!) are supplemented-unconditionally by setting ExtendedDefaultRules ON and-MonomorphismRestriction OFF. The unconditional setting of these options-eventually overwrite settings already specified at the command line.--Therefore instead of unconditionally setting ExtendedDefaultRules and-NoMonomorphismRestriction for the interactive options, we use the function-'xopt_set_unlessExplSpec' to first check whether the extension has already-specified at the command line.--The ghci config file has not yet been processed.--}--resetLastErrorLocations :: GhciMonad m => m ()-resetLastErrorLocations = do-    st <- getGHCiState-    liftIO $ writeIORef (lastErrorLocations st) []--ghciLogAction :: IORef [(FastString, Int)] -> LogAction -> LogAction-ghciLogAction lastErrLocations old_log_action-              dflags msg_class srcSpan msg = do-    old_log_action dflags msg_class srcSpan msg-    case msg_class of-        MCDiagnostic SevError _reason -> case srcSpan of-            RealSrcSpan rsp _ -> modifyIORef lastErrLocations-                (++ [(srcLocFile (realSrcSpanStart rsp), srcLocLine (realSrcSpanStart rsp))])-            _ -> return ()-        _ -> return ()---- | Takes a file name and prefixes it with the appropriate--- GHC appdir.--- Uses ~/.ghc (getAppUserDataDirectory) if it exists--- If it doesn't, then it uses $XDG_DATA_HOME/ghc--- Earlier we always used to use ~/.ghc, but we want--- to gradually move to $XDG_DATA_HOME to respect the XDG specification------ As a migration strategy, we will only create new directories in--- the appropriate XDG location. However, we will use the old directory--- if it already exists.-getAppDataFile :: FilePath -> IO (Maybe FilePath)-getAppDataFile file = do-    let new_path = tryIO (getXdgDirectory XdgConfig "ghc") >>= \case-          Left _ -> pure Nothing-          Right dir -> flip catchIO (const $ return Nothing) $ do-            createDirectoryIfMissing False dir-            pure $ Just $ dir </> file--    e_old_path <- tryIO (getAppUserDataDirectory "ghc")-    case e_old_path of-      Right old_path -> doesDirectoryExist old_path >>= \case-        True -> pure $ Just $ old_path </> file-        False -> new_path-      Left _ -> new_path--runGHCi :: [(FilePath, Maybe UnitId, Maybe Phase)] -> Maybe [String] -> GHCi ()-runGHCi paths maybe_exprs = do-  dflags <- getDynFlags-  let-   ignore_dot_ghci = gopt Opt_IgnoreDotGhci dflags--   app_user_dir = liftIO $ getAppDataFile "ghci.conf"--   home_dir = do-    either_dir <- liftIO $ tryIO (getEnv "HOME")-    case either_dir of-      Right home -> return (Just (home </> ".ghci"))-      _ -> return Nothing--   canonicalizePath' :: FilePath -> IO (Maybe FilePath)-   canonicalizePath' fp = liftM Just (canonicalizePath fp)-                `catchIO` \_ -> return Nothing--   sourceConfigFile :: FilePath -> GHCi ()-   sourceConfigFile file = do-     exists <- liftIO $ doesFileExist file-     when exists $ do-       either_hdl <- liftIO $ tryIO (openFile file ReadMode)-       case either_hdl of-         Left _e   -> return ()-         -- NOTE: this assumes that runInputT won't affect the terminal;-         -- can we assume this will always be the case?-         -- This would be a good place for runFileInputT.-         Right hdl ->-             do runInputTWithPrefs defaultPrefs defaultSettings $-                          runCommands $ fileLoop hdl-                liftIO (hClose hdl `catchIO` \_ -> return ())-                -- Don't print a message if this is really ghc -e (#11478).-                -- Also, let the user silence the message with -v0-                -- (the default verbosity in GHCi is 1).-                when (isNothing maybe_exprs && verbosity dflags > 0) $-                  liftIO $ putStrLn ("Loaded GHCi configuration from " ++ file)--  ----  setGHCContextFromGHCiState--  processedCfgs <- if ignore_dot_ghci-    then pure []-    else do-      userCfgs <- do-        paths <- catMaybes <$> sequence [ app_user_dir, home_dir ]-        checkedPaths <- liftIO $ filterM checkFileAndDirPerms paths-        liftIO . fmap (nub . catMaybes) $ mapM canonicalizePath' checkedPaths--      localCfg <- do-        let path = ".ghci"-        ok <- liftIO $ checkFileAndDirPerms path-        if ok then liftIO $ canonicalizePath' path else pure Nothing--      mapM_ sourceConfigFile userCfgs-        -- Process the global and user .ghci-        -- (but not $CWD/.ghci or CLI args, yet)--      behaviour <- localConfig <$> getGHCiState--      processedLocalCfg <- case localCfg of-        Just path | path `notElem` userCfgs ->-          -- don't read .ghci twice if CWD is $HOME-          case behaviour of-            SourceLocalConfig -> localCfg <$ sourceConfigFile path-            IgnoreLocalConfig -> pure Nothing-        _ -> pure Nothing--      pure $ maybe id (:) processedLocalCfg userCfgs--  let arg_cfgs = reverse $ ghciScripts dflags-    -- -ghci-script are collected in reverse order-    -- We don't require that a script explicitly added by -ghci-script-    -- is owned by the current user. (#6017)--  mapM_ sourceConfigFile $ nub arg_cfgs \\ processedCfgs-    -- Dedup, and remove any configs we already processed.-    -- Importantly, if $PWD/.ghci was ignored due to configuration,-    -- explicitly specifying it does cause it to be processed.--  -- Perform a :reload for files given on the GHCi command line-  -- The appropiate targets will already be set-  -- When in -e mode, if the load fails then we want to stop-  -- immediately rather than going on to evaluate the expression.-  when (not (null paths)) $ do-     ok <- ghciHandle (\e -> do showException e; return Failed) $-                    loadModule paths-     when (isJust maybe_exprs && failed ok) $-        liftIO (exitWith (ExitFailure 1))--  installInteractivePrint (interactivePrint dflags) (isJust maybe_exprs)--  -- if verbosity is greater than 0, or we are connected to a-  -- terminal, display the prompt in the interactive loop.-  is_tty <- liftIO (return True)                                         -- DAP modified.-  let show_prompt = verbosity dflags > 0 || is_tty--  -- reset line number-  modifyGHCiState $ \st -> st{line_number=0}--  case maybe_exprs of-        Nothing ->-          do-            -- enter the interactive loop-            runGHCiInput $ runCommands $ nextInputLine show_prompt is_tty-        Just exprs -> do-            -- just evaluate the expression we were given-            enqueueCommands exprs-            let hdle e = do st <- getGHCiState-                            -- flush the interpreter's stdout/stderr on exit (#3890)-                            flushInterpBuffers-                            -- Jump through some hoops to get the-                            -- current progname in the exception text:-                            -- <progname>: <exception>-                            liftIO $ withProgName (progname st)-                                   $ topHandler e-                                   -- this used to be topHandlerFastExit, see #2228-            runInputTWithPrefs defaultPrefs defaultSettings $ do-                -- make `ghc -e` exit nonzero on failure, see #7962, #9916, #17560, #18441-                _ <- runCommands' hdle-                     (Just $ hdle (toException $ ExitFailure 1) >> return ())-                     (return Nothing)-                return ()--  -- and finally, exit-  liftIO $ when (verbosity dflags > 0) $ putStrLn "Leaving GHCi."--runGHCiInput :: InputT GHCi a -> GHCi a-runGHCiInput f = do-    dflags <- getDynFlags-    let ghciHistory = gopt Opt_GhciHistory dflags-    let localGhciHistory = gopt Opt_LocalGhciHistory dflags-    currentDirectory <- liftIO $ getCurrentDirectory--    histFile <- case (ghciHistory, localGhciHistory) of-      (True, True) -> return (Just (currentDirectory </> ".ghci_history"))-      (True, _) -> liftIO $ getAppDataFile "ghci_history"-      _ -> return Nothing--    runInputT-        (setComplete ghciCompleteWord $ defaultSettings {historyFile = histFile})-        f---- | How to get the next input line from the user-nextInputLine :: Bool -> Bool -> InputT GHCi (Maybe String)-nextInputLine show_prompt is_tty-  | is_tty = do-    prmpt <- if show_prompt then lift mkPrompt else return ""-    r <- getInputLine prmpt-    incrementLineNo-    return r-  | otherwise = do-    when show_prompt $ lift mkPrompt >>= liftIO . putStr-    fileLoop stdin---- NOTE: We only read .ghci files if they are owned by the current user,--- and aren't world writable (files owned by root are ok, see #9324).--- Otherwise, we could be accidentally running code planted by--- a malicious third party.---- Furthermore, We only read ./.ghci if . is owned by the current user--- and isn't writable by anyone else.  I think this is sufficient: we--- don't need to check .. and ../.. etc. because "."  always refers to--- the same directory while a process is running.--checkFileAndDirPerms :: FilePath -> IO Bool-checkFileAndDirPerms file = do-  file_ok <- checkPerms file-  -- Do not check dir perms when .ghci doesn't exist, otherwise GHCi will-  -- print some confusing and useless warnings in some cases (e.g. in-  -- travis). Note that we can't add a test for this, as all ghci tests should-  -- run with -ignore-dot-ghci, which means we never get here.-  if file_ok then checkPerms (getDirectory file) else return False-  where-  getDirectory f = case takeDirectory f of-    "" -> "."-    d -> d--checkPerms :: FilePath -> IO Bool-#if defined(mingw32_HOST_OS)-checkPerms _ = return True-#else-checkPerms file =-  handleIO (\_ -> return False) $ do-    st <- getFileStatus file-    me <- getRealUserID-    let mode = System.Posix.fileMode st-        ok = (fileOwner st == me || fileOwner st == 0) &&-             groupWriteMode /= mode `intersectFileModes` groupWriteMode &&-             otherWriteMode /= mode `intersectFileModes` otherWriteMode-    unless ok $-      -- #8248: Improving warning to include a possible fix.-      putStrLn $ "*** WARNING: " ++ file ++-                 " is writable by someone else, IGNORING!" ++-                 "\nSuggested fix: execute 'chmod go-w " ++ file ++ "'"-    return ok-#endif--incrementLineNo :: GhciMonad m => m ()-incrementLineNo = modifyGHCiState incLineNo-  where-    incLineNo st = st { line_number = line_number st + 1 }--fileLoop :: GhciMonad m => Handle -> m (Maybe String)-fileLoop hdl = do-   l <- liftIO $ tryIO $ hGetLine hdl-   case l of-        Left e | isEOFError e              -> return Nothing-               | -- as we share stdin with the program, the program-                 -- might have already closed it, so we might get a-                 -- handle-closed exception. We therefore catch that-                 -- too.-                 isIllegalOperation e      -> return Nothing-               | InvalidArgument <- etype  -> return Nothing-               | otherwise                 -> liftIO $ ioError e-                where etype = ioeGetErrorType e-                -- treat InvalidArgument in the same way as EOF:-                -- this can happen if the user closed stdin, or-                -- perhaps did getContents which closes stdin at-                -- EOF.-        Right l' -> do-           incrementLineNo-           return (Just l')--formatCurrentTime :: String -> IO String-formatCurrentTime format =-  getZonedTime >>= return . (formatTime defaultTimeLocale format)--getUserName :: IO String-getUserName = do-#if defined(mingw32_HOST_OS)-  getEnv "USERNAME"-    `catchIO` \e -> do-      putStrLn $ show e-      return ""-#else-  getLoginName-#endif--getInfoForPrompt :: GhciMonad m => m (SDoc, [String], Int)-getInfoForPrompt = do-  st <- getGHCiState-  imports <- GHC.getContext-  resumes <- GHC.getResumeContext--  context_bit <--        case resumes of-            [] -> return empty-            r:_ -> do-                let ix = GHC.resumeHistoryIx r-                if ix == 0-                   then return (brackets (ppr (GHC.resumeSpan r)) <> space)-                   else do-                        let hist = GHC.resumeHistory r !! (ix-1)-                        pan <- GHC.getHistorySpan hist-                        return (brackets (ppr (negate ix) <> char ':'-                                          <+> ppr pan) <> space)--  let-        dots | _:rs <- resumes, not (null rs) = text "... "-             | otherwise = empty--        rev_imports = reverse imports -- rightmost are the most recent--        myIdeclName d | Just m <- ideclAs d = unLoc m-                      | otherwise           = unLoc (ideclName d)--        modules_names =-             ['*':(moduleNameString m) | IIModule m <- rev_imports] ++-             [moduleNameString (myIdeclName d) | IIDecl d <- rev_imports]-        line = 1 + line_number st--  return (dots <> context_bit, modules_names, line)--parseCallEscape :: String -> (String, String)-parseCallEscape s-  | not (all isSpace beforeOpen) = ("", "")-  | null sinceOpen               = ("", "")-  | null sinceClosed             = ("", "")-  | null cmd                     = ("", "")-  | otherwise                    = (cmd, tail sinceClosed)-  where-    (beforeOpen, sinceOpen) = span (/='(') s-    (cmd, sinceClosed) = span (/=')') (tail sinceOpen)--checkPromptStringForErrors :: String -> Maybe String-checkPromptStringForErrors ('%':'c':'a':'l':'l':xs) =-  case parseCallEscape xs of-    ("", "") -> Just ("Incorrect %call syntax. " ++-                      "Should be %call(a command and arguments).")-    (_, afterClosed) -> checkPromptStringForErrors afterClosed-checkPromptStringForErrors ('%':'%':xs) = checkPromptStringForErrors xs-checkPromptStringForErrors (_:xs) = checkPromptStringForErrors xs-checkPromptStringForErrors "" = Nothing--generatePromptFunctionFromString :: String -> PromptFunction-generatePromptFunctionFromString promptS modules_names line =-        processString promptS-  where-        processString :: String -> GHCi SDoc-        processString ('%':'s':xs) =-            liftM2 (<>) (return modules_list) (processString xs)-            where-              modules_list = hsep . map text . ordNub $ modules_names-        processString ('%':'l':xs) =-            liftM2 (<>) (return $ ppr line) (processString xs)-        processString ('%':'d':xs) =-            liftM2 (<>) (liftM text formatted_time) (processString xs)-            where-              formatted_time = liftIO $ formatCurrentTime "%a %b %d"-        processString ('%':'t':xs) =-            liftM2 (<>) (liftM text formatted_time) (processString xs)-            where-              formatted_time = liftIO $ formatCurrentTime "%H:%M:%S"-        processString ('%':'T':xs) = do-            liftM2 (<>) (liftM text formatted_time) (processString xs)-            where-              formatted_time = liftIO $ formatCurrentTime "%I:%M:%S"-        processString ('%':'@':xs) = do-            liftM2 (<>) (liftM text formatted_time) (processString xs)-            where-              formatted_time = liftIO $ formatCurrentTime "%I:%M %P"-        processString ('%':'A':xs) = do-            liftM2 (<>) (liftM text formatted_time) (processString xs)-            where-              formatted_time = liftIO $ formatCurrentTime "%H:%M"-        processString ('%':'u':xs) =-            liftM2 (<>) (liftM text user_name) (processString xs)-            where-              user_name = liftIO $ getUserName-        processString ('%':'w':xs) =-            liftM2 (<>) (liftM text current_directory) (processString xs)-            where-              current_directory = liftIO $ getCurrentDirectory-        processString ('%':'o':xs) =-            liftM ((text os) <>) (processString xs)-        processString ('%':'a':xs) =-            liftM ((text arch) <>) (processString xs)-        processString ('%':'N':xs) =-            liftM ((text compilerName) <>) (processString xs)-        processString ('%':'V':xs) =-            liftM ((text $ showVersion compilerVersion) <>) (processString xs)-        processString ('%':'c':'a':'l':'l':xs) = do-            respond <- liftIO $ do-                (code, out, err) <--                    readProcessWithExitCode-                    (head list_words) (tail list_words) ""-                    `catchIO` \e -> return (ExitFailure 1, "", show e)-                case code of-                    ExitSuccess -> return out-                    _ -> do-                        hPutStrLn stderr err-                        return ""-            liftM ((text respond) <>) (processString afterClosed)-            where-              (cmd, afterClosed) = parseCallEscape xs-              list_words = words cmd-        processString ('%':'%':xs) =-            liftM ((char '%') <>) (processString xs)-        processString (x:xs) =-            liftM (char x <>) (processString xs)-        processString "" =-            return empty--mkPrompt :: GHCi String-mkPrompt = do-  st <- getGHCiState-  dflags <- getDynFlags-  (context, modules_names, line) <- getInfoForPrompt--  prompt_string <- (prompt st) modules_names line-  let prompt_doc = context <> prompt_string--  return (showSDoc dflags prompt_doc)--queryQueue :: GhciMonad m => m (Maybe String)-queryQueue = do-  st <- getGHCiState-  case cmdqueue st of-    []   -> return Nothing-    c:cs -> do setGHCiState st{ cmdqueue = cs }-               return (Just c)---- Reconfigurable pretty-printing Ticket #5461-installInteractivePrint :: GhciMonad m => Maybe String -> Bool -> m ()-installInteractivePrint Nothing _  = return ()-installInteractivePrint (Just ipFun) exprmode = do-  ok <- trySuccess $ do-                names <- GHC.parseName ipFun-                let name = case names of-                             name':_ -> name'-                             [] -> panic "installInteractivePrint"-                modifySession (\he -> let new_ic = setInteractivePrintName (hsc_IC he) name-                                      in he{hsc_IC = new_ic})-                return Succeeded--  when (failed ok && exprmode) $ liftIO (exitWith (ExitFailure 1))---- | The main read-eval-print loop-runCommands :: InputT GHCi (Maybe String) -> InputT GHCi ()-runCommands gCmd = runCommands' handler Nothing gCmd >> return ()--runCommands' :: (SomeException -> GHCi Bool) -- ^ Exception handler-             -> Maybe (GHCi ()) -- ^ Source error handler-             -> InputT GHCi (Maybe String)-             -> InputT GHCi ()-runCommands' eh sourceErrorHandler gCmd = mask $ \unmask -> do-    b <- handle (\e -> case fromException e of-                          Just UserInterrupt -> return $ Just False-                          _ -> case fromException e of-                                 Just ghce ->-                                   do liftIO (print (ghce :: GhcException))-                                      return Nothing-                                 _other ->-                                   liftIO (Exception.throwIO e))-            (unmask $ runOneCommand eh gCmd)-    case b of-      Nothing -> return ()-      Just success -> do-        unless success $ maybe (return ()) lift sourceErrorHandler-        unmask $ runCommands' eh sourceErrorHandler gCmd---- | Evaluate a single line of user input (either :<command> or Haskell code).--- A result of Nothing means there was no more input to process.--- Otherwise the result is Just b where b is True if the command succeeded;--- this is relevant only to ghc -e, which will exit with status 1--- if the command was unsuccessful. GHCi will continue in either case.--- TODO: replace Bool with CmdExecOutcome-runOneCommand :: (SomeException -> GHCi Bool) -> InputT GHCi (Maybe String)-            -> InputT GHCi (Maybe Bool)-runOneCommand eh gCmd = do-  -- run a previously queued command if there is one, otherwise get new-  -- input from user-  mb_cmd0 <- noSpace (lift queryQueue)-  mb_cmd1 <- maybe (noSpace gCmd) (return . Just) mb_cmd0-  case mb_cmd1 of-    Nothing -> return Nothing-    Just c  -> do-      st <- getGHCiState-      ghciHandle (\e -> lift $ eh e >>= return . Just) $-        handleSourceError printErrorAndFail $-          cmd_wrapper st $ doCommand c-               -- source error's are handled by runStmt-               -- is the handler necessary here?-  where-    printErrorAndFail err = do-        GHC.printException err-        return $ Just False     -- Exit ghc -e, but not GHCi--    noSpace q = q >>= maybe (return Nothing)-                            (\c -> case removeSpaces c of-                                     ""   -> noSpace q-                                     ":{" -> multiLineCmd q-                                     _    -> return (Just c) )-    multiLineCmd q = do-      st <- getGHCiState-      let p = prompt st-      setGHCiState st{ prompt = prompt_cont st }-      mb_cmd <- collectCommand q "" `MC.finally`-                modifyGHCiState (\st' -> st' { prompt = p })-      return mb_cmd-    -- we can't use removeSpaces for the sublines here, so-    -- multiline commands are somewhat more brittle against-    -- fileformat errors (such as \r in dos input on unix),-    -- we get rid of any extra spaces for the ":}" test;-    -- we also avoid silent failure if ":}" is not found;-    -- and since there is no (?) valid occurrence of \r (as-    -- opposed to its String representation, "\r") inside a-    -- ghci command, we replace any such with ' ' (argh:-(-    collectCommand q c = q >>=-      maybe (liftIO (ioError collectError))-            (\l->if removeSpaces l == ":}"-                 then return (Just c)-                 else collectCommand q (c ++ "\n" ++ map normSpace l))-      where normSpace '\r' = ' '-            normSpace   x  = x-    -- SDM (2007-11-07): is userError the one to use here?-    collectError = userError "unterminated multiline command :{ .. :}"--    cmdOutcome :: CmdExecOutcome -> Maybe Bool-    cmdOutcome CleanExit = Nothing-    cmdOutcome CmdSuccess = Just True-    cmdOutcome CmdFailure = Just False--    -- | Handle a line of input-    doCommand :: String -> InputT GHCi CommandResult--    -- command-    doCommand stmt | stmt'@(':' : cmd) <- removeSpaces stmt = do-      (stats, result) <- runWithStats (const Nothing) $ specialCommand cmd-      return $ CommandComplete stmt' (cmdOutcome <$> result) stats--    -- haskell-    doCommand stmt = do-      -- if 'stmt' was entered via ':{' it will contain '\n's-      let stmt_nl_cnt = length [ () | '\n' <- stmt ]-      ml <- lift $ isOptionSet Multiline-      if ml && stmt_nl_cnt == 0 -- don't trigger automatic multi-line mode for ':{'-multiline input-        then do-          fst_line_num <- line_number <$> getGHCiState-          mb_stmt <- checkInputForLayout stmt gCmd-          case mb_stmt of-            Nothing -> return CommandIncomplete-            Just ml_stmt -> do-              -- temporarily compensate line-number for multi-line input-              (stats, result) <- runAndPrintStats runAllocs $ lift $-                runStmtWithLineNum fst_line_num ml_stmt GHC.RunToCompletion-              return $-                CommandComplete ml_stmt (Just . runSuccess <$> result) stats-        else do -- single line input and :{ - multiline input-          last_line_num <- line_number <$> getGHCiState-          -- reconstruct first line num from last line num and stmt-          let fst_line_num | stmt_nl_cnt > 0 = last_line_num - (stmt_nl_cnt2 + 1)-                           | otherwise = last_line_num -- single line input-              stmt_nl_cnt2 = length [ () | '\n' <- stmt' ]-              stmt' = dropLeadingWhiteLines stmt -- runStmt doesn't like leading empty lines-          -- temporarily compensate line-number for multi-line input-          (stats, result) <- runAndPrintStats runAllocs $ lift $-            runStmtWithLineNum fst_line_num stmt' GHC.RunToCompletion-          return $ CommandComplete stmt' (Just . runSuccess <$> result) stats--    -- runStmt wrapper for temporarily overridden line-number-    runStmtWithLineNum :: Int -> String -> SingleStep-                       -> GHCi (Maybe GHC.ExecResult)-    runStmtWithLineNum lnum stmt step = do-        st0 <- getGHCiState-        setGHCiState st0 { line_number = lnum }-        result <- runStmt stmt step-        -- restore original line_number-        getGHCiState >>= \st -> setGHCiState st { line_number = line_number st0 }-        return result--    -- note: this is subtly different from 'unlines . dropWhile (all isSpace) . lines'-    dropLeadingWhiteLines s | (l0,'\n':r) <- break (=='\n') s-                            , all isSpace l0 = dropLeadingWhiteLines r-                            | otherwise = s----- #4316--- lex the input.  If there is an unclosed layout context, request input-checkInputForLayout-  :: GhciMonad m => String -> m (Maybe String) -> m (Maybe String)-checkInputForLayout stmt getStmt = do-   dflags' <- getDynFlags-   let dflags = xopt_set dflags' LangExt.AlternativeLayoutRule-   st0 <- getGHCiState-   let buf'   =  stringToStringBuffer stmt-       loc    = mkRealSrcLoc (fsLit (progname st0)) (line_number st0) 1-       pstate = Lexer.initParserState (initParserOpts dflags) buf' loc-   case Lexer.unP goToEnd pstate of-     (Lexer.POk _ False) -> return $ Just stmt-     _other              -> do-       st1 <- getGHCiState-       let p = prompt st1-       setGHCiState st1{ prompt = prompt_cont st1 }-       mb_stmt <- ghciHandle (\ex -> case fromException ex of-                            Just UserInterrupt -> return Nothing-                            _ -> case fromException ex of-                                 Just ghce ->-                                   do liftIO (print (ghce :: GhcException))-                                      return Nothing-                                 _other -> liftIO (Exception.throwIO ex))-                     getStmt-       modifyGHCiState (\st' -> st' { prompt = p })-       -- the recursive call does not recycle parser state-       -- as we use a new string buffer-       case mb_stmt of-         Nothing  -> return Nothing-         Just str -> if str == ""-           then return $ Just stmt-           else do-             checkInputForLayout (stmt++"\n"++str) getStmt-     where goToEnd = do-             eof <- Lexer.nextIsEOF-             if eof-               then Lexer.activeContext-               else Lexer.lexer False return >> goToEnd--enqueueCommands :: GhciMonad m => [String] -> m ()-enqueueCommands cmds = do-  -- make sure we force any exceptions in the commands while we're-  -- still inside the exception handler, otherwise bad things will-  -- happen (see #10501)-  cmds `deepseq` return ()-  modifyGHCiState $ \st -> st{ cmdqueue = cmds ++ cmdqueue st }---- | Entry point to execute some haskell code from user.--- The return value True indicates success, as in `runOneCommand`.-runStmt :: GhciMonad m => String -> SingleStep -> m (Maybe GHC.ExecResult)-runStmt input step = do-  pflags <- initParserOpts <$> GHC.getInteractiveDynFlags-  -- In GHCi, we disable `-fdefer-type-errors`, as well as `-fdefer-type-holes`-  -- and `-fdefer-out-of-scope-variables` for **naked expressions**. The-  -- declarations and statements are not affected.-  -- See Note [Deferred type errors in GHCi] in GHC.Tc.Module-  st <- getGHCiState-  let source = progname st-  let line = line_number st--  if | GHC.isStmt pflags input -> do-         hsc_env <- GHC.getSession-         mb_stmt <- liftIO (runInteractiveHsc hsc_env (hscParseStmtWithLocation source line input))-         case mb_stmt of-           Nothing ->-             -- empty statement / comment-             return (Just exec_complete)-           Just stmt ->-             run_stmt stmt--     -- Otherwise assume a declaration (or a list of declarations)-     -- and/or import(s) (#20473).-     -- Note: `GHC.isDecl` returns False on input like-     -- `data Infix a b = a :@: b; infixl 4 :@:`-     -- and should therefore not be used here.-     | otherwise -> do-         hsc_env <- GHC.getSession-         let !ic = hsc_IC hsc_env  -- Bang-pattern to avoid space leaks-         setDumpFilePrefix ic-           -- `-ddump-to-file` must work for normal GHCi compilations /-           --     evaluations. (#17500)-         HsModule { hsmodDecls = decls, hsmodImports = imports } <--            liftIO (hscParseModuleWithLocation hsc_env source line input)-         run_imports imports-         run_decls decls-  where-    exec_complete = GHC.ExecComplete (Right []) 0--    run_imports imports = mapM_ (addImportToContext . unLoc) imports--    run_stmt :: GhciMonad m => GhciLStmt GhcPs -> m (Maybe GHC.ExecResult)-    run_stmt stmt = do-           m_result <- GhciMonad.runStmt stmt input step-           case m_result of-               Nothing     -> return Nothing-               Just result -> Just <$> afterRunStmt (const True) result--    -- `x = y` (a declaration) should be treated as `let x = y` (a statement).-    -- The reason is because GHCi wasn't designed to support `x = y`, but then-    -- b98ff3 (#7253) added support for it, except it did not do a good job and-    -- caused problems like:-    ---    --  - not adding the binders defined this way in the necessary places caused-    --    `x = y` to not work in some cases (#12091).-    --  - some GHCi command crashed after `x = y` (#15721)-    --  - warning generation did not work for `x = y` (#11606)-    --  - because `x = y` is a declaration (instead of a statement) differences-    --    in generated code caused confusion (#16089)-    ---    -- Instead of dealing with all these problems individually here we fix this-    -- mess by just treating `x = y` as `let x = y`.-    run_decls :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe GHC.ExecResult)-    -- Only turn `FunBind` and `VarBind` into statements, other bindings-    -- (e.g. `PatBind`) need to stay as decls.-    run_decls [L l (ValD _ bind@FunBind{})] = run_stmt (mk_stmt (locA l) bind)-    run_decls [L l (ValD _ bind@VarBind{})] = run_stmt (mk_stmt (locA l) bind)-    -- Note that any `x = y` declarations below will be run as declarations-    -- instead of statements (e.g. `...; x = y; ...`)-    run_decls decls = do-      -- In the new IO library, read handles buffer data even if the Handle-      -- is set to NoBuffering.  This causes problems for GHCi where there-      -- are really two stdin Handles.  So we flush any bufferred data in-      -- GHCi's stdin Handle here (only relevant if stdin is attached to-      -- a file, otherwise the read buffer can't be flushed).-      _ <- liftIO $ tryIO $ hFlushAll stdin-      m_result <- GhciMonad.runDecls' decls-      forM m_result $ \result ->-        afterRunStmt (const True) (GHC.ExecComplete (Right result) 0)--    mk_stmt :: SrcSpan -> HsBind GhcPs -> GhciLStmt GhcPs-    mk_stmt loc bind =-      let-        la  = L (noAnnSrcSpan loc)-        la' = L (noAnnSrcSpan loc)-      in la (LetStmt noAnn (HsValBinds noAnn (ValBinds NoAnnSortKey (unitBag (la' bind)) [])))--    setDumpFilePrefix :: GHC.GhcMonad m => InteractiveContext -> m () -- #17500-    setDumpFilePrefix ic = do-        dflags <- GHC.getInteractiveDynFlags-        GHC.setInteractiveDynFlags dflags { dumpPrefix = modStr ++ "." }-      where-        modStr = moduleNameString $ moduleName $ icInteractiveModule $ ic---- | Clean up the GHCi environment after a statement has run-afterRunStmt :: GhciMonad m-             => (SrcSpan -> Bool) -> GHC.ExecResult -> m GHC.ExecResult-afterRunStmt step_here run_result = do-  resumes <- GHC.getResumeContext-  case run_result of-     GHC.ExecComplete{..} ->-       case execResult of-          Left ex -> liftIO $ Exception.throwIO ex-          Right names -> do-            show_types <- isOptionSet ShowType-            when show_types $ printTypeOfNames names-     GHC.ExecBreak names mb_info-         | isNothing  mb_info ||-           step_here (GHC.resumeSpan $ head resumes) -> do-               mb_id_loc <- toBreakIdAndLocation mb_info-               let bCmd = maybe "" ( \(_,l) -> onBreakCmd l ) mb_id_loc-               if (null bCmd)-                 then printStoppedAtBreakInfo (head resumes) names-                 else enqueueCommands [bCmd]-               -- run the command set with ":set stop <cmd>"-               st <- getGHCiState-               enqueueCommands [stop st]-               return ()-         | otherwise -> resume step_here GHC.SingleStep Nothing >>=-                        afterRunStmt step_here >> return ()--  flushInterpBuffers-  withSignalHandlers $ do-     b <- isOptionSet RevertCAFs-     when b revertCAFs--  return run_result--runSuccess :: Maybe GHC.ExecResult -> Bool-runSuccess run_result-  | Just (GHC.ExecComplete { execResult = Right _ }) <- run_result = True-  | otherwise = False--runAllocs :: Maybe GHC.ExecResult -> Maybe Integer-runAllocs m = do-  res <- m-  case res of-    GHC.ExecComplete{..} -> Just (fromIntegral execAllocation)-    _ -> Nothing--toBreakIdAndLocation :: GhciMonad m-                     => Maybe GHC.BreakInfo -> m (Maybe (Int, BreakLocation))-toBreakIdAndLocation Nothing = return Nothing-toBreakIdAndLocation (Just inf) = do-  let md = GHC.breakInfo_module inf-      nm = GHC.breakInfo_number inf-  st <- getGHCiState-  return $ listToMaybe [ id_loc | id_loc@(_,loc) <- IntMap.assocs (breaks st),-                                  breakModule loc == md,-                                  breakTick loc == nm ]--printStoppedAtBreakInfo :: GHC.GhcMonad m => Resume -> [Name] -> m ()-printStoppedAtBreakInfo res names = do-  printForUser $ pprStopped res-  --  printTypeOfNames session names-  let namesSorted = sortBy compareNames names-  tythings <- catMaybes `liftM` mapM GHC.lookupName namesSorted-  docs <- mapM pprTypeAndContents [i | AnId i <- tythings]-  printForUserPartWay $ vcat docs--printTypeOfNames :: GHC.GhcMonad m => [Name] -> m ()-printTypeOfNames names- = mapM_ (printTypeOfName ) $ sortBy compareNames names--compareNames :: Name -> Name -> Ordering-n1 `compareNames` n2 =-  (compare `on` getOccString) n1 n2 `thenCmp`-  (SrcLoc.leftmost_smallest `on` getSrcSpan) n1 n2--printTypeOfName :: GHC.GhcMonad m => Name -> m ()-printTypeOfName n-   = do maybe_tything <- GHC.lookupName n-        case maybe_tything of-            Nothing    -> return ()-            Just thing -> printTyThing thing---data MaybeCommand = GotCommand Command | BadCommand | NoLastCommand---- | Entry point for execution a ':<command>' input from user-specialCommand :: String -> InputT GHCi CmdExecOutcome-specialCommand ('!':str) = lift $ shellEscape (dropWhile isSpace str)-specialCommand str = do-  let (cmd,rest) = break isSpace str-  maybe_cmd <- lookupCommand cmd-  htxt <- short_help <$> getGHCiState-  case maybe_cmd of-    GotCommand cmd -> (cmdAction cmd) (dropWhile isSpace rest)-    BadCommand ->-      do liftIO $ hPutStr stderr ("unknown command ':" ++ cmd ++ "'\n"-                           ++ htxt)-         return CmdFailure-    NoLastCommand ->-      do liftIO $ hPutStr stderr ("there is no last command to perform\n"-                           ++ htxt)-         return CmdFailure--shellEscape :: MonadIO m => String -> m CmdExecOutcome-shellEscape str = liftIO $ do-  exitCode <- system str-  case exitCode of-    ExitSuccess -> return CmdSuccess-    ExitFailure _ -> return CmdFailure--lookupCommand :: GhciMonad m => String -> m (MaybeCommand)-lookupCommand "" = do-  st <- getGHCiState-  case last_command st of-      Just c -> return $ GotCommand c-      Nothing -> return NoLastCommand-lookupCommand str = do-  mc <- lookupCommand' str-  modifyGHCiState (\st -> st { last_command = mc })-  return $ case mc of-           Just c -> GotCommand c-           Nothing -> BadCommand--lookupCommand' :: GhciMonad m => String -> m (Maybe Command)-lookupCommand' ":" = return Nothing-lookupCommand' str' = do-  macros    <- ghci_macros <$> getGHCiState-  ghci_cmds <- ghci_commands <$> getGHCiState--  let ghci_cmds_nohide = filter (not . cmdHidden) ghci_cmds--  let (str, xcmds) = case str' of-          ':' : rest -> (rest, [])     -- "::" selects a builtin command-          _          -> (str', macros) -- otherwise include macros in lookup--      lookupExact  s = find $ (s ==)              . cmdName-      lookupPrefix s = find $ (s `isPrefixOptOf`) . cmdName--      -- hidden commands can only be matched exact-      builtinPfxMatch = lookupPrefix str ghci_cmds_nohide--  -- first, look for exact match (while preferring macros); then, look-  -- for first prefix match (preferring builtins), *unless* a macro-  -- overrides the builtin; see #8305 for motivation-  return $ lookupExact str xcmds <|>-           lookupExact str ghci_cmds <|>-           (builtinPfxMatch >>= \c -> lookupExact (cmdName c) xcmds) <|>-           builtinPfxMatch <|>-           lookupPrefix str xcmds---- This predicate is for prefix match with a command-body and--- suffix match with an option, such as `!`.--- The current implementation assumes only the `!` character--- as the option delimiter.--- See also #17345-isPrefixOptOf :: String -> String -> Bool-isPrefixOptOf s x = let (body, opt) = break (== '!') s-                    in  (body `isPrefixOf` x) && (opt `isSuffixOf` x)--getCurrentBreakSpan :: GHC.GhcMonad m => m (Maybe SrcSpan)-getCurrentBreakSpan = do-  resumes <- GHC.getResumeContext-  case resumes of-    [] -> return Nothing-    (r:_) -> do-        let ix = GHC.resumeHistoryIx r-        if ix == 0-           then return (Just (GHC.resumeSpan r))-           else do-                let hist = GHC.resumeHistory r !! (ix-1)-                pan <- GHC.getHistorySpan hist-                return (Just pan)--getCallStackAtCurrentBreakpoint :: GHC.GhcMonad m => m (Maybe [String])-getCallStackAtCurrentBreakpoint = do-  resumes <- GHC.getResumeContext-  case resumes of-    [] -> return Nothing-    (r:_) -> do-       interp <- hscInterp <$> GHC.getSession-       Just <$> liftIO (costCentreStackInfo interp (GHC.resumeCCS r))--getCurrentBreakModule :: GHC.GhcMonad m => m (Maybe Module)-getCurrentBreakModule = do-  resumes <- GHC.getResumeContext-  case resumes of-    [] -> return Nothing-    (r:_) -> do-        let ix = GHC.resumeHistoryIx r-        if ix == 0-           then return (GHC.breakInfo_module `liftM` GHC.resumeBreakInfo r)-           else do-                let hist = GHC.resumeHistory r !! (ix-1)-                return $ Just $ GHC.getHistoryModule  hist------------------------------------------------------------------------------------- Commands-----------------------------------------------------------------------------------noArgs :: MonadIO m => m () -> String -> m ()-noArgs m "" = m-noArgs _ _  = liftIO $ putStrLn "This command takes no arguments"--withSandboxOnly :: GHC.GhcMonad m => String -> m () -> m ()-withSandboxOnly cmd this = do-   dflags <- getDynFlags-   if not (gopt Opt_GhciSandbox dflags)-      then printForUser (text cmd <+>-                         text "is not supported with -fno-ghci-sandbox")-      else this---------------------------------------------------------------------------------- :help--help :: GhciMonad m => String -> m ()-help _ = do-    txt <- long_help `fmap` getGHCiState-    liftIO $ putStr txt---------------------------------------------------------------------------------- :info--info :: GHC.GhcMonad m => Bool -> String -> m ()-info _ "" = throwGhcException (CmdLineError "syntax: ':i <thing-you-want-info-about>'")-info allInfo s  = handleSourceError GHC.printException $ do-    unqual <- GHC.getPrintUnqual-    dflags <- getDynFlags-    sdocs  <- mapM (infoThing allInfo) (words s)-    unit_state <- hsc_units <$> GHC.getSession-    mapM_ (liftIO . putStrLn . showSDocForUser dflags unit_state unqual) sdocs--infoThing :: GHC.GhcMonad m => Bool -> String -> m SDoc-infoThing allInfo str = do-    names     <- GHC.parseName str-    mb_stuffs <- mapM (GHC.getInfo allInfo) names-    let filtered = filterOutChildren (\(t,_f,_ci,_fi,_sd) -> t)-                                     (catMaybes mb_stuffs)-    return $ vcat (intersperse (text "") $ map pprInfo filtered)--  -- Filter out names whose parent is also there. Good-  -- example is '[]', which is both a type and data-  -- constructor in the same type-filterOutChildren :: (a -> TyThing) -> [a] -> [a]-filterOutChildren get_thing xs-  = filterOut has_parent xs-  where-    all_names = mkNameSet (map (getName . get_thing) xs)-    has_parent x = case tyThingParent_maybe (get_thing x) of-                     Just p  -> getName p `elemNameSet` all_names-                     Nothing -> False--pprInfo :: (TyThing, Fixity, [GHC.ClsInst], [GHC.FamInst], SDoc) -> SDoc-pprInfo (thing, fixity, cls_insts, fam_insts, docs)-  =  docs-  $$ pprTyThingInContextLoc thing-  $$ showFixity thing fixity-  $$ vcat (map GHC.pprInstance cls_insts)-  $$ vcat (map GHC.pprFamInst  fam_insts)---------------------------------------------------------------------------------- :main--runMain :: GhciMonad m => String -> m ()-runMain s = case toArgsNoLoc s of-            Left err   -> liftIO (hPutStrLn stderr err)-            Right args ->-                do dflags <- getDynFlags-                   let main = fromMaybe "main" (mainFunIs dflags)-                   -- Wrap the main function in 'void' to discard its value instead-                   -- of printing it (#9086). See Haskell 2010 report Chapter 5.-                   doWithArgs args $ "Control.Monad.void (" ++ main ++ ")"---------------------------------------------------------------------------------- :run--runRun :: GhciMonad m => String -> m ()-runRun s = case toCmdArgs s of-           Left err          -> liftIO (hPutStrLn stderr err)-           Right (cmd, args) -> doWithArgs args cmd--doWithArgs :: GhciMonad m => [String] -> String -> m ()-doWithArgs args cmd = enqueueCommands ["System.Environment.withArgs " ++-                                       show args ++ " (" ++ cmd ++ ")"]--{--Akin to @Prelude.words@, but acts like the Bourne shell, treating-quoted strings as Haskell Strings, and also parses Haskell [String]-syntax.--}--getCmd :: String -> Either String             -- Error-                           (String, String) -- (Cmd, Rest)-getCmd s = case break isSpace $ dropWhile isSpace s of-           ([], _) -> Left ("Couldn't find command in " ++ show s)-           res -> Right res--toCmdArgs :: String -> Either String             -- Error-                              (String, [String]) -- (Cmd, Args)-toCmdArgs s = case getCmd s of-              Left err -> Left err-              Right (cmd, s') -> case toArgsNoLoc s' of-                                 Left err -> Left err-                                 Right args -> Right (cmd, args)---- wrapper around GHC.Parser.Header.toArgs, but without locations-toArgsNoLoc :: String -> Either String [String]-toArgsNoLoc str = map unLoc <$> toArgs fake_loc str-  where-    fake_loc = mkRealSrcLoc (fsLit "<interactive>") 1 1-    -- this should never be seen, because it's discarded with the `map unLoc`---------------------------------------------------------------------------------- :cd--changeDirectory :: GhciMonad m => String -> m ()-changeDirectory "" = do-  -- :cd on its own changes to the user's home directory-  either_dir <- liftIO $ tryIO getHomeDirectory-  case either_dir of-     Left _e -> return ()-     Right dir -> changeDirectory dir-changeDirectory dir = do-  graph <- GHC.getModuleGraph-  when (not (null $ GHC.mgModSummaries graph)) $-        liftIO $ putStrLn "Warning: changing directory causes all loaded modules to be unloaded,\nbecause the search path has changed."-  -- delete defined breakpoints and clear the interface file cache (#1620)-  clearCaches-  setContextAfterLoad False Nothing-  GHC.workingDirectoryChanged-  dir' <- expandPath dir-  liftIO $ setCurrentDirectory dir'-  -- With -fexternal-interpreter, we have to change the directory of the subprocess too.-  -- (this gives consistent behaviour with and without -fexternal-interpreter)-  interp <- hscInterp <$> GHC.getSession-  case interpInstance interp of-    ExternalInterp {} -> do-      fhv <- compileGHCiExpr $-        "System.Directory.setCurrentDirectory " ++ show dir'-      liftIO $ evalIO interp fhv-    _ -> pure ()--trySuccess :: GhciMonad m => m SuccessFlag -> m SuccessFlag-trySuccess act =-    handleSourceError (\e -> do printErrAndMaybeExit e -- immediately exit fith failure if in ghc -e-                                return Failed) $ do-      act---------------------------------------------------------------------------------- :edit--editFile :: GhciMonad m => String -> m ()-editFile str =-  do file <- if null str then chooseEditFile else expandPath str-     st <- getGHCiState-     errs <- liftIO $ readIORef $ lastErrorLocations st-     let cmd = editor st-     when (null cmd)-       $ throwGhcException (CmdLineError "editor not set, use :set editor")-     lineOpt <- liftIO $ do-         let sameFile p1 p2 = liftA2 (==) (canonicalizePath p1) (canonicalizePath p2)-              `catchIO` (\_ -> return False)--         curFileErrs <- filterM (\(f, _) -> unpackFS f `sameFile` file) errs-         return $ case curFileErrs of-             (_, line):_ -> " +" ++ show line-             _ -> ""-     let cmdArgs = ' ':(file ++ lineOpt)-     code <- liftIO $ system (cmd ++ cmdArgs)--     when (code == ExitSuccess)-       $ reloadModule ""---- The user didn't specify a file so we pick one for them.--- Our strategy is to pick the first module that failed to load,--- or otherwise the first target.------ XXX: Can we figure out what happened if the dependency analysis fails---      (e.g., because the porgrammeer mistyped the name of a module)?--- XXX: Can we figure out the location of an error to pass to the editor?--- XXX: if we could figure out the list of errors that occurred during the--- last load/reaload, then we could start the editor focused on the first--- of those.-chooseEditFile :: GHC.GhcMonad m => m String-chooseEditFile =-  do let hasFailed (GHC.ModuleNode _deps x) = fmap not $ isLoadedModSummary x-         hasFailed _ = return False--     graph <- GHC.getModuleGraph-     failed_graph <--       GHC.mkModuleGraph <$> filterM hasFailed (GHC.mgModSummaries' graph)-     let order g  = flattenSCCs $ filterToposortToModules $-           GHC.topSortModuleGraph True g Nothing-         pick xs  = case xs of-                      x : _ -> GHC.ml_hs_file (GHC.ms_location x)-                      _     -> Nothing--     case pick (order failed_graph) of-       Just file -> return file-       Nothing   ->-         do targets <- GHC.getTargets-            case msum (map fromTarget targets) of-              Just file -> return file-              Nothing   -> throwGhcException (CmdLineError "No files to edit.")--  where fromTarget GHC.Target { targetId = GHC.TargetFile f _ } = Just f-        fromTarget _ = Nothing -- when would we get a module target?----------------------------------------------------------------------------------- :def--defineMacro :: GhciMonad m => Bool{-overwrite-} -> String -> m ()-defineMacro _ (':':_) = (liftIO $ hPutStrLn stderr-                          "macro name cannot start with a colon")-                            >> failIfExprEvalMode-defineMacro _ ('!':_) = (liftIO $ hPutStrLn stderr-                          "macro name cannot start with an exclamation mark")-                            >> failIfExprEvalMode-                          -- little code duplication allows to grep error msg-defineMacro overwrite s = do-  let (macro_name, definition) = break isSpace s-  macros <- ghci_macros <$> getGHCiState-  let defined = map cmdName macros-  if null macro_name-        then if null defined-                then liftIO $ putStrLn "no macros defined"-                else liftIO $ putStr ("the following macros are defined:\n" ++-                                      unlines defined)-  else do-    isCommand <- isJust <$> lookupCommand' macro_name-    let check_newname-          | macro_name `elem` defined = throwGhcException (CmdLineError-            ("macro '" ++ macro_name ++ "' is already defined. " ++ hint))-          | isCommand = throwGhcException (CmdLineError-            ("macro '" ++ macro_name ++ "' overwrites builtin command. " ++ hint))-          | otherwise = return ()-        hint = " Use ':def!' to overwrite."--    unless overwrite check_newname-    -- compile the expression-    handleSourceError printErrAndMaybeExit $ do-      step <- getGhciStepIO-      expr <- GHC.parseExpr definition-      -- > ghciStepIO . definition :: String -> IO String-      let stringTy :: LHsType GhcPs-          stringTy = nlHsTyVar NotPromoted stringTyCon_RDR-          ioM :: LHsType GhcPs -- AZ-          ioM = nlHsTyVar NotPromoted (getRdrName ioTyConName) `nlHsAppTy` stringTy-          body = nlHsVar compose_RDR `mkHsApp` (nlHsPar step)-                                     `mkHsApp` (nlHsPar expr)-          tySig = mkHsWildCardBndrs $ noLocA $ mkHsImplicitSigType $-                  nlHsFunTy stringTy ioM-          new_expr = L (getLoc expr) $ ExprWithTySig noAnn body tySig-      hv <- GHC.compileParsedExprRemote new_expr--      let newCmd = Command { cmdName = macro_name-                           , cmdAction = lift . runMacro hv-                           , cmdHidden = False-                           , cmdCompletionFunc = noCompletion-                           }--      -- later defined macros have precedence-      modifyGHCiState $ \s ->-        let filtered = [ cmd | cmd <- macros, cmdName cmd /= macro_name ]-        in s { ghci_macros = newCmd : filtered }--runMacro-  :: GhciMonad m-  => GHC.ForeignHValue  -- String -> IO String-  -> String-  -> m CmdExecOutcome-runMacro fun s = do-  interp <- hscInterp <$> GHC.getSession-  str <- liftIO $ evalStringToIOString interp fun s-  enqueueCommands (lines str)-  return CmdSuccess----------------------------------------------------------------------------------- :undef--undefineMacro :: GhciMonad m => String -> m ()-undefineMacro str = mapM_ undef (words str)- where undef macro_name = do-        cmds <- ghci_macros <$> getGHCiState-        if (macro_name `notElem` map cmdName cmds)-           then throwGhcException (CmdLineError-                ("macro '" ++ macro_name ++ "' is not defined"))-           else do-            -- This is a tad racy but really, it's a shell-            modifyGHCiState $ \s ->-                s { ghci_macros = filter ((/= macro_name) . cmdName)-                                         (ghci_macros s) }----------------------------------------------------------------------------------- :cmd--cmdCmd :: GhciMonad m => String -> m ()-cmdCmd str = handleSourceError printErrAndMaybeExit $ do-    step <- getGhciStepIO-    expr <- GHC.parseExpr str-    -- > ghciStepIO str :: IO String-    let new_expr = step `mkHsApp` expr-    hv <- GHC.compileParsedExprRemote new_expr--    interp <- hscInterp <$> GHC.getSession-    cmds <- liftIO $ evalString interp hv-    enqueueCommands (lines cmds)---- | Generate a typed ghciStepIO expression--- @ghciStepIO :: Ty String -> IO String@.-getGhciStepIO :: GHC.GhcMonad m => m (LHsExpr GhcPs)-getGhciStepIO = do-  ghciTyConName <- GHC.getGHCiMonad-  let stringTy = nlHsTyVar NotPromoted stringTyCon_RDR-      ghciM = nlHsTyVar NotPromoted (getRdrName ghciTyConName) `nlHsAppTy` stringTy-      ioM = nlHsTyVar NotPromoted (getRdrName ioTyConName) `nlHsAppTy` stringTy-      body = nlHsVar (getRdrName ghciStepIoMName)-      tySig = mkHsWildCardBndrs $ noLocA $ mkHsImplicitSigType $-              nlHsFunTy ghciM ioM-  return $ noLocA $ ExprWithTySig noAnn body tySig---------------------------------------------------------------------------------- :check--checkModule :: GhciMonad m => String -> m ()-checkModule m = do-  let modl = GHC.mkModuleName m-  ok <- handleSourceError (\e -> printErrAndMaybeExit e >> return False) $ do-          r <- GHC.typecheckModule =<< GHC.parseModule =<< GHC.getModSummary modl-          dflags <- getDynFlags-          liftIO $ putStrLn $ showSDoc dflags $-           case GHC.moduleInfo r of-             cm | Just scope <- GHC.modInfoTopLevelScope cm ->-                let-                    (loc, glob) = assert (all isExternalName scope) $-                                  partition ((== modl) . GHC.moduleName . GHC.nameModule) scope-                in-                        (text "global names: " <+> ppr glob) $$-                        (text "local  names: " <+> ppr loc)-             _ -> empty-          return True-  afterLoad (successIf ok) False---------------------------------------------------------------------------------- :doc--docCmd :: GHC.GhcMonad m => String -> m ()-docCmd "" =-  throwGhcException (CmdLineError "syntax: ':doc <thing-you-want-docs-for>'")-docCmd s  = do-  -- TODO: Maybe also get module headers for module names-  names <- GHC.parseName s--  docs <- traverse (buildDocComponents s) names--  let sdocs = pprDocs docs-      sdocs' = vcat (intersperse (text "") sdocs)-  unqual <- GHC.getPrintUnqual-  dflags <- getDynFlags-  unit_state <- hsc_units <$> GHC.getSession-  (liftIO . putStrLn . showSDocForUser dflags unit_state unqual) sdocs'--data DocComponents =-  DocComponents-    { docs      :: Maybe [HsDoc GhcRn]   -- ^ subject's haddocks-    , sigAndLoc :: Maybe SDoc          -- ^ type signature + category + location-    , argDocs   :: IntMap (HsDoc GhcRn) -- ^ haddocks for arguments-    }--buildDocComponents :: GHC.GhcMonad m => String -> Name -> m DocComponents-buildDocComponents str name = do-  mbThing <- GHC.lookupName name-  let sigAndLoc = sigAndLocDoc str <$> mbThing-  (docs, argDocs)-    <- either handleGetDocsFailure pure-         =<< GHC.getDocs name--  pure DocComponents{..}---- | Produce output containing the type/kind signature, category, and definition--- location of a TyThing.-sigAndLocDoc :: String -> TyThing -> SDoc-sigAndLocDoc str tyThing =-  let tyThingTyDoc :: TyThing -> SDoc-      tyThingTyDoc = \case-        AnId i                      -> pprSigmaType $ varType i-        AConLike (RealDataCon dc)   -> pprSigmaType $ dataConDisplayType False dc-        AConLike (PatSynCon patSyn) -> pprPatSynType patSyn-        ATyCon tyCon                -> pprSigmaType $ GHC.tyConKind tyCon-        ACoAxiom _                  -> empty--      tyDoc = tyThingTyDoc tyThing-      sigDoc = text str <+> nest 2 (dcolon <+> tyDoc)-      comment =-        hsep [ char '\t' <> text "--"-             , pprTyThingCategory tyThing-             , text "defined" <+> pprNameDefnLoc (getName tyThing)-             ]-   in hang sigDoc 2 comment--pprDocs :: [DocComponents] -> [SDoc]-pprDocs docs-  | null nonEmptyDocs = pprDoc <$> take 1 docs-  -- elide <has no documentation> if there's at least one non-empty doc (#15784)-  | otherwise = pprDoc <$> nonEmptyDocs-  where-    empty DocComponents{docs = mb_decl_docs, argDocs = arg_docs}-      = maybe True null mb_decl_docs && null arg_docs-    nonEmptyDocs = filter (not . empty) docs---- TODO: also print arg docs.-pprDoc :: DocComponents -> SDoc-pprDoc DocComponents{sigAndLoc = mb_sig_loc, docs = mb_decl_docs} =-  maybe-    (text "<has no documentation>")-    formatDoc-    mb_decl_docs-  where-    formatDoc doc =-      vcat [ fromMaybe empty mb_sig_loc -- print contextual info (#19055)-           , pprHsDocStrings $ map hsDocString doc-           ]--handleGetDocsFailure :: GHC.GhcMonad m => GetDocsFailure -> m a-handleGetDocsFailure no_docs = do-  dflags <- getDynFlags-  let msg = showPpr dflags no_docs-  throwGhcException $ case no_docs of-    NameHasNoModule {} -> Sorry msg-    NoDocsInIface {} -> InstallationError msg-    InteractiveName -> ProgramError msg---------------------------------------------------------------------------------- :instances--instancesCmd :: String -> InputT GHCi ()-instancesCmd "" =-  throwGhcException (CmdLineError "syntax: ':instances <type-you-want-instances-for>'")-instancesCmd s = do-  handleSourceError GHC.printException $ do-    ty <- GHC.parseInstanceHead s-    res <- GHC.getInstancesForType ty--    printForUser $ vcat $ map ppr res---------------------------------------------------------------------------------- :load, :add, :reload---- | Sets '-fdefer-type-errors' if 'defer' is true, executes 'load' and unsets--- '-fdefer-type-errors' again if it has not been set before.-wrapDeferTypeErrors :: GHC.GhcMonad m => m a -> m a-wrapDeferTypeErrors load =-  MC.bracket-    (do-      -- Force originalFlags to avoid leaking the associated HscEnv-      !originalFlags <- getDynFlags-      void $ GHC.setProgramDynFlags $-         setGeneralFlag' Opt_DeferTypeErrors originalFlags-      return originalFlags)-    (\originalFlags -> void $ GHC.setProgramDynFlags originalFlags)-    (\_ -> load)--loadModule :: GhciMonad m => [(FilePath, Maybe UnitId, Maybe Phase)] -> m SuccessFlag-loadModule fs = do-  (_, result) <- runAndPrintStats (const Nothing) (loadModule' fs)-  either (liftIO . Exception.throwIO) return result---- | @:load@ command-loadModule_ :: GhciMonad m => [FilePath] -> m ()-loadModule_ fs = void $ loadModule (zip3 fs (repeat Nothing) (repeat Nothing))--loadModuleDefer :: GhciMonad m => [FilePath] -> m ()-loadModuleDefer = wrapDeferTypeErrors . loadModule_--loadModule' :: GhciMonad m => [(FilePath, Maybe UnitId, Maybe Phase)] -> m SuccessFlag-loadModule' files = do-  let (filenames, uids, phases) = unzip3 files-  exp_filenames <- mapM expandPath filenames-  let files' = zip3 exp_filenames uids phases-  targets <- mapM (\(file, uid, phase) -> GHC.guessTarget file uid phase) files'--  -- NOTE: we used to do the dependency anal first, so that if it-  -- fails we didn't throw away the current set of modules.  This would-  -- require some re-working of the GHC interface, so we'll leave it-  -- as a ToDo for now.--  hsc_env <- GHC.getSession-  let !dflags = hsc_dflags hsc_env--  let load_module = do-        -- unload first-        _ <- GHC.abandonAll-        clearCaches--        GHC.setTargets targets-        doLoadAndCollectInfo False LoadAllTargets--  if gopt Opt_GhciLeakCheck dflags-    then do-      -- Grab references to the currently loaded modules so that we can see if-      -- they leak.-      leak_indicators <- liftIO $ getLeakIndicators hsc_env-      success <- load_module-      liftIO $ checkLeakIndicators dflags leak_indicators-      return success-    else-      load_module---- | @:add@ command-addModule :: GhciMonad m => [FilePath] -> m ()-addModule files = do-  revertCAFs -- always revert CAFs on load/add.-  files' <- mapM expandPath files-  targets <- mapM (\m -> GHC.guessTarget m Nothing Nothing) files'-  targets' <- filterM checkTarget targets-  -- remove old targets with the same id; e.g. for :add *M-  mapM_ GHC.removeTarget [ tid | Target { targetId = tid } <- targets' ]-  mapM_ GHC.addTarget targets'-  _ <- doLoadAndCollectInfo False LoadAllTargets-  return ()-  where-    checkTarget :: GhciMonad m => Target -> m Bool-    checkTarget Target { targetId = TargetModule m } = checkTargetModule m-    checkTarget Target { targetId = TargetFile f _ } = checkTargetFile f--    checkTargetModule :: GhciMonad m => ModuleName -> m Bool-    checkTargetModule m = do-      hsc_env <- GHC.getSession-      let home_unit = hsc_home_unit hsc_env-      result <- liftIO $-        Finder.findImportedModule hsc_env m (ThisPkg (homeUnitId home_unit))-      case result of-        Found _ _ -> return True-        _ -> do liftIO $ hPutStrLn stderr ("Module " ++ moduleNameString m ++ " not found")-                failIfExprEvalMode-                return False--    checkTargetFile :: GhciMonad m => String -> m Bool-    checkTargetFile f = do-      exists <- liftIO (doesFileExist f)-      unless exists $ liftIO $ hPutStrLn stderr $ "File " ++ f ++ " not found"-      failIfExprEvalMode-      return exists---- | @:unadd@ command-unAddModule :: GhciMonad m => [FilePath] -> m ()-unAddModule files = do-  files' <- mapM expandPath files-  targets <- mapM (\m -> GHC.guessTarget m Nothing Nothing) files'-  mapM_ GHC.removeTarget [ tid | Target { targetId = tid } <- targets ]-  _ <- doLoadAndCollectInfo False LoadAllTargets-  return ()---- | @:reload@ command-reloadModule :: GhciMonad m => String -> m ()-reloadModule m = do-  session <- GHC.getSession-  let home_unit = homeUnitId (hsc_home_unit session)-  ok <- doLoadAndCollectInfo True (loadTargets home_unit)-  when (failed ok) failIfExprEvalMode-  where-    loadTargets hu | null m    = LoadAllTargets-                   | otherwise = LoadUpTo (mkModule hu (GHC.mkModuleName m))--reloadModuleDefer :: GhciMonad m => String -> m ()-reloadModuleDefer = wrapDeferTypeErrors . reloadModule---- | Load/compile targets and (optionally) collect module-info------ This collects the necessary SrcSpan annotated type information (via--- 'collectInfo') required by the @:all-types@, @:loc-at@, @:type-at@,--- and @:uses@ commands.------ Meta-info collection is not enabled by default and needs to be--- enabled explicitly via @:set +c@.  The reason is that collecting--- the type-information for all sub-spans can be quite expensive, and--- since those commands are designed to be used by editors and--- tooling, it's useless to collect this data for normal GHCi--- sessions.-doLoadAndCollectInfo :: GhciMonad m => Bool -> LoadHowMuch -> m SuccessFlag-doLoadAndCollectInfo retain_context howmuch = do-  doCollectInfo <- isOptionSet CollectInfo--  doLoad retain_context howmuch >>= \case-    Succeeded | doCollectInfo -> do-      mod_summaries <- GHC.mgModSummaries <$> getModuleGraph-      -- MP: :set +c code path only works in single package mode atm, hence-      -- this call to isLoaded is ok. collectInfo needs to be modified further to-      -- work with :set +c so I have punted on that for now.-      loaded <- filterM GHC.isLoaded (map ms_mod_name mod_summaries)-      v <- mod_infos <$> getGHCiState-      !newInfos <- collectInfo v loaded-      modifyGHCiState (\st -> st { mod_infos = newInfos })-      return Succeeded-    flag -> return flag--doLoad :: GhciMonad m => Bool -> LoadHowMuch -> m SuccessFlag-doLoad retain_context howmuch = do-  -- turn off breakpoints before we load: we can't turn them off later, because-  -- the ModBreaks will have gone away.-  discardActiveBreakPoints--  resetLastErrorLocations-  -- Enable buffering stdout and stderr as we're compiling. Keeping these-  -- handles unbuffered will just slow the compilation down, especially when-  -- compiling in parallel.-  MC.bracket (liftIO $ do hSetBuffering stdout LineBuffering-                          hSetBuffering stderr LineBuffering)-             (\_ ->-              liftIO $ do hSetBuffering stdout NoBuffering-                          hSetBuffering stderr NoBuffering) $ \_ -> do-      hmis <- ifaceCache <$> getGHCiState-      ok <- trySuccess $ GHC.loadWithCache (Just hmis) howmuch-      afterLoad ok retain_context-      return ok---afterLoad-  :: GhciMonad m-  => SuccessFlag-  -> Bool   -- keep the remembered_ctx, as far as possible (:reload)-  -> m ()-afterLoad ok retain_context = do-  revertCAFs  -- always revert CAFs on load.-  discardTickArrays-  loaded_mods <- getLoadedModules-  modulesLoadedMsg ok loaded_mods-  graph <- GHC.getModuleGraph-  setContextAfterLoad retain_context (Just graph)--setContextAfterLoad :: GhciMonad m => Bool -> Maybe GHC.ModuleGraph -> m ()-setContextAfterLoad keep_ctxt Nothing = do-  setContextKeepingPackageModules keep_ctxt []-setContextAfterLoad keep_ctxt (Just graph) = do-  -- load a target if one is available, otherwise load the topmost module.-  targets <- GHC.getTargets-  loaded_graph <- filterM is_loaded $ GHC.mgModSummaries' graph-  case [ m | Just m <- map (findTarget loaded_graph) targets ] of-        []    ->-          let graph' = flattenSCCs $ filterToposortToModules $-                GHC.topSortModuleGraph True (GHC.mkModuleGraph loaded_graph) Nothing-          in case graph' of-              [] -> setContextKeepingPackageModules keep_ctxt []-              xs -> load_this (last xs)-        (m:_) ->-          load_this m- where-   is_loaded (GHC.ModuleNode _ ms) = isLoadedModSummary ms-   is_loaded _ = return False--   findTarget mds t-    = case mapMaybe (`matches` t) mds of-        []    -> Nothing-        (m:_) -> Just m--   (GHC.ModuleNode _ summary) `matches` Target { targetId = TargetModule m }-        = if GHC.ms_mod_name summary == m then Just summary else Nothing-   (GHC.ModuleNode _ summary) `matches` Target { targetId = TargetFile f _ }-        | Just f' <- GHC.ml_hs_file (GHC.ms_location summary)   =-          if f == f' then Just summary else Nothing-   _ `matches` _ = Nothing--   load_this summary | m <- GHC.ms_mod summary = do-        is_interp <- GHC.moduleIsInterpreted m-        dflags <- getDynFlags-        let star_ok = is_interp && not (safeLanguageOn dflags)-              -- We import the module with a * iff-              --   - it is interpreted, and-              --   - -XSafe is off (it doesn't allow *-imports)-        let new_ctx | star_ok   = [mkIIModule (GHC.moduleName m)]-                    | otherwise = [mkIIDecl   (GHC.moduleName m)]-        setContextKeepingPackageModules keep_ctxt new_ctx----- | Keep any package modules (except Prelude) when changing the context.-setContextKeepingPackageModules-  :: GhciMonad m-  => Bool                 -- True  <=> keep all of remembered_ctx-                          -- False <=> just keep package imports-  -> [InteractiveImport]  -- new context-  -> m ()-setContextKeepingPackageModules keep_ctx trans_ctx = do--  st <- getGHCiState-  let rem_ctx = remembered_ctx st-  new_rem_ctx <- if keep_ctx then return rem_ctx-                             else keepPackageImports rem_ctx-  setGHCiState st{ remembered_ctx = new_rem_ctx,-                   transient_ctx  = filterSubsumed new_rem_ctx trans_ctx }-  setGHCContextFromGHCiState---- | Filters a list of 'InteractiveImport', clearing out any home package--- imports so only imports from external packages are preserved.  ('IIModule'--- counts as a home package import, because we are only able to bring a--- full top-level into scope when the source is available.)-keepPackageImports-  :: GHC.GhcMonad m => [InteractiveImport] -> m [InteractiveImport]-keepPackageImports = filterM is_pkg_import-  where-     is_pkg_import :: GHC.GhcMonad m => InteractiveImport -> m Bool-     is_pkg_import (IIModule _) = return False-     is_pkg_import (IIDecl d)-         = do pkgqual <- GHC.renameRawPkgQualM (unLoc $ ideclName d) (ideclPkgQual d)-              e <- MC.try $ GHC.findQualifiedModule pkgqual mod_name-              case e :: Either SomeException Module of-                Left _  -> return False-                Right m -> return (not (isMainUnitModule m))-        where-          mod_name = unLoc (ideclName d)----modulesLoadedMsg :: GHC.GhcMonad m => SuccessFlag -> [GHC.ModSummary] -> m ()-modulesLoadedMsg ok mods = do-  dflags <- getDynFlags-  unit_state <- hsc_units <$> GHC.getSession-  unqual <- GHC.getPrintUnqual--  msg <- if gopt Opt_ShowLoadedModules dflags-         then do-               mod_names <- mapM mod_name mods-               let mod_commas-                     | null mods = text "none."-                     | otherwise = hsep (punctuate comma mod_names) <> text "."-               return $ status <> text ", modules loaded:" <+> mod_commas-         else do-               return $ status <> text ","-                    <+> speakNOf (length mods) (text "module") <+> "loaded."--  when (verbosity dflags > 0) $-     liftIO $ putStrLn $ showSDocForUser dflags unit_state unqual msg-  where-    status = case ok of-                  Failed    -> text "Failed"-                  Succeeded -> text "Ok"--    mod_name mod = do-        is_interpreted <- GHC.moduleIsBootOrNotObjectLinkable mod-        return $ if is_interpreted-                 then ppr (GHC.ms_mod mod)-                 else ppr (GHC.ms_mod mod)-                      <+> parens (text $ normalise $ msObjFilePath mod)-                      -- Fix #9887---- | Run an 'ExceptT' wrapped 'GhcMonad' while handling source errors--- and printing 'throwE' strings to 'stderr'. If in expression--- evaluation mode - throw GhcException and exit.-runExceptGhciMonad :: GhciMonad m => ExceptT SDoc m () -> m ()-runExceptGhciMonad act = handleSourceError GHC.printException $-                         either handleErr pure =<<-                         runExceptT act-  where-    handleErr sdoc = do-        dflags <- getDynFlags-        unit_state <- hsc_units <$> GHC.getSession-        liftIO . hPutStrLn stderr . showSDocForUser dflags unit_state alwaysQualify $ sdoc-        failIfExprEvalMode---- | Inverse of 'runExceptT' for \"pure\" computations--- (c.f. 'except' for 'Except')-exceptT :: Applicative m => Either e a -> ExceptT e m a-exceptT = ExceptT . pure---------------------------------------------------------------------------------- | @:type@ command. See also Note [TcRnExprMode] in GHC.Tc.Module.--typeOfExpr :: GhciMonad m => String -> m ()-typeOfExpr str = handleSourceError printErrAndMaybeExit $-    case break isSpace str of-      ("+v", _)    -> printForUser (text "`:type +v' has gone; use `:type' instead")-      ("+d", rest) -> do_it GHC.TM_Default (dropWhile isSpace rest)-      _            -> do_it GHC.TM_Inst    str-  where-    do_it mode expr_str-      = do { ty <- GHC.exprType mode expr_str-           ;    printForUser $ sep [ text expr_str-                                   , nest 2 (dcolon <+> pprSigmaType ty)] }---------------------------------------------------------------------------------- | @:type-at@ command--typeAtCmd :: GhciMonad m => String -> m ()-typeAtCmd str = runExceptGhciMonad $ do-    (span',sample) <- exceptT $ parseSpanArg str-    infos      <- lift $ mod_infos <$> getGHCiState-    (info, ty) <- findType infos span' sample-    lift $ printForUserModInfo (modinfoInfo info)-                               (sep [text sample,nest 2 (dcolon <+> ppr ty)])---------------------------------------------------------------------------------- | @:uses@ command--usesCmd :: GhciMonad m => String -> m ()-usesCmd str = runExceptGhciMonad $ do-    (span',sample) <- exceptT $ parseSpanArg str-    infos  <- lift $ mod_infos <$> getGHCiState-    uses   <- findNameUses infos span' sample-    forM_ uses (liftIO . putStrLn . showSrcSpan)---------------------------------------------------------------------------------- | @:loc-at@ command--locAtCmd :: GhciMonad m => String -> m ()-locAtCmd str = runExceptGhciMonad $ do-    (span',sample) <- exceptT $ parseSpanArg str-    infos    <- lift $ mod_infos <$> getGHCiState-    (_,_,sp) <- findLoc infos span' sample-    liftIO . putStrLn . showSrcSpan $ sp---------------------------------------------------------------------------------- | @:all-types@ command--allTypesCmd :: GhciMonad m => String -> m ()-allTypesCmd _ = runExceptGhciMonad $ do-    infos <- lift $ mod_infos <$> getGHCiState-    forM_ (M.elems infos) $ \mi ->-        forM_ (modinfoSpans mi) (lift . printSpan)-  where-    printSpan span'-      | Just ty <- spaninfoType span' = do-        hsc_env <- GHC.getSession-        let tyInfo = unwords . words $-                     showSDocForUser (hsc_dflags hsc_env)-                                     (hsc_units  hsc_env)-                                     alwaysQualify (pprSigmaType ty)-        liftIO . putStrLn $-            showRealSrcSpan (spaninfoSrcSpan span') ++ ": " ++ tyInfo-      | otherwise = return ()---------------------------------------------------------------------------------- Helpers for locAtCmd/typeAtCmd/usesCmd---- | Parse a span: <module-name/filepath> <sl> <sc> <el> <ec> <string>-parseSpanArg :: String -> Either SDoc (RealSrcSpan,String)-parseSpanArg s = do-    (fp,s0) <- readAsString (skipWs s)-    s0'     <- skipWs1 s0-    (sl,s1) <- readAsInt s0'-    s1'     <- skipWs1 s1-    (sc,s2) <- readAsInt s1'-    s2'     <- skipWs1 s2-    (el,s3) <- readAsInt s2'-    s3'     <- skipWs1 s3-    (ec,s4) <- readAsInt s3'--    trailer <- case s4 of-        [] -> Right ""-        _  -> skipWs1 s4--    let fs    = mkFastString fp-        span' = mkRealSrcSpan (mkRealSrcLoc fs sl sc)-                              -- End column of RealSrcSpan is the column-                              -- after the end of the span.-                              (mkRealSrcLoc fs el (ec + 1))--    return (span',trailer)-  where-    readAsInt :: String -> Either SDoc (Int,String)-    readAsInt "" = Left "Premature end of string while expecting Int"-    readAsInt s0 = case reads s0 of-        [s_rest] -> Right s_rest-        _        -> Left ("Couldn't read" <+> text (show s0) <+> "as Int")--    readAsString :: String -> Either SDoc (String,String)-    readAsString s0-      | '"':_ <- s0 = case reads s0 of-          [s_rest] -> Right s_rest-          _        -> leftRes-      | s_rest@(_:_,_) <- breakWs s0 = Right s_rest-      | otherwise = leftRes-      where-        leftRes = Left ("Couldn't read" <+> text (show s0) <+> "as String")--    skipWs1 :: String -> Either SDoc String-    skipWs1 (c:cs) | isWs c = Right (skipWs cs)-    skipWs1 s0 = Left ("Expected whitespace in" <+> text (show s0))--    isWs    = (`elem` [' ','\t'])-    skipWs  = dropWhile isWs-    breakWs = break isWs----- | Pretty-print \"real\" 'SrcSpan's as--- @<filename>:(<line>,<col>)-(<line-end>,<col-end>)@--- while simply unpacking 'UnhelpfulSpan's-showSrcSpan :: SrcSpan -> String-showSrcSpan (UnhelpfulSpan s)  = unpackFS (unhelpfulSpanFS s)-showSrcSpan (RealSrcSpan spn _) = showRealSrcSpan spn---- | Variant of 'showSrcSpan' for 'RealSrcSpan's-showRealSrcSpan :: RealSrcSpan -> String-showRealSrcSpan spn = concat [ fp, ":(", show sl, ",", show sc-                             , ")-(", show el, ",", show ec, ")"-                             ]-  where-    fp = unpackFS (srcSpanFile spn)-    sl = srcSpanStartLine spn-    sc = srcSpanStartCol  spn-    el = srcSpanEndLine   spn-    -- The end column is the column after the end of the span see the-    -- RealSrcSpan module-    ec = let ec' = srcSpanEndCol    spn in if ec' == 0 then 0 else ec' - 1---------------------------------------------------------------------------------- | @:kind@ command--kindOfType :: GhciMonad m => Bool -> String -> m ()-kindOfType norm str = handleSourceError printErrAndMaybeExit $ do-    (ty, kind) <- GHC.typeKind norm str-    printForUser $ vcat [ text str <+> dcolon <+> pprSigmaType kind-                        , ppWhen norm $ equals <+> pprSigmaType ty ]---------------------------------------------------------------------------------- :quit--quit :: Monad m => String -> m CmdExecOutcome-quit _ = return CleanExit----------------------------------------------------------------------------------- :script---- running a script file #1363--scriptCmd :: String -> InputT GHCi ()-scriptCmd ws = do-  case words' ws of-    [s]    -> runScript s-    _      -> throwGhcException (CmdLineError "syntax:  :script <filename>")---- | A version of 'words' that treats sequences enclosed in double quotes as--- single words and that does not break on backslash-escaped spaces.--- E.g., 'words\' "\"lorem ipsum\" dolor"' and 'words\' "lorem\\ ipsum dolor"'--- yield '["lorem ipsum", "dolor"]'.--- Used to scan for file paths in 'scriptCmd'.-words' :: String -> [String]-words' s = case dropWhile isSpace s of-  "" -> []-  s'@('\"' : _) | [(w, s'')] <- reads s' -> w : words' s''-  s' -> go id s'- where-  go acc []                          = [acc []]-  go acc ('\\' : c : cs) | isSpace c = go (acc . (c :)) cs-  go acc (c : cs) | isSpace c = acc [] : words' cs-                  | otherwise = go (acc . (c :)) cs--runScript :: String    -- ^ filename-           -> InputT GHCi ()-runScript filename = do-  filename' <- expandPath filename-  either_script <- liftIO $ tryIO (openFile filename' ReadMode)-  case either_script of-    Left _err    -> throwGhcException (CmdLineError $ "IO error:  \""++filename++"\" "-                      ++(ioeGetErrorString _err))-    Right script -> do-      st <- getGHCiState-      let prog = progname st-          line = line_number st-      setGHCiState st{progname=filename',line_number=0}-      scriptLoop script-      liftIO $ hClose script-      new_st <- getGHCiState-      setGHCiState new_st{progname=prog,line_number=line}-  where scriptLoop script = do-          res <- runOneCommand handler $ fileLoop script-          case res of-            Nothing -> return ()-            Just s  -> if s-              then scriptLoop script-              else return ()---------------------------------------------------------------------------------- :issafe---- Displaying Safe Haskell properties of a module--isSafeCmd :: GHC.GhcMonad m => String -> m ()-isSafeCmd m =-    case words m of-        [s] | looksLikeModuleName s -> do-            md <- lookupModule s-            isSafeModule md-        [] -> do md <- guessCurrentModule "issafe"-                 isSafeModule md-        _ -> throwGhcException (CmdLineError "syntax:  :issafe <module>")--isSafeModule :: GHC.GhcMonad m => Module -> m ()-isSafeModule m = do-    mb_mod_info <- GHC.getModuleInfo m-    when (isNothing mb_mod_info)-         (throwGhcException $ CmdLineError $ "unknown module: " ++ mname)--    dflags <- getDynFlags-    hsc_env <- GHC.getSession-    let iface = GHC.modInfoIface $ fromJust mb_mod_info-    when (isNothing iface)-         (throwGhcException $ CmdLineError $ "can't load interface file for module: " ++-                                    (GHC.moduleNameString $ GHC.moduleName m))--    (msafe, pkgs) <- GHC.moduleTrustReqs m-    let trust  = showPpr dflags $ getSafeMode $ GHC.mi_trust $ fromJust iface-        pkg    = if packageTrusted hsc_env m then "trusted" else "untrusted"-        (good, bad) = tallyPkgs hsc_env pkgs--    -- print info to user...-    liftIO $ putStrLn $ "Trust type is (Module: " ++ trust ++ ", Package: " ++ pkg ++ ")"-    liftIO $ putStrLn $ "Package Trust: " ++ (if packageTrustOn dflags then "On" else "Off")-    when (not $ S.null good)-         (liftIO $ putStrLn $ "Trusted package dependencies (trusted): " ++-                        (intercalate ", " $ map (showPpr dflags) (S.toList good)))-    case msafe && S.null bad of-        True -> liftIO $ putStrLn $ mname ++ " is trusted!"-        False -> do-            when (not $ null bad)-                 (liftIO $ putStrLn $ "Trusted package dependencies (untrusted): "-                            ++ (intercalate ", " $ map (showPpr dflags) (S.toList bad)))-            liftIO $ putStrLn $ mname ++ " is NOT trusted!"--  where-    mname = GHC.moduleNameString $ GHC.moduleName m--    packageTrusted hsc_env md-        | isHomeModule (hsc_home_unit hsc_env) md = True-        | otherwise = unitIsTrusted $ unsafeLookupUnit (hsc_units hsc_env) (moduleUnit md)--    tallyPkgs hsc_env deps | not (packageTrustOn dflags) = (S.empty, S.empty)-                          | otherwise = S.partition part deps-        where part pkg   = unitIsTrusted $ unsafeLookupUnitId unit_state pkg-              unit_state = hsc_units hsc_env-              dflags     = hsc_dflags hsc_env---------------------------------------------------------------------------------- :browse---- Browsing a module's contents--browseCmd :: GHC.GhcMonad m => Bool -> String -> m ()-browseCmd bang m =-  case words m of-    ['*':s] | looksLikeModuleName s -> do-        md <- wantInterpretedModule s-        browseModule bang md False-    [s] | looksLikeModuleName s -> do-        md <- lookupModule s-        browseModule bang md True-    [] -> do md <- guessCurrentModule ("browse" ++ if bang then "!" else "")-             browseModule bang md True-    _ -> throwGhcException (CmdLineError "syntax:  :browse <module>")--guessCurrentModule :: GHC.GhcMonad m => String -> m Module--- Guess which module the user wants to browse.  Pick--- modules that are interpreted first.  The most--- recently-added module occurs last, it seems.-guessCurrentModule cmd-  = do imports <- GHC.getContext-       when (null imports) $ throwGhcException $-          CmdLineError (':' : cmd ++ ": no current module")-       case (head imports) of-          IIModule m -> GHC.findQualifiedModule NoPkgQual m-          IIDecl d   -> do-            pkgqual <- GHC.renameRawPkgQualM (unLoc $ ideclName d) (ideclPkgQual d)-            GHC.findQualifiedModule pkgqual (unLoc (ideclName d))---- without bang, show items in context of their parents and omit children--- with bang, show class methods and data constructors separately, and---            indicate import modules, to aid qualifying unqualified names--- with sorted, sort items alphabetically-browseModule :: GHC.GhcMonad m => Bool -> Module -> Bool -> m ()-browseModule bang modl exports_only = do-  -- :browse reports qualifiers wrt current context-  unqual <- GHC.getPrintUnqual--  mb_mod_info <- GHC.getModuleInfo modl-  case mb_mod_info of-    Nothing -> throwGhcException (CmdLineError ("unknown module: " ++-                                GHC.moduleNameString (GHC.moduleName modl)))-    Just mod_info -> do-        dflags <- getDynFlags-        let names-               | exports_only = GHC.modInfoExports mod_info-               | otherwise    = GHC.modInfoTopLevelScope mod_info-                                `orElse` []--                -- sort alphabetically name, but putting locally-defined-                -- identifiers first. We would like to improve this; see #1799.-            sorted_names = loc_sort local ++ occ_sort external-                where-                (local,external) = assert (all isExternalName names) $-                                   partition ((==modl) . nameModule) names-                occ_sort = sortBy (compare `on` nameOccName)-                -- try to sort by src location. If the first name in our list-                -- has a good source location, then they all should.-                loc_sort ns-                      | n:_ <- ns, isGoodSrcSpan (nameSrcSpan n)-                      = sortBy (SrcLoc.leftmost_smallest `on` nameSrcSpan) ns-                      | otherwise-                      = occ_sort ns--        mb_things <- mapM GHC.lookupName sorted_names-        let filtered_things = filterOutChildren (\t -> t) (catMaybes mb_things)--        rdr_env <- GHC.getGRE--        let things | bang      = catMaybes mb_things-                   | otherwise = filtered_things-            pretty | bang      = pprTyThing showToHeader-                   | otherwise = pprTyThingInContext showToHeader--            labels  [] = text "-- not currently imported"-            labels  l  = text $ intercalate "\n" $ map qualifier l--            qualifier :: Maybe [ModuleName] -> String-            qualifier  = maybe "-- defined locally"-                             (("-- imported via "++) . intercalate ", "-                               . map GHC.moduleNameString)-            importInfo = RdrName.getGRE_NameQualifier_maybes rdr_env--            modNames :: [[Maybe [ModuleName]]]-            modNames   = map (importInfo . GHC.getName) things--            -- annotate groups of imports with their import modules-            -- the default ordering is somewhat arbitrary, so we group-            -- by header and sort groups; the names themselves should-            -- really come in order of source appearance.. (trac #1799)-            annotate mts = concatMap (\(m,ts)->labels m:ts)-                         $ sortBy cmpQualifiers $ grp mts-              where cmpQualifiers =-                      compare `on` (map (fmap (map (unpackFS . moduleNameFS))) . fst)-            grp []            = []-            grp mts@((m,_):_) = (m,map snd g) : grp ng-              where (g,ng) = partition ((==m).fst) mts--        let prettyThings, prettyThings' :: [SDoc]-            prettyThings = map pretty things-            prettyThings' | bang      = annotate $ zip modNames prettyThings-                          | otherwise = prettyThings-        unit_state <- hsc_units <$> GHC.getSession-        liftIO $ putStrLn $ showSDocForUser dflags unit_state unqual (vcat prettyThings')-        -- ToDo: modInfoInstances currently throws an exception for-        -- package modules.  When it works, we can do this:-        --        $$ vcat (map GHC.pprInstance (GHC.modInfoInstances mod_info))----------------------------------------------------------------------------------- :module---- Setting the module context.  For details on context handling see--- "remembered_ctx" and "transient_ctx" in GhciMonad.--moduleCmd :: GhciMonad m => String -> m ()-moduleCmd str-  | all sensible strs = cmd-  | otherwise = throwGhcException (CmdLineError "syntax:  :module [+/-] [*]M1 ... [*]Mn")-  where-    (cmd, strs) =-        case str of-          '+':stuff -> rest addModulesToContext   stuff-          '-':stuff -> rest remModulesFromContext stuff-          stuff     -> rest setContext            stuff--    rest op stuff = (op as bs, stuffs)-       where (as,bs) = partitionWith starred stuffs-             stuffs  = words stuff--    sensible ('*':m) = looksLikeModuleName m-    sensible m       = looksLikeModuleName m--    starred ('*':m) = Left  (GHC.mkModuleName m)-    starred m       = Right (GHC.mkModuleName m)----- -------------------------------------------------------------------------------- Four ways to manipulate the context:---   (a) :module +<stuff>:     addModulesToContext---   (b) :module -<stuff>:     remModulesFromContext---   (c) :module <stuff>:      setContext---   (d) import <module>...:   addImportToContext--addModulesToContext :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()-addModulesToContext starred unstarred = restoreContextOnFailure $ do-   addModulesToContext_ starred unstarred--addModulesToContext_ :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()-addModulesToContext_ starred unstarred = do-   mapM_ addII (map mkIIModule starred ++ map mkIIDecl unstarred)-   setGHCContextFromGHCiState--remModulesFromContext :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()-remModulesFromContext  starred unstarred = do-   -- we do *not* call restoreContextOnFailure here.  If the user-   -- is trying to fix up a context that contains errors by removing-   -- modules, we don't want GHC to silently put them back in again.-   mapM_ rm (starred ++ unstarred)-   setGHCContextFromGHCiState- where-   rm :: GhciMonad m => ModuleName -> m ()-   rm str = do-     m <- moduleName <$> lookupModuleName str-     let filt = filter ((/=) m . iiModuleName)-     modifyGHCiState $ \st ->-        st { remembered_ctx = filt (remembered_ctx st)-           , transient_ctx  = filt (transient_ctx st) }--setContext :: GhciMonad m => [ModuleName] -> [ModuleName] -> m ()-setContext starred unstarred = restoreContextOnFailure $ do-  modifyGHCiState $ \st -> st { remembered_ctx = [], transient_ctx = [] }-                                -- delete the transient context-  addModulesToContext_ starred unstarred--addImportToContext :: GhciMonad m => ImportDecl GhcPs -> m ()-addImportToContext idecl = restoreContextOnFailure $ do-  addII (IIDecl idecl)   -- #5836-  setGHCContextFromGHCiState---- Util used by addImportToContext and addModulesToContext-addII :: GhciMonad m => InteractiveImport -> m ()-addII iidecl = do-  checkAdd iidecl-  modifyGHCiState $ \st ->-     st { remembered_ctx = addNotSubsumed iidecl (remembered_ctx st)-        , transient_ctx = filter (not . (iidecl `iiSubsumes`))-                                 (transient_ctx st)-        }---- Sometimes we can't tell whether an import is valid or not until--- we finally call 'GHC.setContext'.  e.g.------   import System.IO (foo)------ will fail because System.IO does not export foo.  In this case we--- don't want to store the import in the context permanently, so we--- catch the failure from 'setGHCContextFromGHCiState' and set the--- context back to what it was.------ See #6007----restoreContextOnFailure :: GhciMonad m => m a -> m a-restoreContextOnFailure do_this = do-  st <- getGHCiState-  let rc = remembered_ctx st; tc = transient_ctx st-  do_this `MC.onException` (modifyGHCiState $ \st' ->-     st' { remembered_ctx = rc, transient_ctx = tc })---- -------------------------------------------------------------------------------- Validate a module that we want to add to the context--checkAdd :: GHC.GhcMonad m => InteractiveImport -> m ()-checkAdd ii = do-  dflags <- getDynFlags-  let safe = safeLanguageOn dflags-  case ii of-    IIModule modname-       | safe -> throwGhcException $ CmdLineError "can't use * imports with Safe Haskell"-       | otherwise -> wantInterpretedModuleName modname >> return ()--    IIDecl d -> do-       let modname = unLoc (ideclName d)-       pkgqual <- GHC.renameRawPkgQualM modname (ideclPkgQual d)-       m <- GHC.lookupQualifiedModule pkgqual modname-       when safe $ do-           t <- GHC.isModuleTrusted m-           when (not t) $ throwGhcException $ ProgramError $ ""---- -------------------------------------------------------------------------------- Update the GHC API's view of the context---- | Sets the GHC context from the GHCi state.  The GHC context is--- always set this way, we never modify it incrementally.------ We ignore any imports for which the ModuleName does not currently--- exist.  This is so that the remembered_ctx can contain imports for--- modules that are not currently loaded, perhaps because we just did--- a :reload and encountered errors.------ Prelude is added if not already present in the list.  Therefore to--- override the implicit Prelude import you can say 'import Prelude ()'--- at the prompt, just as in Haskell source.----setGHCContextFromGHCiState :: GhciMonad m => m ()-setGHCContextFromGHCiState = do-  st <- getGHCiState-      -- re-use checkAdd to check whether the module is valid.  If the-      -- module does not exist, we do *not* want to print an error-      -- here, we just want to silently keep the module in the context-      -- until such time as the module reappears again.  So we ignore-      -- the actual exception thrown by checkAdd, using tryBool to-      -- turn it into a Bool.-  iidecls <- filterM (tryBool.checkAdd) (transient_ctx st ++ remembered_ctx st)--  prel_iidecls <- getImplicitPreludeImports iidecls-  valid_prel_iidecls <- filterM (tryBool . checkAdd) prel_iidecls--  extra_imports <- filterM (tryBool . checkAdd) (map IIDecl (extra_imports st))--  GHC.setContext $ iidecls ++ extra_imports ++ valid_prel_iidecls---getImplicitPreludeImports :: GhciMonad m-                          => [InteractiveImport] -> m [InteractiveImport]-getImplicitPreludeImports iidecls = do-  dflags <- GHC.getInteractiveDynFlags-     -- allow :seti to override -XNoImplicitPrelude-  st <- getGHCiState--  -- We add the prelude imports if there are no *-imports, and we also-  -- allow each prelude import to be subsumed by another explicit import-  -- of the same module.  This means that you can override the prelude import-  -- with "import Prelude hiding (map)", for example.-  let prel_iidecls =-         if xopt LangExt.ImplicitPrelude dflags && not (any isIIModule iidecls)-            then [ IIDecl imp-                 | imp <- prelude_imports st-                 , not (any (sameImpModule imp) iidecls) ]-            else []--  return prel_iidecls---- -------------------------------------------------------------------------------- Utils on InteractiveImport--mkIIModule :: ModuleName -> InteractiveImport-mkIIModule = IIModule--mkIIDecl :: ModuleName -> InteractiveImport-mkIIDecl = IIDecl . simpleImportDecl--iiModules :: [InteractiveImport] -> [ModuleName]-iiModules is = [m | IIModule m <- is]--isIIModule :: InteractiveImport -> Bool-isIIModule (IIModule _) = True-isIIModule _ = False--iiModuleName :: InteractiveImport -> ModuleName-iiModuleName (IIModule m) = m-iiModuleName (IIDecl d)   = unLoc (ideclName d)--preludeModuleName :: ModuleName-preludeModuleName = GHC.mkModuleName "Prelude"--sameImpModule :: ImportDecl GhcPs -> InteractiveImport -> Bool-sameImpModule _ (IIModule _) = False -- we only care about imports here-sameImpModule imp (IIDecl d) = unLoc (ideclName d) == unLoc (ideclName imp)--addNotSubsumed :: InteractiveImport-               -> [InteractiveImport] -> [InteractiveImport]-addNotSubsumed i is-  | any (`iiSubsumes` i) is = is-  | otherwise               = i : filter (not . (i `iiSubsumes`)) is---- | @filterSubsumed is js@ returns the elements of @js@ not subsumed--- by any of @is@.-filterSubsumed :: [InteractiveImport] -> [InteractiveImport]-               -> [InteractiveImport]-filterSubsumed is js = filter (\j -> not (any (`iiSubsumes` j) is)) js---- | Returns True if the left import subsumes the right one.  Doesn't--- need to be 100% accurate, conservatively returning False is fine.--- (EXCEPT: (IIModule m) *must* subsume itself, otherwise a panic in--- plusProv will ensue (#5904))------ Note that an IIModule does not necessarily subsume an IIDecl,--- because e.g. a module might export a name that is only available--- qualified within the module itself.------ Note that 'import M' does not necessarily subsume 'import M(foo)',--- because M might not export foo and we want an error to be produced--- in that case.----iiSubsumes :: InteractiveImport -> InteractiveImport -> Bool-iiSubsumes (IIModule m1) (IIModule m2) = m1==m2-iiSubsumes (IIDecl d1) (IIDecl d2)      -- A bit crude-  =  unLoc (ideclName d1) == unLoc (ideclName d2)-     && ideclAs d1 == ideclAs d2-     && (not (isImportDeclQualified (ideclQualified d1)) || isImportDeclQualified (ideclQualified d2))-     && (ideclHiding d1 `hidingSubsumes` ideclHiding d2)-  where-     _                    `hidingSubsumes` Just (False,L _ []) = True-     Just (False, L _ xs) `hidingSubsumes` Just (False,L _ ys)-                                                           = all (`elem` xs) ys-     h1                   `hidingSubsumes` h2              = h1 == h2-iiSubsumes _ _ = False---------------------------------------------------------------------------------- :set---- set options in the interpreter.  Syntax is exactly the same as the--- ghc command line, except that certain options aren't available (-C,--- -E etc.)------ This is pretty fragile: most options won't work as expected.  ToDo:--- figure out which ones & disallow them.--setCmd :: GhciMonad m => String -> m ()-setCmd ""   = showOptions False-setCmd "-a" = showOptions True-setCmd str-  = case getCmd str of-    Right ("args",    rest) ->-        case toArgsNoLoc rest of-            Left err -> liftIO (hPutStrLn stderr err)-            Right args -> setArgs args-    Right ("prog",    rest) ->-        case toArgsNoLoc rest of-            Right [prog] -> setProg prog-            _ -> liftIO (hPutStrLn stderr "syntax: :set prog <progname>")--    Right ("prompt",           rest) ->-        setPromptString setPrompt (dropWhile isSpace rest)-                        "syntax: set prompt <string>"-    Right ("prompt-function",  rest) ->-        setPromptFunc setPrompt $ dropWhile isSpace rest-    Right ("prompt-cont",          rest) ->-        setPromptString setPromptCont (dropWhile isSpace rest)-                        "syntax: :set prompt-cont <string>"-    Right ("prompt-cont-function", rest) ->-        setPromptFunc setPromptCont $ dropWhile isSpace rest--    Right ("editor",  rest) -> setEditor  $ dropWhile isSpace rest-    Right ("stop",    rest) -> setStop    $ dropWhile isSpace rest-    Right ("local-config", rest) ->-        setLocalConfigBehaviour $ dropWhile isSpace rest-    _ -> case toArgsNoLoc str of-         Left err -> liftIO (hPutStrLn stderr err)-         Right wds -> () <$ keepGoing' setOptions wds--setiCmd :: GhciMonad m => String -> m ()-setiCmd ""   = GHC.getInteractiveDynFlags >>= liftIO . showDynFlags False-setiCmd "-a" = GHC.getInteractiveDynFlags >>= liftIO . showDynFlags True-setiCmd str  =-  case toArgsNoLoc str of-    Left err -> liftIO (hPutStrLn stderr err)-    Right wds -> newDynFlags True wds--showOptions :: GhciMonad m => Bool -> m ()-showOptions show_all-  = do st <- getGHCiState-       dflags <- getDynFlags-       let opts = options st-       liftIO $ putStrLn (showSDoc dflags (-              text "options currently set: " <>-              if null opts-                   then text "none."-                   else hsep (map (\o -> char '+' <> text (optToStr o)) opts)-           ))-       getDynFlags >>= liftIO . showDynFlags show_all---showDynFlags :: Bool -> DynFlags -> IO ()-showDynFlags show_all dflags = do-  showLanguages' show_all dflags-  putStrLn $ showSDoc dflags $-     text "GHCi-specific dynamic flag settings:" $$-         nest 2 (vcat (map (setting "-f" "-fno-" gopt) ghciFlags))-  putStrLn $ showSDoc dflags $-     text "other dynamic, non-language, flag settings:" $$-         nest 2 (vcat (map (setting "-f" "-fno-" gopt) others))-  putStrLn $ showSDoc dflags $-     text "warning settings:" $$-         nest 2 (vcat (map (setting "-W" "-Wno-" wopt) DynFlags.wWarningFlags))-  where-        setting :: String -> String -> (flag -> DynFlags -> Bool) -> FlagSpec flag -> SDoc-        setting prefix noPrefix test flag-          | quiet     = empty-          | is_on     = text prefix <> text name-          | otherwise = text noPrefix <> text name-          where name = flagSpecName flag-                f = flagSpecFlag flag-                is_on = test f dflags-                quiet = not show_all && test f default_dflags == is_on--        default_dflags = defaultDynFlags (settings dflags) (llvmConfig dflags)--        (ghciFlags,others)  = partition (\f -> flagSpecFlag f `elem` flgs)-                                        DynFlags.fFlags-        flgs = [ Opt_PrintExplicitForalls-               , Opt_PrintExplicitKinds-               , Opt_PrintUnicodeSyntax-               , Opt_PrintBindResult-               , Opt_BreakOnException-               , Opt_BreakOnError-               , Opt_PrintEvldWithShow-               ]--setArgs, setOptions :: GhciMonad m => [String] -> m ()-setProg, setEditor, setStop :: GhciMonad m => String -> m ()-setLocalConfigBehaviour :: GhciMonad m => String -> m ()--setArgs args = do-  st <- getGHCiState-  wrapper <- mkEvalWrapper (progname st) args-  setGHCiState st { GhciMonad.args = args, evalWrapper = wrapper }--setProg prog = do-  st <- getGHCiState-  wrapper <- mkEvalWrapper prog (GhciMonad.args st)-  setGHCiState st { progname = prog, evalWrapper = wrapper }--setEditor cmd = modifyGHCiState (\st -> st { editor = cmd })--setLocalConfigBehaviour s-  | s == "source" =-      modifyGHCiState (\st -> st { localConfig = SourceLocalConfig })-  | s == "ignore" =-      modifyGHCiState (\st -> st { localConfig = IgnoreLocalConfig })-  | otherwise = throwGhcException-      (CmdLineError "syntax:  :set local-config { source | ignore }")--setStop str@(c:_) | isDigit c-  = do let (nm_str,rest) = break (not.isDigit) str-           nm = read nm_str-       st <- getGHCiState-       let old_breaks = breaks st-       case IntMap.lookup nm old_breaks of-         Nothing ->  printForUser (text "Breakpoint" <+> ppr nm <+>-                                   text "does not exist")-         Just loc -> do-            let new_breaks = IntMap.insert nm-                                loc { onBreakCmd = dropWhile isSpace rest }-                                old_breaks-            setGHCiState st{ breaks = new_breaks }-setStop cmd = modifyGHCiState (\st -> st { stop = cmd })--setPrompt :: GhciMonad m => PromptFunction -> m ()-setPrompt v = modifyGHCiState (\st -> st {prompt = v})--setPromptCont :: GhciMonad m => PromptFunction -> m ()-setPromptCont v = modifyGHCiState (\st -> st {prompt_cont = v})--setPromptFunc :: GHC.GhcMonad m => (PromptFunction -> m ()) -> String -> m ()-setPromptFunc fSetPrompt s = do-    -- We explicitly annotate the type of the expression to ensure-    -- that unsafeCoerce# is passed the exact type necessary rather-    -- than a more general one-    let exprStr = "(" ++ s ++ ") :: [String] -> Int -> IO String"-    (HValue funValue) <- GHC.compileExpr exprStr-    fSetPrompt (convertToPromptFunction $ unsafeCoerce funValue)-    where-      convertToPromptFunction :: ([String] -> Int -> IO String)-                              -> PromptFunction-      convertToPromptFunction func = (\mods line -> liftIO $-                                       liftM text (func mods line))--setPromptString :: MonadIO m-                => (PromptFunction -> m ()) -> String -> String -> m ()-setPromptString fSetPrompt value err = do-  if null value-    then liftIO $ hPutStrLn stderr $ err-    else case value of-           ('\"':_) ->-             case reads value of-               [(value', xs)] | all isSpace xs ->-                 setParsedPromptString fSetPrompt value'-               _ -> liftIO $ hPutStrLn stderr-                             "Can't parse prompt string. Use Haskell syntax."-           _ ->-             setParsedPromptString fSetPrompt value--setParsedPromptString :: MonadIO m-                      => (PromptFunction -> m ()) ->  String -> m ()-setParsedPromptString fSetPrompt s = do-  case (checkPromptStringForErrors s) of-    Just err ->-      liftIO $ hPutStrLn stderr err-    Nothing ->-      fSetPrompt $ generatePromptFunctionFromString s--setOptions wds =-   do -- first, deal with the GHCi opts (+s, +t, etc.)-      let (plus_opts, minus_opts)  = partitionWith isPlus wds-      mapM_ setOpt plus_opts-      -- then, dynamic flags-      when (not (null minus_opts)) $ newDynFlags False minus_opts---- | newDynFlags will *not* read package environment files, therefore we--- use 'parseDynamicFlagsCmdLine' rather than 'parseDynamicFlags'. This--- function is called very often and results in repeatedly loading--- environment files (see #19650)-newDynFlags :: GhciMonad m => Bool -> [String] -> m ()-newDynFlags interactive_only minus_opts = do-      let lopts = map noLoc minus_opts--      logger <- getLogger-      idflags0 <- GHC.getInteractiveDynFlags-      (idflags1, leftovers, warns) <- DynFlags.parseDynamicFlagsCmdLine idflags0 lopts--      liftIO $ handleFlagWarnings logger (initDiagOpts idflags1) warns-      when (not $ null leftovers)-           (throwGhcException . CmdLineError-            $ "Some flags have not been recognized: "-            ++ (concat . intersperse ", " $ map unLoc leftovers))--      when (interactive_only && packageFlagsChanged idflags1 idflags0) $ do-          liftIO $ hPutStrLn stderr "cannot set package flags with :seti; use :set"-      GHC.setInteractiveDynFlags idflags1-      installInteractivePrint (interactivePrint idflags1) False--      dflags0 <- getDynFlags--      when (not interactive_only) $ do-        (dflags1, _, _) <- liftIO $ DynFlags.parseDynamicFlagsCmdLine dflags0 lopts-        must_reload <- GHC.setProgramDynFlags dflags1--        -- if the package flags changed, reset the context and link-        -- the new packages.-        hsc_env <- GHC.getSession-        let dflags2 = hsc_dflags hsc_env-        let interp  = hscInterp hsc_env-        when (packageFlagsChanged dflags2 dflags0) $ do-          when (verbosity dflags2 > 0) $-            liftIO . putStrLn $-              "package flags have changed, resetting and loading new packages..."-          -- Clear caches and eventually defined breakpoints. (#1620)-          clearCaches-          when must_reload $ do-            let units = preloadUnits (hsc_units hsc_env)-            liftIO $ Loader.loadPackages interp hsc_env units-          -- package flags changed, we can't re-use any of the old context-          setContextAfterLoad False Nothing-          -- and copy the package flags to the interactive DynFlags-          idflags <- GHC.getInteractiveDynFlags-          GHC.setInteractiveDynFlags-              idflags{ packageFlags = packageFlags dflags2 }--        let ld0length   = length $ ldInputs dflags0-            fmrk0length = length $ cmdlineFrameworks dflags0--            newLdInputs     = drop ld0length (ldInputs dflags2)-            newCLFrameworks = drop fmrk0length (cmdlineFrameworks dflags2)--            dflags'  = dflags2 { ldInputs = newLdInputs-                               , cmdlineFrameworks = newCLFrameworks-                               }-            hsc_env' = hscSetFlags dflags' hsc_env--        when (not (null newLdInputs && null newCLFrameworks)) $-          liftIO $ Loader.loadCmdLineLibs (hscInterp hsc_env') hsc_env'--      return ()---unsetOptions :: GhciMonad m => String -> m ()-unsetOptions str-  =   -- first, deal with the GHCi opts (+s, +t, etc.)-     let opts = words str-         (minus_opts, rest1) = partition isMinus opts-         (plus_opts, rest2)  = partitionWith isPlus rest1-         (other_opts, rest3) = partition (`elem` map fst defaulters) rest2--         defaulters =-           [ ("args"   , setArgs default_args)-           , ("prog"   , setProg default_progname)-           , ("prompt"     , setPrompt default_prompt)-           , ("prompt-cont", setPromptCont default_prompt_cont)-           , ("editor" , liftIO findEditor >>= setEditor)-           , ("stop"   , setStop default_stop)-           ]--         no_flag ('-':'f':rest) = return ("-fno-" ++ rest)-         no_flag ('-':'X':rest) = return ("-XNo" ++ rest)-         no_flag f = throwGhcException (ProgramError ("don't know how to reverse " ++ f))--     in if (not (null rest3))-           then liftIO (putStrLn ("unknown option: '" ++ head rest3 ++ "'"))-           else do-             mapM_ (fromJust.flip lookup defaulters) other_opts--             mapM_ unsetOpt plus_opts--             no_flags <- mapM no_flag minus_opts-             when (not (null no_flags)) $ newDynFlags False no_flags--isMinus :: String -> Bool-isMinus ('-':_) = True-isMinus _ = False--isPlus :: String -> Either String String-isPlus ('+':opt) = Left opt-isPlus other     = Right other--setOpt, unsetOpt :: GhciMonad m => String -> m ()--setOpt str-  = case strToGHCiOpt str of-        Nothing -> liftIO (putStrLn ("unknown option: '" ++ str ++ "'"))-        Just o  -> setOption o--unsetOpt str-  = case strToGHCiOpt str of-        Nothing -> liftIO (putStrLn ("unknown option: '" ++ str ++ "'"))-        Just o  -> unsetOption o--strToGHCiOpt :: String -> (Maybe GHCiOption)-strToGHCiOpt "m" = Just Multiline-strToGHCiOpt "s" = Just ShowTiming-strToGHCiOpt "t" = Just ShowType-strToGHCiOpt "r" = Just RevertCAFs-strToGHCiOpt "c" = Just CollectInfo-strToGHCiOpt _   = Nothing--optToStr :: GHCiOption -> String-optToStr Multiline  = "m"-optToStr ShowTiming = "s"-optToStr ShowType   = "t"-optToStr RevertCAFs = "r"-optToStr CollectInfo = "c"----- ------------------------------------------------------------------------------ :show--showCmd :: forall m. GhciMonad m => String -> m ()-showCmd ""   = showOptions False-showCmd "-a" = showOptions True-showCmd str = do-    st <- getGHCiState-    dflags <- getDynFlags-    hsc_env <- GHC.getSession--    let lookupCmd :: String -> Maybe (m ())-        lookupCmd name = lookup name $ map (\(_,b,c) -> (b,c)) cmds--        -- (show in help?, command name, action)-        action :: String -> m () -> (Bool, String, m ())-        action name m = (True, name, m)--        hidden :: String -> m () -> (Bool, String, m ())-        hidden name m = (False, name, m)--        cmds =-            [ action "args"       $ liftIO $ putStrLn (show (GhciMonad.args st))-            , action "prog"       $ liftIO $ putStrLn (show (progname st))-            , action "editor"     $ liftIO $ putStrLn (show (editor st))-            , action "stop"       $ liftIO $ putStrLn (show (stop st))-            , action "imports"    $ showImports-            , action "modules"    $ showModules-            , action "bindings"   $ showBindings-            , action "linker"     $ do-               msg <- liftIO $ Loader.showLoaderState (hscInterp hsc_env)-               putLogMsgM MCDump noSrcSpan msg-            , action "breaks"     $ showBkptTable-            , action "context"    $ showContext-            , action "packages"   $ showUnits-            , action "paths"      $ showPaths-            , action "language"   $ showLanguages-            , hidden "languages"  $ showLanguages -- backwards compat-            , hidden "lang"       $ showLanguages -- useful abbreviation-            , action "targets"    $ showTargets-            ]--    case words str of-      [w] | Just action <- lookupCmd w -> action--      _ -> let helpCmds = [ text name | (True, name, _) <- cmds ]-           in throwGhcException $ CmdLineError $ showSDoc dflags-              $ hang (text "syntax:") 4-              $ hang (text ":show") 6-              $ brackets (fsep $ punctuate (text " |") helpCmds)--showiCmd :: GHC.GhcMonad m => String -> m ()-showiCmd str = do-  case words str of-        ["languages"]  -> showiLanguages -- backwards compat-        ["language"]   -> showiLanguages-        ["lang"]       -> showiLanguages -- useful abbreviation-        _ -> throwGhcException (CmdLineError ("syntax:  :showi language"))--showImports :: GhciMonad m => m ()-showImports = do-  st <- getGHCiState-  dflags <- getDynFlags-  let rem_ctx   = reverse (remembered_ctx st)-      trans_ctx = transient_ctx st--      show_one (IIModule star_m)-          = ":module +*" ++ moduleNameString star_m-      show_one (IIDecl imp) = showPpr dflags imp--  prel_iidecls <- getImplicitPreludeImports (rem_ctx ++ trans_ctx)--  let show_prel p = show_one p ++ " -- implicit"-      show_extra p = show_one (IIDecl p) ++ " -- fixed"--      trans_comment s = s ++ " -- added automatically" :: String-  ---  liftIO $ mapM_ putStrLn (map show_one rem_ctx ++-                           map (trans_comment . show_one) trans_ctx ++-                           map show_prel prel_iidecls ++-                           map show_extra (extra_imports st))--showModules :: GHC.GhcMonad m => m ()-showModules = do-  loaded_mods <- getLoadedModules-        -- we want *loaded* modules only, see #1734-  let show_one ms = do m <- GHC.showModule ms; liftIO (putStrLn m)-  mapM_ show_one loaded_mods--getLoadedModules :: GHC.GhcMonad m => m [GHC.ModSummary]-getLoadedModules = do-  graph <- GHC.getModuleGraph-  filterM isLoadedModSummary (GHC.mgModSummaries graph)--showBindings :: GHC.GhcMonad m => m ()-showBindings = do-    bindings <- GHC.getBindings-    (insts, finsts) <- GHC.getInsts-    let idocs  = map GHC.pprInstanceHdr insts-        fidocs = map GHC.pprFamInst finsts-        binds = filter (not . isDerivedOccName . getOccName) bindings -- #12525-        -- See Note [Filter bindings]-    docs <- mapM makeDoc (reverse binds)-                  -- reverse so the new ones come last-    mapM_ printForUserPartWay (docs ++ idocs ++ fidocs)-  where-    makeDoc (AnId i) = pprTypeAndContents i-    makeDoc tt = do-        mb_stuff <- GHC.getInfo False (getName tt)-        return $ maybe (text "") pprTT mb_stuff--    pprTT :: (TyThing, Fixity, [GHC.ClsInst], [GHC.FamInst], SDoc) -> SDoc-    pprTT (thing, fixity, _cls_insts, _fam_insts, _docs)-      = pprTyThing showToHeader thing-        $$ showFixity thing fixity---printTyThing :: GHC.GhcMonad m => TyThing -> m ()-printTyThing tyth = printForUser (pprTyThing showToHeader tyth)--isLoadedModSummary :: GHC.GhcMonad m => ModSummary -> m Bool-isLoadedModSummary ms = GHC.isLoadedModule (ms_unitid ms) (ms_mod_name ms)--{--Note [Filter bindings]-~~~~~~~~~~~~~~~~~~~~~~-If we don't filter the bindings returned by the function GHC.getBindings,-then the :show bindings command will also show unwanted bound names,-internally generated by GHC, eg:-    $tcFoo :: GHC.Types.TyCon = _-    $trModule :: GHC.Unit.Module = _ .--The filter was introduced as a fix for #12525 [1]. Comment:1 [2] to this-ticket contains an analysis of the situation and suggests the solution-implemented above.--The same filter was also implemented to fix #11051 [3]. See the-Note [What to show to users] in GHC.Runtime.Eval--[1] https://gitlab.haskell.org/ghc/ghc/issues/12525-[2] https://gitlab.haskell.org/ghc/ghc/issues/12525#note_123489-[3] https://gitlab.haskell.org/ghc/ghc/issues/11051--}---showBkptTable :: GhciMonad m => m ()-showBkptTable = do-  st <- getGHCiState-  printForUser $ prettyLocations (breaks st)--showContext :: GHC.GhcMonad m => m ()-showContext = do-   resumes <- GHC.getResumeContext-   printForUser $ vcat (map pp_resume (reverse resumes))-  where-   pp_resume res =-        text "--> " <> text (GHC.resumeStmt res)-        $$ nest 2 (pprStopped res)--pprStopped :: GHC.Resume -> SDoc-pprStopped res =-  text "Stopped in"-    <+> ((case mb_mod_name of-           Nothing -> empty-           Just mod_name -> text (moduleNameString mod_name) <> char '.')-         <> text (GHC.resumeDecl res))-    <> char ',' <+> ppr (GHC.resumeSpan res)- where-  mb_mod_name = moduleName <$> GHC.breakInfo_module <$> GHC.resumeBreakInfo res--showUnits :: GHC.GhcMonad m => m ()-showUnits = do-  dflags <- getDynFlags-  let pkg_flags = packageFlags dflags-  liftIO $ putStrLn $ showSDoc dflags $-    text ("active package flags:"++if null pkg_flags then " none" else "") $$-      nest 2 (vcat (map pprFlag pkg_flags))--showPaths :: GHC.GhcMonad m => m ()-showPaths = do-  dflags <- getDynFlags-  liftIO $ do-    cwd <- getCurrentDirectory-    putStrLn $ showSDoc dflags $-      text "current working directory: " $$-        nest 2 (text cwd)-    let ipaths = importPaths dflags-    putStrLn $ showSDoc dflags $-      text ("module import search paths:"++if null ipaths then " none" else "") $$-        nest 2 (vcat (map text ipaths))--showLanguages :: GHC.GhcMonad m => m ()-showLanguages = getDynFlags >>= liftIO . showLanguages' False--showiLanguages :: GHC.GhcMonad m => m ()-showiLanguages = GHC.getInteractiveDynFlags >>= liftIO . showLanguages' False--showLanguages' :: Bool -> DynFlags -> IO ()-showLanguages' show_all dflags =-  putStrLn $ showSDoc dflags $ vcat-     [ text "base language is: " <>-         case lang of-           Haskell98   -> text "Haskell98"-           Haskell2010 -> text "Haskell2010"-           GHC2021     -> text "GHC2021"-     , (if show_all then text "all active language options:"-                    else text "with the following modifiers:") $$-          nest 2 (vcat (map (setting xopt) DynFlags.xFlags))-     ]-  where-   setting test flag-          | quiet     = empty-          | is_on     = text "-X" <> text name-          | otherwise = text "-XNo" <> text name-          where name = flagSpecName flag-                f = flagSpecFlag flag-                is_on = test f dflags-                quiet = not show_all && test f default_dflags == is_on--   default_dflags =-       defaultDynFlags (settings dflags) (llvmConfig dflags) `lang_set` Just lang--   lang = fromMaybe GHC2021 (language dflags)---showTargets :: GHC.GhcMonad m => m ()-showTargets = mapM_ showTarget =<< GHC.getTargets-  where-    showTarget :: GHC.GhcMonad m => Target -> m ()-    showTarget Target { targetId = TargetFile f _ } = liftIO (putStrLn f)-    showTarget Target { targetId = TargetModule m } =-      liftIO (putStrLn $ moduleNameString m)---- -------------------------------------------------------------------------------- Completion--completeCmd :: String -> GHCi ()-completeCmd argLine0 = case parseLine argLine0 of-    Just ("repl", resultRange, left) -> do-        (unusedLine,compls) <- ghciCompleteWord (reverse left,"")-        let compls' = takeRange resultRange compls-        liftIO . putStrLn $ unwords [ show (length compls'), show (length compls), show (reverse unusedLine) ]-        forM_ (takeRange resultRange compls) $ \(Completion r _ _) -> do-            liftIO $ print r-    _ -> throwGhcException (CmdLineError "Syntax: :complete repl [<range>] <quoted-string-to-complete>")-  where-    parseLine argLine-        | null argLine = Nothing-        | null rest1   = Nothing-        | otherwise    = (,,) dom <$> resRange <*> s-      where-        (dom, rest1) = breakSpace argLine-        (rng, rest2) = breakSpace rest1-        resRange | head rest1 == '"' = parseRange ""-                 | otherwise         = parseRange rng-        s | head rest1 == '"' = readMaybe rest1 :: Maybe String-          | otherwise         = readMaybe rest2-        breakSpace = fmap (dropWhile isSpace) . break isSpace--    takeRange (lb,ub) = maybe id (drop . pred) lb . maybe id take ub--    -- syntax: [n-][m] with semantics "drop (n-1) . take m"-    parseRange :: String -> Maybe (Maybe Int,Maybe Int)-    parseRange s = case span isDigit s of-                   (_, "") ->-                       -- upper limit only-                       Just (Nothing, bndRead s)-                   (s1, '-' : s2)-                    | all isDigit s2 ->-                       Just (bndRead s1, bndRead s2)-                   _ ->-                       Nothing-      where-        bndRead x = if null x then Nothing else Just (read x)----completeGhciCommand, completeMacro, completeIdentifier, completeModule,-    completeSetModule, completeSeti, completeShowiOptions,-    completeHomeModule, completeSetOptions, completeShowOptions,-    completeHomeModuleOrFile, completeExpression, completeBreakpoint-    :: GhciMonad m => CompletionFunc m---- | Provide completions for last word in a given string.------ Takes a tuple of two strings.  First string is a reversed line to be--- completed.  Second string is likely unused, 'completeCmd' always passes an--- empty string as second item in tuple.-ghciCompleteWord :: CompletionFunc GHCi-ghciCompleteWord line@(left,_) = case firstWord of-    -- If given string starts with `:` colon, and there is only one following-    -- word then provide REPL command completions.  If there is more than one-    -- word complete either filename or builtin ghci commands or macros.-    ':':cmd     | null rest     -> completeGhciCommand line-                | otherwise     -> do-                        completion <- lookupCompletion cmd-                        completion line-    -- If given string starts with `import` keyword provide module name-    -- completions-    "import"    -> completeModule line-    -- otherwise provide identifier completions-    _           -> completeExpression line-  where-    (firstWord,rest) = break isSpace $ dropWhile isSpace $ reverse left-    lookupCompletion ('!':_) = return completeFilename-    lookupCompletion c = do-        maybe_cmd <- lookupCommand' c-        case maybe_cmd of-            Just cmd -> return (cmdCompletionFunc cmd)-            Nothing  -> return completeFilename--completeGhciCommand = wrapCompleter " " $ \w -> do-  macros <- ghci_macros <$> getGHCiState-  cmds   <- ghci_commands `fmap` getGHCiState-  let macro_names = map (':':) . map cmdName $ macros-  let command_names = map (':':) . map cmdName $ filter (not . cmdHidden) cmds-  let{ candidates = case w of-      ':' : ':' : _ -> map (':':) command_names-      _ -> nub $ macro_names ++ command_names }-  return $ filter (w `isPrefixOptOf`) candidates--completeMacro = wrapIdentCompleter $ \w -> do-  cmds <- ghci_macros <$> getGHCiState-  return (filter (w `isPrefixOf`) (map cmdName cmds))--completeIdentifier line@(left, _) =-  -- Note: `left` is a reversed input-  case left of-    ('.':_)  -> wrapCompleter (specials ++ spaces) complete line-               -- operator or qualification-    (x:_) | isSymbolChar x -> wrapCompleter' (\c -> c `elem` (specials ++ spaces) || not (isSymbolChar c))-                                 complete line         -- operator-    _                      -> wrapIdentCompleter complete line-  where-    complete w = do-      rdrs <- GHC.getRdrNamesInScope-      dflags <- GHC.getSessionDynFlags-      return (filter (w `isPrefixOf`) (map (showPpr dflags) rdrs))---- TAB-completion for the :break command.--- Build and return a list of breakpoint identifiers with a given prefix.--- See Note [Tab-completion for :break]-completeBreakpoint = wrapCompleter spaces $ \w -> do          -- #3000-    -- bid ~ breakpoint identifier = a name of a function that is-    --       eligible to set a breakpoint.-    let (mod_str, _, _) = splitIdent w-    bids_mod_breaks <- bidsFromModBreaks mod_str-    bids_inscopes <- bidsFromInscopes-    pure $ nub $ filter (isPrefixOf w) $ bids_mod_breaks ++ bids_inscopes-  where-    -- Extract all bids from ModBreaks for a given module name prefix-    bidsFromModBreaks :: GhciMonad m => String -> m [String]-    bidsFromModBreaks mod_pref = do-        imods <- interpretedHomeMods-        let pmods = filter ((isPrefixOf mod_pref) . showModule) imods-        nonquals <- case null mod_pref of-          -- If the prefix is empty, then for functions declared in a module-          -- in scope, don't qualify the function name.-          -- (eg: `main` instead of `Main.main`)-            True -> do-                imports <- GHC.getContext-                pure [ m | IIModule m <- imports]-            False -> return []-        bidss <- mapM (bidsByModule nonquals) pmods-        pure $ concat bidss--    -- Return a list of interpreted home modules-    interpretedHomeMods :: GhciMonad m => m [Module]-    interpretedHomeMods = do-        graph <- GHC.getModuleGraph-        let hmods = ms_mod <$> GHC.mgModSummaries graph-        filterM GHC.moduleIsInterpreted hmods--    -- Return all possible bids for a given Module-    bidsByModule :: GhciMonad m => [ModuleName] -> Module -> m [String]-    bidsByModule nonquals mod = do-      (_, decls) <- getModBreak mod-      let bids = nub $ declPath <$> elems decls-      pure $ case (moduleName mod) `elem` nonquals of-              True  -> bids-              False -> (combineModIdent (showModule mod)) <$> bids--    -- Extract all bids from all top-level identifiers in scope.-    bidsFromInscopes :: GhciMonad m => m [String]-    bidsFromInscopes = do-        dflags <- getDynFlags-        rdrs <- GHC.getRdrNamesInScope-        inscopess <- mapM createInscope $ (showSDoc dflags . ppr) <$> rdrs-        imods <- interpretedHomeMods-        let topLevels = filter ((`elem` imods) . snd) $ concat inscopess-        bidss <- mapM (addNestedDecls) topLevels-        pure $ concat bidss--    -- Return a list of (bid,module) for a single top-level in-scope identifier-    createInscope :: GhciMonad m => String -> m [(String, Module)]-    createInscope str_rdr = do-        names <- GHC.parseName str_rdr-        pure $ zip (repeat str_rdr) $ GHC.nameModule <$> names--    -- For every top-level identifier in scope, add the bids of the nested-    -- declarations. See Note [ModBreaks.decls] in GHC.ByteCode.Types-    addNestedDecls :: GhciMonad m => (String, Module) -> m [String]-    addNestedDecls (ident, mod) = do-        (_, decls) <- getModBreak mod-        let (mod_str, topLvl, _) = splitIdent ident-            ident_decls = filter ((topLvl ==) . head) $ elems decls-            bids = nub $ declPath <$> ident_decls-        pure $ map (combineModIdent mod_str) bids--completeModule = wrapIdentCompleterMod $ \w -> do-  hsc_env <- GHC.getSession-  let pkg_mods = allVisibleModules (hsc_units hsc_env)-  loaded_mods <- liftM (map GHC.ms_mod_name) getLoadedModules-  return $ filter (w `isPrefixOf`)-        $ map (showPpr (hsc_dflags hsc_env)) $ loaded_mods ++ pkg_mods--completeSetModule = wrapIdentCompleterWithModifier "+-" $ \m w -> do-  hsc_env <- GHC.getSession-  modules <- case m of-    Just '-' -> do-      imports <- GHC.getContext-      return $ map iiModuleName imports-    _ -> do-      let pkg_mods = allVisibleModules (hsc_units hsc_env)-      loaded_mods <- liftM (map GHC.ms_mod_name) getLoadedModules-      return $ loaded_mods ++ pkg_mods-  return $ filter (w `isPrefixOf`) $ map (showPpr (hsc_dflags hsc_env)) modules--completeHomeModule = wrapIdentCompleterMod listHomeModules--listHomeModules :: GHC.GhcMonad m => String -> m [String]-listHomeModules w = do-    g <- GHC.getModuleGraph-    let home_mods = map GHC.ms_mod_name (GHC.mgModSummaries g)-    dflags <- getDynFlags-    return $ sort $ filter (w `isPrefixOf`)-            $ map (showPpr dflags) home_mods--completeSetOptions = wrapCompleter flagWordBreakChars $ \w -> do-  return (filter (w `isPrefixOf`) opts)-    where opts = "args":"prog":"prompt":"prompt-cont":"prompt-function":-                 "prompt-cont-function":"editor":"stop":flagList-          flagList = map head $ group $ sort allNonDeprecatedFlags--completeSeti = wrapCompleter flagWordBreakChars $ \w -> do-  return (filter (w `isPrefixOf`) flagList)-    where flagList = map head $ group $ sort allNonDeprecatedFlags--completeShowOptions = wrapCompleter flagWordBreakChars $ \w -> do-  return (filter (w `isPrefixOf`) opts)-    where opts = ["args", "prog", "editor", "stop",-                     "modules", "bindings", "linker", "breaks",-                     "context", "packages", "paths", "language", "imports"]--completeShowiOptions = wrapCompleter flagWordBreakChars $ \w -> do-  return (filter (w `isPrefixOf`) ["language"])--completeHomeModuleOrFile = completeWord Nothing filenameWordBreakChars-                $ unionComplete (fmap (map simpleCompletion) . listHomeModules)-                            listFiles--unionComplete :: Monad m => (a -> m [b]) -> (a -> m [b]) -> a -> m [b]-unionComplete f1 f2 line = do-  cs1 <- f1 line-  cs2 <- f2 line-  return (cs1 ++ cs2)--wrapCompleter :: Monad m => String -> (String -> m [String]) -> CompletionFunc m-wrapCompleter breakChars = wrapCompleter' (`elem` breakChars)--wrapCompleter' :: Monad m => (Char -> Bool) -> (String -> m [String]) -> CompletionFunc m-wrapCompleter' breakPred fun = completeWord' Nothing breakPred-    $ fmap (map simpleCompletion . nubSort) . fun--wrapIdentCompleter :: Monad m => (String -> m [String]) -> CompletionFunc m-wrapIdentCompleter = wrapCompleter' word_break_chars_pred--wrapIdentCompleterMod :: Monad m => (String -> m [String]) -> CompletionFunc m-wrapIdentCompleterMod = wrapCompleter' go-  where-    go '.' = False -- Treated specially since it is a seperator for module qualifiers-    go c = word_break_chars_pred c--wrapIdentCompleterWithModifier-  :: Monad m-  => String -> (Maybe Char -> String -> m [String]) -> CompletionFunc m-wrapIdentCompleterWithModifier modifChars fun = completeWordWithPrev Nothing word_break_chars-    $ \rest -> fmap (map simpleCompletion . nubSort) . fun (getModifier rest)- where-  getModifier = find (`elem` modifChars)---- | Return a list of visible module names for autocompletion.--- (NB: exposed != visible)-allVisibleModules :: UnitState -> [ModuleName]-allVisibleModules unit_state = listVisibleModuleNames unit_state--completeExpression = completeQuotedWord (Just '\\') "\"" listFiles-                        completeIdentifier---{--Note [Tab-completion for :break]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-In tab-completion for the `:break` command, only those-identifiers should be shown, that are accepted in the-`:break` command. Hence these identifiers must be--- defined in an interpreted module-- listed in a `ModBreaks` value as a possible breakpoint.--The identifiers may be qualified or unqualified.--To get all possible top-level breakpoints for tab-completion-with the correct qualification do:--1. Build a list called `bids_mod_breaks` of identifier names eligible-for setting breakpoints: For every interpreted module with the-correct module prefix read all identifier names from the `decls` field-of the `ModBreaks` array.--2. Build a list called `bids_inscopess` of identifiers in scope:-Take all RdrNames in scope, and filter by interpreted modules.-Fore each of these top-level identifiers add from the `ModBreaks`-arrays the available identifiers of the nested functions.--3.) Combine both lists, filter by the given prefix, and remove duplicates.--}---- -------------------------------------------------------------------------------- commands for debugger--sprintCmd, printCmd, forceCmd :: GHC.GhcMonad m => String -> m ()-sprintCmd = pprintClosureCommand False False-printCmd  = pprintClosureCommand True False-forceCmd  = pprintClosureCommand False True--stepCmd :: GhciMonad m => String -> m ()-stepCmd arg = withSandboxOnly ":step" $ step arg-  where-  step []         = doContinue (const True) GHC.SingleStep-  step expression = runStmt expression GHC.SingleStep >> return ()--stepLocalCmd :: GhciMonad m => String -> m ()-stepLocalCmd arg = withSandboxOnly ":steplocal" $ step arg-  where-  step expr-   | not (null expr) = stepCmd expr-   | otherwise = do-      mb_span <- getCurrentBreakSpan-      case mb_span of-        Nothing  -> stepCmd []-        Just (UnhelpfulSpan _) -> liftIO $ putStrLn (            -- #14690-           ":steplocal is not possible." ++-           "\nCannot determine current top-level binding after " ++-           "a break on error / exception.\nUse :stepmodule.")-        Just loc -> do-           md <- fromMaybe (panic "stepLocalCmd") <$> getCurrentBreakModule-           current_toplevel_decl <- enclosingTickSpan md loc-           doContinue (`isSubspanOf` RealSrcSpan current_toplevel_decl Strict.Nothing) GHC.SingleStep--stepModuleCmd :: GhciMonad m => String -> m ()-stepModuleCmd arg = withSandboxOnly ":stepmodule" $ step arg-  where-  step expr-   | not (null expr) = stepCmd expr-   | otherwise = do-      mb_span <- getCurrentBreakSpan-      case mb_span of-        Nothing  -> stepCmd []-        Just pan -> do-           let f some_span = srcSpanFileName_maybe pan == srcSpanFileName_maybe some_span-           doContinue f GHC.SingleStep---- | Returns the span of the largest tick containing the srcspan given-enclosingTickSpan :: GhciMonad m => Module -> SrcSpan -> m RealSrcSpan-enclosingTickSpan _ (UnhelpfulSpan _) = panic "enclosingTickSpan UnhelpfulSpan"-enclosingTickSpan md (RealSrcSpan src _) = do-  ticks <- getTickArray md-  let line = srcSpanStartLine src-  massert (inRange (bounds ticks) line)-  let enclosing_spans = [ pan | (_,pan) <- ticks ! line-                               , realSrcSpanEnd pan >= realSrcSpanEnd src]-  return . head . sortBy leftmostLargestRealSrcSpan $ enclosing_spans- where--leftmostLargestRealSrcSpan :: RealSrcSpan -> RealSrcSpan -> Ordering-leftmostLargestRealSrcSpan a b =-  (realSrcSpanStart a `compare` realSrcSpanStart b)-     `thenCmp`-  (realSrcSpanEnd b `compare` realSrcSpanEnd a)--traceCmd :: GhciMonad m => String -> m ()-traceCmd arg-  = withSandboxOnly ":trace" $ tr arg-  where-  tr []         = doContinue (const True) GHC.RunAndLogSteps-  tr expression = runStmt expression GHC.RunAndLogSteps >>= setContinueExecResult >> return ()   -- DAP added--continueCmd :: GhciMonad m => String -> m ()                  -- #19157-continueCmd argLine = withSandboxOnly ":continue" $-  case contSwitch (words argLine) of-    Left sdoc   -> printForUser sdoc-    Right mbCnt -> doContinue' (const True) GHC.RunToCompletion mbCnt-    where-      contSwitch :: [String] -> Either SDoc (Maybe Int)-      contSwitch [ ] = Right Nothing-      contSwitch [x] = getIgnoreCount x-      contSwitch  _  = Left $-          text "After ':continue' only one ignore count is allowed"--doContinue :: GhciMonad m => (SrcSpan -> Bool) -> SingleStep -> m ()-doContinue pre step = doContinue' pre step Nothing--doContinue' :: GhciMonad m => (SrcSpan -> Bool) -> SingleStep -> Maybe Int -> m ()-doContinue' pre step mbCnt= do-  runResult <- resume pre step mbCnt-  setContinueExecResult (Just runResult)   -- DAP added.-  _ <- afterRunStmt pre runResult-  return ()--abandonCmd :: GhciMonad m => String -> m ()-abandonCmd = noArgs $ withSandboxOnly ":abandon" $ do-  b <- GHC.abandon -- the prompt will change to indicate the new context-  when (not b) $ liftIO $ putStrLn "There is no computation running."--deleteCmd :: GhciMonad m => String -> m ()-deleteCmd argLine = withSandboxOnly ":delete" $ do-   deleteSwitch $ words argLine-   where-   deleteSwitch :: GhciMonad m => [String] -> m ()-   deleteSwitch [] =-      liftIO $ putStrLn "The delete command requires at least one argument."-   -- delete all break points-   deleteSwitch ("*":_rest) = discardActiveBreakPoints-   deleteSwitch idents = do-      mapM_ deleteOneBreak idents-      where-      deleteOneBreak :: GhciMonad m => String -> m ()-      deleteOneBreak str-         | all isDigit str = deleteBreak (read str)-         | otherwise = return ()--enableCmd :: GhciMonad m => String -> m ()-enableCmd argLine = withSandboxOnly ":enable" $ do-    enaDisaSwitch True $ words argLine--disableCmd :: GhciMonad m => String -> m ()-disableCmd argLine = withSandboxOnly ":disable" $ do-    enaDisaSwitch False $ words argLine--enaDisaSwitch :: GhciMonad m => Bool -> [String] -> m ()-enaDisaSwitch enaDisa [] =-    printForUser (text "The" <+> text strCmd <+>-                  text "command requires at least one argument.")-  where-    strCmd = if enaDisa then ":enable" else ":disable"-enaDisaSwitch enaDisa ("*" : _) = enaDisaAllBreaks enaDisa-enaDisaSwitch enaDisa idents = do-    mapM_ (enaDisaOneBreak enaDisa) idents-  where-    enaDisaOneBreak :: GhciMonad m => Bool -> String -> m ()-    enaDisaOneBreak enaDisa strId = do-      sdoc_loc <- checkEnaDisa enaDisa strId-      case sdoc_loc of-        Left sdoc -> printForUser sdoc-        Right loc -> enaDisaAssoc enaDisa (read strId, loc)--checkEnaDisa :: GhciMonad m => Bool -> String -> m (Either SDoc BreakLocation)-checkEnaDisa enaDisa strId = do-    sdoc_loc <- getBreakLoc strId-    pure $ sdoc_loc >>= checkEnaDisaState enaDisa strId--getBreakLoc :: GhciMonad m => String -> m (Either SDoc BreakLocation)-getBreakLoc strId = do-    st <- getGHCiState-    case readMaybe strId >>= flip IntMap.lookup (breaks st) of-      Nothing -> return $ Left (text "Breakpoint" <+> text strId <+>-                                text "not found")-      Just loc -> return $ Right loc--checkEnaDisaState :: Bool -> String -> BreakLocation -> Either SDoc BreakLocation-checkEnaDisaState enaDisa strId loc = do-    if breakEnabled loc == enaDisa-    then Left $-        text "Breakpoint" <+> text strId <+> text "already in desired state"-    else Right loc--enaDisaAssoc :: GhciMonad m => Bool -> (Int, BreakLocation) -> m ()-enaDisaAssoc enaDisa (intId, loc) = do-    st <- getGHCiState-    newLoc <- turnBreakOnOff enaDisa loc-    let new_breaks = IntMap.insert intId newLoc (breaks st)-    setGHCiState $ st { breaks = new_breaks }--enaDisaAllBreaks :: GhciMonad m => Bool -> m()-enaDisaAllBreaks enaDisa = do-    st <- getGHCiState-    mapM_ (enaDisaAssoc enaDisa) $ IntMap.assocs $ breaks st--historyCmd :: GhciMonad m => String -> m ()   -- DAP Modified-historyCmd arg-  | null arg        = history 20-  | all isDigit arg = history (read arg)-  | otherwise       = liftIO $ putStrLn "Syntax:  :history [num]"-  where-  history num = do-    resumes <- GHC.getResumeContext-    case resumes of-      [] -> liftIO $ putStrLn "Not stopped at a breakpoint"-      (r:_) -> do-        let hist = GHC.resumeHistory r-            (took,rest) = splitAt num hist-        case hist of-          [] -> liftIO $ putStrLn $-                   "Empty history. Perhaps you forgot to use :trace?"-          _  -> do-                 pans <- mapM GHC.getHistorySpan took-                 let nums  = map (printf "-%-3d:") [(1::Int)..]-                     names = map GHC.historyEnclosingDecls took-                 printForUser (vcat(zipWith3-                                 (\x y z -> x <+> y <+> z)-                                 (map text nums)-                                 (map (bold . hcat . punctuate colon . map text) names)-                                 (map (parens . ppr) pans)))-                 liftIO $ putStrLn $ if null rest then "<end of history>" else "..."-        setStackTraceResult r took   -- DAP added.--bold :: SDoc -> SDoc-bold c | do_bold   = text start_bold <> c <> text end_bold-       | otherwise = c--ignoreCmd  :: GhciMonad m => String -> m ()                     -- #19157-ignoreCmd argLine = withSandboxOnly ":ignore" $ do-    result <- ignoreSwitch (words argLine)-    case result of-      Left sdoc -> printForUser sdoc-      Right (loc, mbCount)   -> do-        let breakInfo = GHC.BreakInfo (breakModule loc) (breakTick loc)-            count = fromMaybe 0 mbCount-        setupBreakpoint breakInfo count--ignoreSwitch :: GhciMonad m => [String] -> m (Either SDoc (BreakLocation, Maybe Int))-ignoreSwitch [break, count] = do-    sdoc_loc <- getBreakLoc break-    pure $ (,) <$> sdoc_loc <*> getIgnoreCount count-ignoreSwitch _ = pure $ Left $ text "Syntax:  :ignore <breaknum> <count>"--getIgnoreCount :: String -> Either SDoc (Maybe Int)-getIgnoreCount str =-    let checkJust :: Maybe Int -> Either SDoc (Maybe Int)-        checkJust mbCnt-          | (isJust mbCnt) = Right mbCnt-          | otherwise    = Left $ sdocIgnore <+> text "is not numeric"-        checkPositive :: Maybe Int -> Either SDoc (Maybe Int)-        checkPositive mbCnt-          | isJust mbCnt && fromJust mbCnt >= 0 = Right mbCnt-          | otherwise = Left $  sdocIgnore <+> text "must be >= 0"-        mbCnt :: Maybe Int = readMaybe str-        sdocIgnore = (text "Ignore count") <+> quotes (text str)-    in  Right mbCnt >>= checkJust >>= checkPositive--setupBreakpoint :: GhciMonad m => GHC.BreakInfo -> Int -> m()-setupBreakpoint loc count = do-    hsc_env <- GHC.getSession-    GHC.setupBreakpoint hsc_env loc count--backCmd :: GhciMonad m => String -> m ()-backCmd arg-  | null arg        = back 1-  | all isDigit arg = back (read arg)-  | otherwise       = liftIO $ putStrLn "Syntax:  :back [num]"-  where-  back num = withSandboxOnly ":back" $ do-      (names, _, pan, _) <- GHC.back num-      printForUser $ text "Logged breakpoint at" <+> ppr pan-      printTypeOfNames names-       -- run the command set with ":set stop <cmd>"-      st <- getGHCiState-      enqueueCommands [stop st]-      setBindingNames names      -- DAP added.--forwardCmd :: GhciMonad m => String -> m ()-forwardCmd arg-  | null arg        = forward 1-  | all isDigit arg = forward (read arg)-  | otherwise       = liftIO $ putStrLn "Syntax:  :forward [num]"-  where-  forward num = withSandboxOnly ":forward" $ do-      (names, ix, pan, _) <- GHC.forward num-      printForUser $ (if (ix == 0)-                        then text "Stopped at"-                        else text "Logged breakpoint at") <+> ppr pan-      printTypeOfNames names-       -- run the command set with ":set stop <cmd>"-      st <- getGHCiState-      enqueueCommands [stop st]-      setBindingNames names   -- DAP added.---- handle the "break" command-breakCmd :: GhciMonad m => String -> m ()-breakCmd argLine = withSandboxOnly ":break" $ breakSwitch $ words argLine--breakSwitch :: GhciMonad m => [String] -> m ()-breakSwitch [] = do-   liftIO $ putStrLn "The break command requires at least one argument."-breakSwitch (arg1:rest)-   | looksLikeModuleName arg1 && not (null rest) = do-        md <- wantInterpretedModule arg1-        breakByModule md rest-   | all isDigit arg1 = do-        imports <- GHC.getContext-        case iiModules imports of-           (mn : _) -> do-              md <- lookupModuleName mn-              breakByModuleLine md (read arg1) rest-           [] -> do-              liftIO $ putStrLn "No modules are loaded with debugging support."-   | otherwise = do -- try parsing it as an identifier-        breakById arg1--breakByModule :: GhciMonad m => Module -> [String] -> m ()-breakByModule md (arg1:rest)-   | all isDigit arg1 = do  -- looks like a line number-        breakByModuleLine md (read arg1) rest-breakByModule _ _-   = breakSyntax--breakByModuleLine :: GhciMonad m => Module -> Int -> [String] -> m ()-breakByModuleLine md line args-   | [] <- args = findBreakAndSet md $ maybeToList . findBreakByLine line-   | [col] <- args, all isDigit col =-        findBreakAndSet md $ maybeToList . findBreakByCoord Nothing (line, read col)-   | otherwise = breakSyntax---- Set a breakpoint for an identifier--- See Note [Setting Breakpoints by Id]-breakById :: GhciMonad m => String -> m ()                          -- #3000-breakById inp = do-    let (mod_str, top_level, fun_str) = splitIdent inp-        mod_top_lvl = combineModIdent mod_str top_level-    mb_mod <- catch (lookupModuleInscope mod_top_lvl)-                    (\(_ :: SomeException) -> lookupModuleInGraph mod_str)-      -- If the top-level name is not in scope, `lookupModuleInscope` will-      -- throw an exception, then lookup the module name in the module graph.-    mb_err_msg <- validateBP mod_str fun_str mb_mod-    case mb_err_msg of-        Just err_msg -> printForUser $-          text "Cannot set breakpoint on" <+> quotes (text inp)-          <> text ":" <+> err_msg-        Nothing -> do-          -- No errors found, go and set the breakpoint-          mb_mod_info  <- GHC.getModuleInfo $ fromJust mb_mod-          let modBreaks = case mb_mod_info of-                (Just mod_info) -> GHC.modInfoModBreaks mod_info-                Nothing         -> emptyModBreaks-          findBreakAndSet (fromJust mb_mod) $ findBreakForBind fun_str modBreaks-  where-    -- Try to lookup the module for an identifier that is in scope.-    -- `parseName` throws an exception, if the identifier is not in scope-    lookupModuleInscope :: GhciMonad m => String -> m (Maybe Module)-    lookupModuleInscope mod_top_lvl = do-        names <- GHC.parseName mod_top_lvl-        pure $ Just $ head $ GHC.nameModule <$> names-          -- if GHC.parseName succeeds `names` is not empty!-          -- if it fails, the last line will not be evaluated.--    -- Lookup the Module of a module name in the module graph-    lookupModuleInGraph :: GhciMonad m => String -> m (Maybe Module)-    lookupModuleInGraph mod_str = do-        graph <- GHC.getModuleGraph-        let hmods = ms_mod <$> GHC.mgModSummaries graph-        pure $ find ((== mod_str) . showModule) hmods--    -- Check validity of an identifier to set a breakpoint:-    --  1. The module of the identifier must exist-    --  2. the identifier must be in an interpreted module-    --  3. the ModBreaks array for module `mod` must have an entry-    --     for the function-    validateBP :: GhciMonad m => String -> String -> Maybe Module-                       -> m (Maybe SDoc)-    validateBP mod_str fun_str Nothing = pure $ Just $ quotes (text-        (combineModIdent mod_str (Prelude.takeWhile (/= '.') fun_str)))-        <+> text "not in scope"-    validateBP _ "" (Just _) = pure $ Just $ text "Function name is missing"-    validateBP _ fun_str (Just modl) = do-        isInterpr <- GHC.moduleIsInterpreted modl-        (_, decls) <- getModBreak modl-        mb_err_msg <- case isInterpr of-          False -> pure $ Just $ text "Module" <+> quotes (ppr modl)-                        <+> text "is not interpreted"-          True -> case fun_str `elem` (declPath <$> elems decls) of-                False -> pure $ Just $-                   text "No breakpoint found for" <+> quotes (text fun_str)-                   <+> "in module" <+> quotes (ppr modl)-                True  -> pure Nothing-        pure mb_err_msg--breakSyntax :: a-breakSyntax = throwGhcException $ CmdLineError ("Syntax: :break [<mod>.]<func>[.<func>]\n"-                                             ++ "        :break [<mod>] <line> [<column>]")--findBreakAndSet :: GhciMonad m-                => Module -> (TickArray -> [(Int, RealSrcSpan)]) -> m ()-findBreakAndSet md lookupTickTree = do-   tickArray <- getTickArray md-   case lookupTickTree tickArray of-      []  -> liftIO $ putStrLn $ "No breakpoints found at that location."-      some -> mapM_ breakAt some- where-   breakAt (tick, pan) = do-         setBreakFlag md tick True-         (alreadySet, nm) <--               recordBreak $ BreakLocation-                       { breakModule = md-                       , breakLoc = RealSrcSpan pan Strict.Nothing-                       , breakTick = tick-                       , onBreakCmd = ""-                       , breakEnabled = True-                       }-         printForUser $-            text "Breakpoint " <> ppr nm <>-            if alreadySet-               then text " was already set at " <> ppr pan-               else text " activated at " <> ppr pan---- When a line number is specified, the current policy for choosing--- the best breakpoint is this:---    - the leftmost complete subexpression on the specified line, or---    - the leftmost subexpression starting on the specified line, or---    - the rightmost subexpression enclosing the specified line----findBreakByLine :: Int -> TickArray -> Maybe (BreakIndex,RealSrcSpan)-findBreakByLine line arr-  | not (inRange (bounds arr) line) = Nothing-  | otherwise =-    listToMaybe (sortBy (leftmostLargestRealSrcSpan `on` snd)  comp)   `mplus`-    listToMaybe (sortBy (compare `on` snd) incomp) `mplus`-    listToMaybe (sortBy (flip compare `on` snd) ticks)-  where-        ticks = arr ! line--        starts_here = [ (ix,pan) | (ix, pan) <- ticks,-                        GHC.srcSpanStartLine pan == line ]--        (comp, incomp) = partition ends_here starts_here-            where ends_here (_,pan) = GHC.srcSpanEndLine pan == line---- The aim is to find the breakpoints for all the RHSs of the--- equations corresponding to a binding.  So we find all breakpoints--- for---   (a) this binder only (it maybe a top-level or a nested declaration)---   (b) that do not have an enclosing breakpoint-findBreakForBind :: String -> GHC.ModBreaks -> TickArray-                 -> [(BreakIndex,RealSrcSpan)]-findBreakForBind str_name modbreaks _ = filter (not . enclosed) ticks-  where-    ticks = [ (index, span)-            | (index, decls) <- assocs (GHC.modBreaks_decls modbreaks),-              str_name == declPath decls,-              RealSrcSpan span _ <- [GHC.modBreaks_locs modbreaks ! index] ]-    enclosed (_,sp0) = any subspan ticks-      where subspan (_,sp) = sp /= sp0 &&-                         realSrcSpanStart sp <= realSrcSpanStart sp0 &&-                         realSrcSpanEnd sp0 <= realSrcSpanEnd sp--findBreakByCoord :: Maybe FastString -> (Int,Int) -> TickArray-                 -> Maybe (BreakIndex,RealSrcSpan)-findBreakByCoord mb_file (line, col) arr-  | not (inRange (bounds arr) line) = Nothing-  | otherwise =-    listToMaybe (sortBy (flip compare `on` snd) contains ++-                 sortBy (compare `on` snd) after_here)-  where-        ticks = arr ! line--        -- the ticks that span this coordinate-        contains = [ tick | tick@(_,pan) <- ticks, RealSrcSpan pan Strict.Nothing `spans` (line,col),-                            is_correct_file pan ]--        is_correct_file pan-                 | Just f <- mb_file = GHC.srcSpanFile pan == f-                 | otherwise         = True--        after_here = [ tick | tick@(_,pan) <- ticks,-                              GHC.srcSpanStartLine pan == line,-                              GHC.srcSpanStartCol pan >= col ]---- For now, use ANSI bold on terminals that we know support it.--- Otherwise, we add a line of carets under the active expression instead.--- In particular, on Windows and when running the testsuite (which sets--- TERM to vt100 for other reasons) we get carets.--- We really ought to use a proper termcap/terminfo library.-do_bold :: Bool-do_bold = (`isPrefixOf` unsafePerformIO mTerm) `any` ["xterm", "linux"]-    where mTerm = System.Environment.getEnv "TERM"-                  `catchIO` \_ -> return "TERM not set"--start_bold :: String-start_bold = "\ESC[1m"-end_bold :: String-end_bold   = "\ESC[0m"--{--Note [Setting Breakpoints by Id]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-To set a breakpoint first check whether a ModBreaks array contains a-breakpoint with the given function name:-In `:break M.foo` `M` may be a module name or a local alias of an import-statement. To lookup a breakpoint in the ModBreaks, the effective module-name is needed. Even if a module called `M` exists, `M` may still be-a local alias. To get the module name, parse the top-level identifier with-`GHC.parseName`. If this succeeds, extract the module name from the-returned value. If it fails, catch the exception and assume `M` is a real-module name.--The names of nested functions are stored in `ModBreaks.modBreaks_decls`.--}---------------------------------------------------------------------------------- :where--whereCmd :: GHC.GhcMonad m => String -> m ()-whereCmd = noArgs $ do-  mstrs <- getCallStackAtCurrentBreakpoint-  case mstrs of-    Nothing -> return ()-    Just strs -> liftIO $ putStrLn (renderStack strs)---------------------------------------------------------------------------------- :list--listCmd :: GhciMonad m => String -> m ()-listCmd "" = do-   mb_span <- getCurrentBreakSpan-   case mb_span of-      Nothing ->-          printForUser $ text "Not stopped at a breakpoint; nothing to list"-      Just (RealSrcSpan pan _) ->-          listAround pan True-      Just pan@(UnhelpfulSpan _) ->-          do resumes <- GHC.getResumeContext-             case resumes of-                 [] -> panic "No resumes"-                 (r:_) ->-                     do let traceIt = case GHC.resumeHistory r of-                                      [] -> text "rerunning with :trace,"-                                      _ -> empty-                            doWhat = traceIt <+> text ":back then :list"-                        printForUser (text "Unable to list source for" <+>-                                      ppr pan-                                   $$ text "Try" <+> doWhat)-listCmd str = list2 (words str)--list2 :: GhciMonad m => [String] -> m ()-list2 [arg] | all isDigit arg = do-    imports <- GHC.getContext-    case iiModules imports of-        [] -> liftIO $ putStrLn "No module to list"-        (mn : _) -> do-          md <- lookupModuleName mn-          listModuleLine md (read arg)-list2 [arg1,arg2] | looksLikeModuleName arg1, all isDigit arg2 = do-        md <- wantInterpretedModule arg1-        listModuleLine md (read arg2)-list2 [arg] = do-        wantNameFromInterpretedModule noCanDo arg $ \name -> do-        let loc = GHC.srcSpanStart (GHC.nameSrcSpan name)-        case loc of-            RealSrcLoc l _ ->-               do tickArray <- assert (isExternalName name) $-                               getTickArray (GHC.nameModule name)-                  let mb_span = findBreakByCoord (Just (GHC.srcLocFile l))-                                        (GHC.srcLocLine l, GHC.srcLocCol l)-                                        tickArray-                  case mb_span of-                    Nothing       -> listAround (realSrcLocSpan l) False-                    Just (_, pan) -> listAround pan False-            UnhelpfulLoc _ ->-                  noCanDo name $ text "can't find its location: " <>-                                 ppr loc-    where-        noCanDo n why = printForUser $-            text "cannot list source code for " <> ppr n <> text ": " <> why-list2  _other =-        liftIO $ putStrLn "syntax:  :list [<line> | <module> <line> | <identifier>]"--listModuleLine :: GHC.GhcMonad m => Module -> Int -> m ()-listModuleLine modl line = do-   graph <- GHC.getModuleGraph-   let this = GHC.mgLookupModule graph modl-   case this of-     Nothing -> panic "listModuleLine"-     Just summ -> do-           let filename = expectJust "listModuleLine" (ml_hs_file (GHC.ms_location summ))-               loc = mkRealSrcLoc (mkFastString (filename)) line 0-           listAround (realSrcLocSpan loc) False---- | list a section of a source file around a particular SrcSpan.--- If the highlight flag is True, also highlight the span using--- start_bold\/end_bold.---- GHC files are UTF-8, so we can implement this by:--- 1) read the file in as a BS and syntax highlight it as before--- 2) convert the BS to String using utf-string, and write it out.--- It would be better if we could convert directly between UTF-8 and the--- console encoding, of course.-listAround :: MonadIO m => RealSrcSpan -> Bool -> m ()-listAround pan do_highlight = do-      contents <- liftIO $ BS.readFile (unpackFS file)-      -- Drop carriage returns to avoid duplicates, see #9367.-      let ls  = BS.split '\n' $ BS.filter (/= '\r') contents-          ls' = take (line2 - line1 + 1 + pad_before + pad_after) $-                        drop (line1 - 1 - pad_before) $ ls-          fst_line = max 1 (line1 - pad_before)-          line_nos = [ fst_line .. ]--          highlighted | do_highlight = zipWith highlight line_nos ls'-                      | otherwise    = [\p -> BS.concat[p,l] | l <- ls']--          bs_line_nos = [ BS.pack (show l ++ "  ") | l <- line_nos ]-          prefixed = zipWith ($) highlighted bs_line_nos-          output   = BS.intercalate (BS.pack "\n") prefixed--      let utf8Decoded = utf8DecodeByteString output-      liftIO $ putStrLn utf8Decoded-  where-        file  = GHC.srcSpanFile pan-        line1 = GHC.srcSpanStartLine pan-        col1  = GHC.srcSpanStartCol pan - 1-        line2 = GHC.srcSpanEndLine pan-        col2  = GHC.srcSpanEndCol pan - 1--        pad_before | line1 == 1 = 0-                   | otherwise  = 1-        pad_after = 1--        highlight | do_bold   = highlight_bold-                  | otherwise = highlight_carets--        highlight_bold no line prefix-          | no == line1 && no == line2-          = let (a,r) = BS.splitAt col1 line-                (b,c) = BS.splitAt (col2-col1) r-            in-            BS.concat [prefix, a,BS.pack start_bold,b,BS.pack end_bold,c]-          | no == line1-          = let (a,b) = BS.splitAt col1 line in-            BS.concat [prefix, a, BS.pack start_bold, b]-          | no == line2-          = let (a,b) = BS.splitAt col2 line in-            BS.concat [prefix, a, BS.pack end_bold, b]-          | otherwise   = BS.concat [prefix, line]--        highlight_carets no line prefix-          | no == line1 && no == line2-          = BS.concat [prefix, line, nl, indent, BS.replicate col1 ' ',-                                         BS.replicate (col2-col1) '^']-          | no == line1-          = BS.concat [indent, BS.replicate (col1 - 2) ' ', BS.pack "vv", nl,-                                         prefix, line]-          | no == line2-          = BS.concat [prefix, line, nl, indent, BS.replicate col2 ' ',-                                         BS.pack "^^"]-          | otherwise   = BS.concat [prefix, line]-         where-           indent = BS.pack ("  " ++ replicate (length (show no)) ' ')-           nl = BS.singleton '\n'----- ----------------------------------------------------------------------------- Tick arrays--getTickArray :: GhciMonad m => Module -> m TickArray-getTickArray modl = do-   st <- getGHCiState-   let arrmap = tickarrays st-   case lookupModuleEnv arrmap modl of-      Just arr -> return arr-      Nothing  -> do-        (ticks, _) <- getModBreak modl-        let arr = mkTickArray (assocs ticks)-        setGHCiState st{tickarrays = extendModuleEnv arrmap modl arr}-        return arr--discardTickArrays :: GhciMonad m => m ()-discardTickArrays = modifyGHCiState (\st -> st {tickarrays = emptyModuleEnv})--mkTickArray :: [(BreakIndex,SrcSpan)] -> TickArray-mkTickArray ticks-  = accumArray (flip (:)) [] (1, max_line)-        [ (line, (nm,pan)) | (nm,RealSrcSpan pan _) <- ticks, line <- srcSpanLines pan ]-    where-        max_line = foldr max 0 [ GHC.srcSpanEndLine sp | (_, RealSrcSpan sp _) <- ticks ]-        srcSpanLines pan = [ GHC.srcSpanStartLine pan ..  GHC.srcSpanEndLine pan ]---- don't reset the counter back to zero?-discardActiveBreakPoints :: GhciMonad m => m ()-discardActiveBreakPoints = do-   st <- getGHCiState-   mapM_ (turnBreakOnOff False) $ breaks st-   setGHCiState $ st { breaks = IntMap.empty }--discardInterfaceCache :: GhciMonad m => m ()-discardInterfaceCache =-   void (liftIO . iface_clearCache . ifaceCache =<< getGHCiState)--clearHPTs :: GhciMonad m => m ()-clearHPTs = do-  let pruneHomeUnitEnv hme = hme { homeUnitEnv_hpt = emptyHomePackageTable }-      discardMG hsc = hsc { hsc_mod_graph = GHC.emptyMG }-  modifySession (discardMG . discardIC . hscUpdateHUG (unitEnv_map pruneHomeUnitEnv))----- The unused package warning doesn't make sense once the targets get out of--- sync with the package flags. See #21110--- Therefore if it's turned on, the warnings are issued until the module context--- changes (via :load or :cd), at which stage the package flags are not going to change--- but the loaded modules will probably not use all the specified packages so the--- warning becomes spurious. At that point the warning is silently disabled.-disableUnusedPackages :: GhciMonad m => m ()-disableUnusedPackages = newDynFlags False ["-Wno-unused-packages"]--deleteBreak :: GhciMonad m => Int -> m ()-deleteBreak identity = do-   st <- getGHCiState-   let oldLocations = breaks st-   case IntMap.lookup identity oldLocations of-       Nothing -> printForUser (text "Breakpoint" <+> ppr identity <+>-                                text "does not exist")-       Just loc -> do-           _ <- (turnBreakOnOff False) loc-           let rest = IntMap.delete identity oldLocations-           setGHCiState $ st { breaks = rest }--turnBreakOnOff :: GhciMonad m => Bool -> BreakLocation -> m BreakLocation-turnBreakOnOff onOff loc-  | onOff == breakEnabled loc = return loc-  | otherwise = do-      setBreakFlag (breakModule loc) (breakTick loc)  onOff-      return loc { breakEnabled = onOff }--getModBreak :: GHC.GhcMonad m-            => Module -> m (Array Int SrcSpan, Array Int [String])-getModBreak m = do-   mod_info      <- fromMaybe (panic "getModBreak") <$> GHC.getModuleInfo m-   let modBreaks  = GHC.modInfoModBreaks mod_info-   let ticks      = GHC.modBreaks_locs  modBreaks-   let decls      = GHC.modBreaks_decls modBreaks-   return (ticks, decls)--setBreakFlag :: GhciMonad m => Module -> Int -> Bool ->m ()-setBreakFlag  md ix enaDisa = do-  let enaDisaToCount True = breakOn-      enaDisaToCount False = breakOff-  setupBreakpoint (GHC.BreakInfo md ix) $ enaDisaToCount enaDisa---- ------------------------------------------------------------------------------ User code exception handling---- This is the exception handler for exceptions generated by the--- user's code and exceptions coming from children sessions;--- it normally just prints out the exception.  The--- handler must be recursive, in case showing the exception causes--- more exceptions to be raised.------ Bugfix: if the user closed stdout or stderr, the flushing will fail,--- raising another exception.  We therefore don't put the recursive--- handler around the flushing operation, so if stderr is closed--- GHCi will just die gracefully rather than going into an infinite loop.-handler :: GhciMonad m => SomeException -> m Bool-handler exception = do-  flushInterpBuffers-  withSignalHandlers $-     ghciHandle handler (showException exception >> return False)--showException :: MonadIO m => SomeException -> m ()-showException se =-  liftIO $ case fromException se of-           -- omit the location for CmdLineError:-           Just (CmdLineError s)    -> putException s-           -- ditto:-           Just other_ghc_ex        -> putException (show other_ghc_ex)-           Nothing                  ->-               case fromException se of-               Just UserInterrupt -> putException "Interrupted."-               _                  -> putException ("*** Exception: " ++ show se)-  where-    putException = hPutStrLn stderr--failIfExprEvalMode :: GhciMonad m => m ()-failIfExprEvalMode = do-  s <- getGHCiState-  when (ghc_e s) $-    liftIO (exitWith (ExitFailure 1))---- | When in expression evaluation mode (ghc -e), we want to exit immediately.--- Otherwis, just print out the message.-printErrAndMaybeExit :: (GhciMonad m, MonadIO m, HasLogger m) => SourceError -> m ()-printErrAndMaybeExit = (>> failIfExprEvalMode) . GHC.printException---------------------------------------------------------------------------------- recursive exception handlers---- Don't forget to unblock async exceptions in the handler, or if we're--- in an exception loop (eg. let a = error a in a) the ^C exception--- may never be delivered.  Thanks to Marcin for pointing out the bug.--ghciHandle :: (HasLogger m, ExceptionMonad m) => (SomeException -> m a) -> m a -> m a-ghciHandle h m = mask $ \restore -> do-                 -- Force dflags to avoid leaking the associated HscEnv-                 !log <- getLogger-                 catch (restore (GHC.prettyPrintGhcErrors log m)) $ \e -> restore (h e)--ghciTry :: ExceptionMonad m => m a -> m (Either SomeException a)-ghciTry m = fmap Right m `catch` \e -> return $ Left e--tryBool :: ExceptionMonad m => m a -> m Bool-tryBool m = do-    r <- ghciTry m-    case r of-      Left _  -> return False-      Right _ -> return True---- ------------------------------------------------------------------------------- Utils--lookupModule :: GHC.GhcMonad m => String -> m Module-lookupModule mName = lookupModuleName (GHC.mkModuleName mName)--lookupModuleName :: GHC.GhcMonad m => ModuleName -> m Module-lookupModuleName mName = GHC.lookupQualifiedModule NoPkgQual mName--isMainUnitModule :: Module -> Bool-isMainUnitModule m = GHC.moduleUnit m == mainUnit--showModule :: Module -> String-showModule = moduleNameString . moduleName---- Return a String with the declPath of the function of a breakpoint.--- See Note [Field modBreaks_decls] in GHC.ByteCode.Types-declPath :: [String] -> String-declPath = intercalate "."---- | Optionally show a fixity declaration like @infixr 4 #@------ We always display the fixity of terms with symbolic names (like <$>).--- For other terms we only display the fixity if it has been set to a--- value other than the default infixl 9.------ We have no way of distinguishing between a fixity that has been--- manually set to infixl 9 and a fixity that has assumed infixl 9 as--- the default, so we choose to not display the fixity in both cases--- (for terms with non-symbolic names).------ See #19200.-showFixity :: TyThing -> Fixity -> SDoc-showFixity thing fixity-    | fixity /= GHC.defaultFixity || isSymOcc (getOccName thing)-        = ppr fixity <+> pprInfixName (GHC.getName thing)-    | otherwise = empty---- TODO: won't work if home dir is encoded.--- (changeDirectory may not work either in that case.)-expandPath :: MonadIO m => String -> m String-expandPath = liftIO . expandPathIO--expandPathIO :: String -> IO String-expandPathIO p =-  case dropWhile isSpace p of-   ('~':d) -> do-        tilde <- getHomeDirectory -- will fail if HOME not defined-        return (tilde ++ '/':d)-   other ->-        return other--wantInterpretedModule :: GHC.GhcMonad m => String -> m Module-wantInterpretedModule str = wantInterpretedModuleName (GHC.mkModuleName str)--wantInterpretedModuleName :: GHC.GhcMonad m => ModuleName -> m Module-wantInterpretedModuleName modname = do-   modl <- lookupModuleName modname-   let str = moduleNameString modname-   home_unit <- hsc_home_unit <$> GHC.getSession-   unless (isHomeModule home_unit modl) $-      throwGhcException (CmdLineError ("module '" ++ str ++ "' is from another package;\nthis command requires an interpreted module"))-   is_interpreted <- GHC.moduleIsInterpreted modl-   when (not is_interpreted) $-       throwGhcException (CmdLineError ("module '" ++ str ++ "' is not interpreted; try \':add *" ++ str ++ "' first"))-   return modl--wantNameFromInterpretedModule :: GHC.GhcMonad m-                              => (Name -> SDoc -> m ())-                              -> String-                              -> (Name -> m ())-                              -> m ()-wantNameFromInterpretedModule noCanDo str and_then =-  handleSourceError GHC.printException $ do-   names <- GHC.parseName str-   case names of-      []    -> return ()-      (n:_) -> do-            let modl = assert (isExternalName n) $ GHC.nameModule n-            if not (GHC.isExternalName n)-               then noCanDo n $ ppr n <>-                                text " is not defined in an interpreted module"-               else do-            is_interpreted <- GHC.moduleIsInterpreted modl-            if not is_interpreted-               then noCanDo n $ text "module " <> ppr modl <>-                                text " is not interpreted"-               else and_then n--clearCaches :: GhciMonad m => m ()-clearCaches = discardActiveBreakPoints-              >> discardInterfaceCache-              >> disableUnusedPackages-              >> clearHPTs------ Split up a string with an eventually qualified declaration name into 3 components---   1. module name---   2. top-level decl---   3. full-name of the eventually nested decl, but without module qualification--- eg  "foo"           = ("", "foo", "foo")---     "A.B.C.foo"     = ("A.B.C", "foo", "foo")---     "M.N.foo.bar"   = ("M.N", "foo", "foo.bar")-splitIdent :: String -> (String, String, String)-splitIdent [] = ("", "", "")-splitIdent inp@(a : _)-    | (isUpper a) = case fixs of-        []            -> (inp, "", "")-        (i1 : [] )    -> (upto i1, from i1, from i1)-        (i1 : i2 : _) -> (upto i1, take (i2 - i1 - 1) (from i1), from i1)-    | otherwise = case ixs of-        []            -> ("", inp, inp)-        (i1 : _)      -> ("", upto i1, inp)-  where-    ixs = elemIndices '.' inp        -- indices of '.' in whole input-    fixs = dropWhile isNextUc ixs    -- indices of '.' in function names              ---    isNextUc ix = isUpper $ safeInp !! (ix+1)-    safeInp = inp ++ " "-    upto i = take i inp-    from i = drop (i + 1) inp---- Qualify an identifier name with a module name--- combineModIdent "A" "foo"  =  "A.foo"--- combineModIdent ""  "foo"  =  "foo"-combineModIdent :: String -> String -> String-combineModIdent mod ident-          | null mod   = ident-          | null ident = mod-          | otherwise  = mod ++ "." ++ ident------------------------------------------------------------------------------------------------------  DAP Utility----------------------------------------------------------------------------------------------------- |----setStackTraceResult :: GhciMonad m => Resume -> [GHC.History] -> m ()-setStackTraceResult r hs = do-  ctxMVar <- dapContextGHCiState <$> getGHCiState-  ctx <- liftIO $ takeMVar ctxMVar-  liftIO $ putMVar ctxMVar ctx {DAP.stackTraceResultDAPContext = Just (r, hs)}----- |----setBindingNames :: GhciMonad m => [Name] -> m ()-setBindingNames names = do-  ctxMVar <- dapContextGHCiState <$> getGHCiState-  ctx <- liftIO $ takeMVar ctxMVar-  liftIO $ putMVar ctxMVar ctx {DAP.bindingNamesDAPContext = names}----- |----setContinueExecResult :: GhciMonad m => Maybe GHC.ExecResult -> m (Maybe GHC.ExecResult)-setContinueExecResult res = do-  ctxMVar <- dapContextGHCiState  <$> getGHCiState-  ctx <- liftIO $ takeMVar ctxMVar-  liftIO $ putMVar ctxMVar ctx{DAP.continueExecResultDAPContext = res}-  return res---
− app-ghc-9.4/GHCi/UI/Info.hs
@@ -1,384 +0,0 @@-{-# LANGUAGE LambdaCase          #-}-{-# LANGUAGE RankNTypes          #-}-{-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE ViewPatterns        #-}--{-# OPTIONS -fno-warn-name-shadowing #-}---- | Get information on modules, expressions, and identifiers-module GHCi.UI.Info-    ( ModInfo(..)-    , SpanInfo(..)-    , spanInfoFromRealSrcSpan-    , collectInfo-    , findLoc-    , findNameUses-    , findType-    , getModInfo-    ) where--import           Control.Exception-import           Control.Monad-import           Control.Monad.Catch as MC-import           Control.Monad.Trans.Class-import           Control.Monad.Trans.Except-import           Control.Monad.Trans.Maybe-import           Data.Data-import           Data.Function-import           Data.List (find, sortBy)-import           Data.Map.Strict   (Map)-import qualified Data.Map.Strict   as M-import           Data.Maybe-import           Data.Time-import           Prelude           hiding (mod,(<>))-import           System.Directory--import           GHC.Hs.Syn.Type-import           GHC.Driver.Session (HasDynFlags(..))-import           GHC.Data.FastString-import           GHC-import           GHC.Driver.Monad-import           GHC.Driver.Env-import           GHC.Driver.Ppr-import           GHC.Types.Name-import           GHC.Types.Name.Set-import           GHC.Utils.Outputable-import           GHC.Types.SrcLoc-import           GHC.Types.Var-import qualified GHC.Data.Strict as Strict---- | Info about a module. This information is generated every time a--- module is loaded.-data ModInfo = ModInfo-    { modinfoSummary    :: !ModSummary-      -- ^ Summary generated by GHC. Can be used to access more-      -- information about the module.-    , modinfoSpans      :: [SpanInfo]-      -- ^ Generated set of information about all spans in the-      -- module that correspond to some kind of identifier for-      -- which there will be type info and/or location info.-    , modinfoInfo       :: !ModuleInfo-      -- ^ Again, useful from GHC for accessing information-      -- (exports, instances, scope) from a module.-    , modinfoLastUpdate :: !UTCTime-      -- ^ The timestamp of the file used to generate this record.-    }---- | Type of some span of source code. Most of these fields are--- unboxed but Haddock doesn't show that.-data SpanInfo = SpanInfo-    { spaninfoSrcSpan   :: {-# UNPACK #-} !RealSrcSpan-      -- ^ The span we associate information with-    , spaninfoType      :: !(Maybe Type)-      -- ^ The 'Type' associated with the span-    , spaninfoVar       :: !(Maybe Id)-      -- ^ The actual 'Var' associated with the span, if-      -- any. This can be useful for accessing a variety of-      -- information about the identifier such as module,-      -- locality, definition location, etc.-    }--instance Outputable SpanInfo where-  ppr (SpanInfo s t i) = ppr s <+> ppr t <+> ppr i---- | Test whether second span is contained in (or equal to) first span.--- This is basically 'containsSpan' for 'SpanInfo'-containsSpanInfo :: SpanInfo -> SpanInfo -> Bool-containsSpanInfo = containsSpan `on` spaninfoSrcSpan---- | Filter all 'SpanInfo' which are contained in 'SpanInfo'-spaninfosWithin :: [SpanInfo] -> SpanInfo -> [SpanInfo]-spaninfosWithin spans' si = filter (si `containsSpanInfo`) spans'---- | Construct a 'SpanInfo' from a 'RealSrcSpan' and optionally a--- 'Type' and an 'Id' (for 'spaninfoType' and 'spaninfoVar'--- respectively)-spanInfoFromRealSrcSpan :: RealSrcSpan -> Maybe Type -> Maybe Id -> SpanInfo-spanInfoFromRealSrcSpan spn mty mvar =-    SpanInfo spn mty mvar---- | Convenience wrapper around 'spanInfoFromRealSrcSpan' which needs--- only a 'RealSrcSpan'-spanInfoFromRealSrcSpan' :: RealSrcSpan -> SpanInfo-spanInfoFromRealSrcSpan' s = spanInfoFromRealSrcSpan s Nothing Nothing---- | Convenience wrapper around 'srcSpanFile' which results in a 'FilePath'-srcSpanFilePath :: RealSrcSpan -> FilePath-srcSpanFilePath = unpackFS . srcSpanFile---- | Try to find the location of the given identifier at the given--- position in the module.-findLoc :: GhcMonad m-        => Map ModuleName ModInfo-        -> RealSrcSpan-        -> String-        -> ExceptT SDoc m (ModInfo,Name,SrcSpan)-findLoc infos span0 string = do-    name  <- maybeToExceptT "Couldn't guess that module name. Does it exist?" $-             guessModule infos (srcSpanFilePath span0)--    info  <- maybeToExceptT "No module info for current file! Try loading it?" $-             MaybeT $ pure $ M.lookup name infos--    name' <- findName infos span0 info string--    case getSrcSpan name' of-        UnhelpfulSpan{} -> do-            throwE ("Found a name, but no location information." <+>-                    "The module is:" <+>-                    maybe "<unknown>" (ppr . moduleName)-                          (nameModule_maybe name'))--        span' -> return (info,name',span')---- | Find any uses of the given identifier in the codebase.-findNameUses :: (GhcMonad m)-             => Map ModuleName ModInfo-             -> RealSrcSpan-             -> String-             -> ExceptT SDoc m [SrcSpan]-findNameUses infos span0 string =-    locToSpans <$> findLoc infos span0 string-  where-    locToSpans (modinfo,name',span') =-        stripSurrounding (span' : map toSrcSpan spans)-      where-        toSrcSpan s = RealSrcSpan (spaninfoSrcSpan s) Strict.Nothing-        spans = filter ((== Just name') . fmap getName . spaninfoVar)-                       (modinfoSpans modinfo)---- | Filter out redundant spans which surround/contain other spans.-stripSurrounding :: [SrcSpan] -> [SrcSpan]-stripSurrounding xs = filter (not . isRedundant) xs-  where-    isRedundant x = any (x `strictlyContains`) xs--    (RealSrcSpan s1 _) `strictlyContains` (RealSrcSpan s2 _)-         = s1 /= s2 && s1 `containsSpan` s2-    _                `strictlyContains` _ = False---- | Try to resolve the name located at the given position, or--- otherwise resolve based on the current module's scope.-findName :: GhcMonad m-         => Map ModuleName ModInfo-         -> RealSrcSpan-         -> ModInfo-         -> String-         -> ExceptT SDoc m Name-findName infos span0 mi string =-    case resolveName (modinfoSpans mi) (spanInfoFromRealSrcSpan' span0) of-      Nothing -> tryExternalModuleResolution-      Just name ->-        case getSrcSpan name of-          UnhelpfulSpan {} -> tryExternalModuleResolution-          RealSrcSpan   {} -> return (getName name)-  where-    tryExternalModuleResolution =-      case find (matchName $ mkFastString string)-                (fromMaybe [] (modInfoTopLevelScope (modinfoInfo mi))) of-        Nothing -> throwE "Couldn't resolve to any modules."-        Just imported -> resolveNameFromModule infos imported--    matchName :: FastString -> Name -> Bool-    matchName str name =-      str ==-      occNameFS (getOccName name)---- | Try to resolve the name from another (loaded) module's exports.-resolveNameFromModule :: GhcMonad m-                      => Map ModuleName ModInfo-                      -> Name-                      -> ExceptT SDoc m Name-resolveNameFromModule infos name = do-     modL <- maybe (throwE $ "No module for" <+> ppr name) return $-             nameModule_maybe name--     info <- maybe (throwE (ppr (moduleUnit modL) <> ":" <>-                            ppr modL)) return $-             M.lookup (moduleName modL) infos--     maybe (throwE "No matching export in any local modules.") return $-         find (matchName name) (modInfoExports (modinfoInfo info))-  where-    matchName :: Name -> Name -> Bool-    matchName x y = occNameFS (getOccName x) ==-                    occNameFS (getOccName y)---- | Try to resolve the type display from the given span.-resolveName :: [SpanInfo] -> SpanInfo -> Maybe Var-resolveName spans' si = listToMaybe $ mapMaybe spaninfoVar $-                        reverse spans' `spaninfosWithin` si---- | Try to find the type of the given span.-findType :: GhcMonad m-         => Map ModuleName ModInfo-         -> RealSrcSpan-         -> String-         -> ExceptT SDoc m (ModInfo, Type)-findType infos span0 string = do-    name  <- maybeToExceptT "Couldn't guess that module name. Does it exist?" $-             guessModule infos (srcSpanFilePath span0)--    info  <- maybeToExceptT "No module info for current file! Try loading it?" $-             MaybeT $ pure $ M.lookup name infos--    case resolveType (modinfoSpans info) (spanInfoFromRealSrcSpan' span0) of-        Nothing -> (,) info <$> lift (exprType TM_Inst string)-        Just ty -> return (info, ty)-  where-    -- | Try to resolve the type display from the given span.-    resolveType :: [SpanInfo] -> SpanInfo -> Maybe Type-    resolveType spans' si = listToMaybe $ mapMaybe spaninfoType $-                            reverse spans' `spaninfosWithin` si---- | Guess a module name from a file path.-guessModule :: GhcMonad m-            => Map ModuleName ModInfo -> FilePath -> MaybeT m ModuleName-guessModule infos fp = do-    target <- lift $ guessTarget fp Nothing Nothing-    case targetId target of-        TargetModule mn  -> return mn-        TargetFile fp' _ -> guessModule' fp'-  where-    guessModule' :: GhcMonad m => FilePath -> MaybeT m ModuleName-    guessModule' fp' = case findModByFp fp' of-        Just mn -> return mn-        Nothing -> do-            fp'' <- liftIO (makeRelativeToCurrentDirectory fp')--            target' <- lift $ guessTarget fp'' Nothing Nothing-            case targetId target' of-                TargetModule mn -> return mn-                _               -> MaybeT . pure $ findModByFp fp''--    findModByFp :: FilePath -> Maybe ModuleName-    findModByFp fp' = fst <$> find ((Just fp' ==) . mifp) (M.toList infos)-      where-        mifp :: (ModuleName, ModInfo) -> Maybe FilePath-        mifp = ml_hs_file . ms_location . modinfoSummary . snd----- | Collect type info data for the loaded modules.-collectInfo :: (GhcMonad m) => Map ModuleName ModInfo -> [ModuleName]-               -> m (Map ModuleName ModInfo)-collectInfo ms loaded = do-    df <- getDynFlags-    unit_state <- hsc_units <$> getSession-    liftIO (filterM cacheInvalid loaded) >>= \case-        [] -> return ms-        invalidated -> do-            liftIO (putStrLn ("Collecting type info for " ++-                              show (length invalidated) ++-                              " module(s) ... "))--            foldM (go df unit_state) ms invalidated-  where-    go df unit_state m name = do { info <- getModInfo name; return (M.insert name info m) }-                   `MC.catch`-                   (\(e :: SomeException) -> do-                         liftIO $ putStrLn-                                $ showSDocForUser df unit_state alwaysQualify-                                $ "Error while getting type info from" <+>-                                  ppr name <> ":" <+> text (show e)-                         return m)--    cacheInvalid name = case M.lookup name ms of-        Nothing -> return True-        Just mi -> do-            let fp = srcFilePath (modinfoSummary mi)-                last' = modinfoLastUpdate mi-            current <- getModificationTime fp-            exists <- doesFileExist fp-            if exists-                then return $ current /= last'-                else return True---- | Get the source file path from a ModSummary.--- If the .hs file is missing, and the .o file exists,--- we return the .o file path.-srcFilePath :: ModSummary -> FilePath-srcFilePath modSum = fromMaybe obj_fp src_fp-    where-        src_fp = ml_hs_file ms_loc-        obj_fp = ml_obj_file ms_loc-        ms_loc = ms_location modSum---- | Get info about the module: summary, types, etc.-getModInfo :: (GhcMonad m) => ModuleName -> m ModInfo-getModInfo name = do-    m <- getModSummary name-    p <- parseModule m-    typechecked <- typecheckModule p-    let allTypes = processAllTypeCheckedModule typechecked-    let i = tm_checked_module_info typechecked-    ts <- liftIO $ getModificationTime $ srcFilePath m-    return (ModInfo m allTypes i ts)---- | Get ALL source spans in the module.-processAllTypeCheckedModule :: TypecheckedModule -> [SpanInfo]-processAllTypeCheckedModule tcm-  = mapMaybe toSpanInfo-  $ sortBy cmpSpan-  $ catMaybes (bts ++ ets ++ pts)-  where-    bts = map getTypeLHsBind $ listifyAllSpans tcs-    ets = map getTypeLHsExpr $ listifyAllSpans tcs-    pts = map getTypeLPat    $ listifyAllSpans tcs--    tcs = tm_typechecked_source tcm--    -- | Extract 'Id', 'SrcSpan', and 'Type' for 'LHsBind's-    getTypeLHsBind :: LHsBind GhcTc -> Maybe (Maybe Id,SrcSpan,Type)-    getTypeLHsBind (L _spn FunBind{fun_id = pid,fun_matches = MG _ _ _})-        = Just (Just (unLoc pid), getLocA pid,varType (unLoc pid))-    getTypeLHsBind _ = Nothing--    -- | Extract 'Id', 'SrcSpan', and 'Type' for 'LHsExpr's-    getTypeLHsExpr :: LHsExpr GhcTc -> Maybe (Maybe Id,SrcSpan,Type)-    getTypeLHsExpr e = Just (mid, getLocA e, lhsExprType e)-      where-        mid :: Maybe Id-        mid | HsVar _ (L _ i) <- unwrapVar (unLoc e) = Just i-            | otherwise                              = Nothing--        unwrapVar (XExpr (WrapExpr (HsWrap _ var))) = var-        unwrapVar e'                                = e'--    -- | Extract 'Id', 'SrcSpan', and 'Type' for 'LPats's-    getTypeLPat :: LPat GhcTc -> Maybe (Maybe Id,SrcSpan,Type)-    getTypeLPat (L spn pat) = Just (getMaybeId pat,locA spn,hsPatType pat)-      where-        getMaybeId :: Pat GhcTc -> Maybe Id-        getMaybeId (VarPat _ (L _ vid)) = Just vid-        getMaybeId _                        = Nothing--    -- | Get ALL source spans in the source.-    listifyAllSpans :: Typeable a => TypecheckedSource -> [LocatedA a]-    listifyAllSpans = everythingAllSpans (++) [] ([] `mkQ` (\x -> [x | p x]))-      where-        p (L spn _) = isGoodSrcSpan (locA spn)--    -- | Variant of @syb@'s @everything@ (which summarises all nodes-    -- in top-down, left-to-right order) with a stop-condition on 'NameSet's-    everythingAllSpans :: (r -> r -> r) -> r -> GenericQ r -> GenericQ r-    everythingAllSpans k z f x-      | (False `mkQ` (const True :: NameSet -> Bool)) x = z-      | otherwise = foldl k (f x) (gmapQ (everythingAllSpans k z f) x)--    cmpSpan (_,a,_) (_,b,_)-      | a `isSubspanOf` b = LT-      | b `isSubspanOf` a = GT-      | otherwise         = EQ--    -- | Pretty print the types into a 'SpanInfo'.-    toSpanInfo :: (Maybe Id,SrcSpan,Type) -> Maybe SpanInfo-    toSpanInfo (n,RealSrcSpan spn _,typ)-        = Just $ spanInfoFromRealSrcSpan spn (Just typ) n-    toSpanInfo _ = Nothing---- helper stolen from @syb@ package-type GenericQ r = forall a. Data a => a -> r--mkQ :: (Typeable a, Typeable b) => r -> (b -> r) -> a -> r-(r `mkQ` br) a = maybe r br (cast a)
− app-ghc-9.4/GHCi/UI/Monad.hs
@@ -1,599 +0,0 @@-{-# LANGUAGE FlexibleInstances, DeriveFunctor, DerivingVia #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# OPTIONS -fno-warn-name-shadowing #-}------------------------------------------------------------------------------------- Monadery code used in InteractiveUI------ (c) The GHC Team 2005-2006-----------------------------------------------------------------------------------module GHCi.UI.Monad (-        GHCi(..), startGHCi,-        GHCiState(..), GhciMonad(..),-        GHCiOption(..), isOptionSet, setOption, unsetOption,-        Command(..), CommandResult(..), cmdSuccess,-        CmdExecOutcome(..),-        LocalConfigBehaviour(..),-        PromptFunction,-        BreakLocation(..),-        TickArray,-        extractDynFlags, getDynFlags,--        runStmt, runDecls, runDecls', resume, recordBreak, revertCAFs,-        ActionStats(..), runAndPrintStats, runWithStats, printStats,--        printForUserNeverQualify, printForUserModInfo,-        printForUser, printForUserPartWay, prettyLocations,--        compileGHCiExpr,-        initInterpBuffering,-        turnOffBuffering, turnOffBuffering_,-        flushInterpBuffers,-        runInternal,-        mkEvalWrapper,--        -- DAP added.-        dapLookupMaxBreakLocation-    ) where--import GHCi.UI.Info (ModInfo)-import qualified GHC-import GHC.Driver.Monad hiding (liftIO)-import GHC.Utils.Outputable-import qualified GHC.Driver.Ppr as Ppr-import GHC.Types.Name.Occurrence-import GHC.Driver.Session-import GHC.Data.FastString-import GHC.Driver.Env-import GHC.Types.SrcLoc-import GHC.Types.SafeHaskell-import GHC.Driver.Make (ModIfaceCache(..))-import GHC.Unit-import GHC.Types.Name.Reader as RdrName (mkOrig)-import GHC.Builtin.Names (gHC_GHCI_HELPERS)-import GHC.Runtime.Interpreter-import GHC.Runtime.Context-import GHCi.RemoteTypes-import GHC.Hs (ImportDecl, GhcPs, GhciLStmt, LHsDecl)-import GHC.Hs.Utils-import GHC.Utils.Misc-import GHC.Utils.Logger--import GHC.Utils.Exception hiding (uninterruptibleMask, mask, catch)-import Numeric-import Data.Array-import Data.IORef-import Data.Time-import System.Environment-import System.IO-import Control.Monad-import Prelude hiding ((<>))--import System.Console.Haskeline (CompletionFunc, InputT)-import Control.Monad.Catch as MC-import Control.Monad.Trans.Class-import Control.Monad.Trans.Reader-import Control.Monad.IO.Class-import Data.Map.Strict (Map)-import qualified Data.IntMap.Strict as IntMap-import qualified GHC.Data.EnumSet as EnumSet-import qualified GHC.LanguageExtensions as LangExt---- DAP add.-import qualified GHCi.DAP.Type as DAP-import Control.Concurrent-import GHC.Types.SourceError----------------------------------------------------------------------------------- GHCi monad--data GHCiState = GHCiState-     {-        progname       :: String,-        args           :: [String],-        evalWrapper    :: ForeignHValue, -- ^ of type @IO a -> IO a@-        prompt         :: PromptFunction,-        prompt_cont    :: PromptFunction,-        editor         :: String,-        stop           :: String,-        multiMode      :: Bool,-        localConfig    :: LocalConfigBehaviour,-        options        :: [GHCiOption],-        line_number    :: !Int,         -- ^ input line-        break_ctr      :: !Int,-        breaks         :: !(IntMap.IntMap BreakLocation),-        tickarrays     :: ModuleEnv TickArray,-            -- ^ 'tickarrays' caches the 'TickArray' for loaded modules,-            -- so that we don't rebuild it each time the user sets-            -- a breakpoint.-        ghci_commands  :: [Command],-            -- ^ available ghci commands-        ghci_macros    :: [Command],-            -- ^ user-defined macros-        last_command   :: Maybe Command,-            -- ^ @:@ at the GHCi prompt repeats the last command, so we-            -- remember it here-        cmd_wrapper    :: InputT GHCi CommandResult -> InputT GHCi (Maybe Bool),-            -- ^ The command wrapper is run for each command or statement.-            -- The 'Bool' value denotes whether the command is successful and-            -- 'Nothing' means to exit GHCi.-        cmdqueue       :: [String],--        remembered_ctx :: [InteractiveImport],-            -- ^ The imports that the user has asked for, via import-            -- declarations and :module commands.  This list is-            -- persistent over :reloads (but any imports for modules-            -- that are not loaded are temporarily ignored).  After a-            -- :load, all the home-package imports are stripped from-            -- this list.-            ---            -- See bugs #2049, #1873, #1360--        transient_ctx  :: [InteractiveImport],-            -- ^ An import added automatically after a :load, usually of-            -- the most recently compiled module.  May be empty if-            -- there are no modules loaded.  This list is replaced by-            -- :load, :reload, and :add.  In between it may be modified-            -- by :module.--        extra_imports  :: [ImportDecl GhcPs],-            -- ^ These are "always-on" imports, added to the-            -- context regardless of what other imports we have.-            -- This is useful for adding imports that are required-            -- by setGHCiMonad.  Be careful adding things here:-            -- you can create ambiguities if these imports overlap-            -- with other things in scope.-            ---            -- NB. although this is not currently used by GHCi itself,-            -- it was added to support other front-ends that are based-            -- on the GHCi code.  Potentially we could also expose-            -- this functionality via GHCi commands.--        prelude_imports :: [ImportDecl GhcPs],-            -- ^ These imports are added to the context when-            -- -XImplicitPrelude is on and we don't have a *-module-            -- in the context.  They can also be overridden by another-            -- import for the same module, e.g.-            -- "import Prelude hiding (map)"--        ghc_e :: Bool, -- ^ True if this is 'ghc -e' (or runghc)--        short_help :: String,-            -- ^ help text to display to a user-        long_help  :: String,-        lastErrorLocations :: IORef [(FastString, Int)],--        mod_infos  :: !(Map ModuleName ModInfo),--        flushStdHandles :: ForeignHValue,-            -- ^ @hFlush stdout; hFlush stderr@ in the interpreter-        noBuffering :: ForeignHValue,-            -- ^ @hSetBuffering NoBuffering@ for stdin/stdout/stderr-        ifaceCache :: ModIfaceCache,-        dapContextGHCiState :: DAP.MVarDAPContext-     }--type TickArray = Array Int [(GHC.BreakIndex,RealSrcSpan)]---- | A GHCi command-data Command-   = Command-   { cmdName           :: String-     -- ^ Name of GHCi command (e.g. "exit")-   , cmdAction         :: String -> InputT GHCi CmdExecOutcome-     -- ^ The 'CmdExecOutcome' value denotes whether to exit GHCi cleanly or error out-   , cmdHidden         :: Bool-     -- ^ Commands which are excluded from default completion-     -- and @:help@ summary. This is usually set for commands not-     -- useful for interactive use but rather for IDEs.-   , cmdCompletionFunc :: CompletionFunc GHCi-     -- ^ 'CompletionFunc' for arguments-   }---- | Used to denote GHCi command execution result. Specifically, used to--- distinguish between two ghci execution modes - "REPL" and "Expression--- evaluation mode (ghc -e)". When in "REPL" mode, we don't want to exit--- GHCi session when error occurs, (which is when we use "CmdSuccess").--- Otherwise, when in expression evaluation mode, all command failures--- should lead to GHCi session termination (with ExitFailure 1) which is--- when "CmdFailure" is used(this is useful when executing scripts).--- "CleanExit" is used to signal end of GHCi session (for example, when--- ":quit" command is called).-data CmdExecOutcome-  = CleanExit-  | CmdSuccess-  | CmdFailure--data CommandResult-   = CommandComplete-   { cmdInput :: String-   , cmdResult :: Either SomeException (Maybe Bool)-   , cmdStats :: ActionStats-   }-   | CommandIncomplete-     -- ^ Unterminated multiline command-   deriving Show--cmdSuccess :: MonadThrow m => CommandResult -> m (Maybe Bool)-cmdSuccess CommandComplete{ cmdResult = Left e } = throwM e-cmdSuccess CommandComplete{ cmdResult = Right r } = return r-cmdSuccess CommandIncomplete = return $ Just True--type PromptFunction = [String]-                   -> Int-                   -> GHCi SDoc--data GHCiOption-        = ShowTiming            -- show time/allocs after evaluation-        | ShowType              -- show the type of expressions-        | RevertCAFs            -- revert CAFs after every evaluation-        | Multiline             -- use multiline commands-        | CollectInfo           -- collect and cache information about-                                -- modules after load-        deriving Eq---- | Treatment of ./.ghci files.  For now we either load or--- ignore.  But later we could implement a "safe mode" where--- only safe operations are performed.----data LocalConfigBehaviour-  = SourceLocalConfig-  | IgnoreLocalConfig-  deriving (Eq)--data BreakLocation-   = BreakLocation-   { breakModule :: !GHC.Module-   , breakLoc    :: !SrcSpan-   , breakTick   :: {-# UNPACK #-} !Int-   , breakEnabled:: !Bool-   , onBreakCmd  :: String-   }--instance Eq BreakLocation where-  loc1 == loc2 = breakModule loc1 == breakModule loc2 &&-                 breakTick loc1   == breakTick loc2--prettyLocations :: IntMap.IntMap BreakLocation -> SDoc-prettyLocations  locs =-    case  IntMap.null locs of-      True  -> text "No active breakpoints."-      False -> vcat $ map (\(i, loc) -> brackets (int i) <+> ppr loc) $ IntMap.toAscList locs--instance Outputable BreakLocation where-   ppr loc = (ppr $ breakModule loc) <+> ppr (breakLoc loc) <+> pprEnaDisa <+>-                if null (onBreakCmd loc)-                   then empty-                   else doubleQuotes (text (onBreakCmd loc))-      where pprEnaDisa = case breakEnabled loc of-                True  -> text "enabled"-                False -> text "disabled"--recordBreak-  :: GhciMonad m => BreakLocation -> m (Bool{- was already present -}, Int)-recordBreak brkLoc = do-   st <- getGHCiState-   let oldmap = breaks st-       oldActiveBreaks = IntMap.assocs oldmap-   -- don't store the same break point twice-   case [ nm | (nm, loc) <- oldActiveBreaks, loc == brkLoc ] of-     (nm:_) -> return (True, nm)-     [] -> do-      let oldCounter = break_ctr st-          newCounter = oldCounter + 1-      setGHCiState $ st { break_ctr = newCounter,-                          breaks = IntMap.insert oldCounter brkLoc oldmap-                        }-      return (False, oldCounter)--newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> Ghc a }-    deriving (Functor)-    deriving (MonadThrow, MonadCatch, MonadMask) via (ReaderT (IORef GHCiState) Ghc)--reflectGHCi :: (Session, IORef GHCiState) -> GHCi a -> IO a-reflectGHCi (s, gs) m = unGhc (unGHCi m gs) s--startGHCi :: GHCi a -> GHCiState -> Ghc a-startGHCi g state = do ref <- liftIO $ newIORef state; unGHCi g ref--instance Applicative GHCi where-    pure a = GHCi $ \_ -> pure a-    (<*>) = ap--instance Monad GHCi where-  (GHCi m) >>= k  =  GHCi $ \s -> m s >>= \a -> unGHCi (k a) s--class GhcMonad m => GhciMonad m where-  getGHCiState    :: m GHCiState-  setGHCiState    :: GHCiState -> m ()-  modifyGHCiState :: (GHCiState -> GHCiState) -> m ()-  reifyGHCi       :: ((Session, IORef GHCiState) -> IO a) -> m a--instance GhciMonad GHCi where-  getGHCiState      = GHCi $ \r -> liftIO $ readIORef r-  setGHCiState s    = GHCi $ \r -> liftIO $ writeIORef r s-  modifyGHCiState f = GHCi $ \r -> liftIO $ modifyIORef' r f-  reifyGHCi f       = GHCi $ \r -> reifyGhc $ \s -> f (s, r)--instance GhciMonad (InputT GHCi) where-  getGHCiState    = lift getGHCiState-  setGHCiState    = lift . setGHCiState-  modifyGHCiState = lift . modifyGHCiState-  reifyGHCi       = lift . reifyGHCi--liftGhc :: Ghc a -> GHCi a-liftGhc m = GHCi $ \_ -> m--instance MonadIO GHCi where-  liftIO = liftGhc . liftIO--instance HasDynFlags GHCi where-  getDynFlags = getSessionDynFlags--instance HasLogger GHCi where-  getLogger = hsc_logger <$> getSession--instance GhcMonad GHCi where-  setSession s' = liftGhc $ setSession s'-  getSession    = liftGhc $ getSession---instance HasDynFlags (InputT GHCi) where-  getDynFlags = lift getDynFlags--instance HasLogger (InputT GHCi) where-  getLogger = lift getLogger--instance GhcMonad (InputT GHCi) where-  setSession = lift . setSession-  getSession = lift getSession--isOptionSet :: GhciMonad m => GHCiOption -> m Bool-isOptionSet opt- = do st <- getGHCiState-      return $! (opt `elem` options st)--setOption :: GhciMonad m => GHCiOption -> m ()-setOption opt- = do st <- getGHCiState-      setGHCiState (st{ options = opt : filter (/= opt) (options st) })--unsetOption :: GhciMonad m => GHCiOption -> m ()-unsetOption opt- = do st <- getGHCiState-      setGHCiState (st{ options = filter (/= opt) (options st) })--printForUserNeverQualify :: GhcMonad m => SDoc -> m ()-printForUserNeverQualify doc = do-  dflags <- GHC.getInteractiveDynFlags-  liftIO $ Ppr.printForUser dflags stdout neverQualify AllTheWay doc--printForUserModInfo :: GhcMonad m => GHC.ModuleInfo -> SDoc -> m ()-printForUserModInfo info doc = do-  dflags <- GHC.getInteractiveDynFlags-  mUnqual <- GHC.mkPrintUnqualifiedForModule info-  unqual <- maybe GHC.getPrintUnqual return mUnqual-  liftIO $ Ppr.printForUser dflags stdout unqual AllTheWay doc--printForUser :: GhcMonad m => SDoc -> m ()-printForUser doc = do-  unqual <- GHC.getPrintUnqual-  dflags <- GHC.getInteractiveDynFlags-  liftIO $ Ppr.printForUser dflags stdout unqual AllTheWay doc--printForUserPartWay :: GhcMonad m => SDoc -> m ()-printForUserPartWay doc = do-  unqual <- GHC.getPrintUnqual-  dflags <- GHC.getInteractiveDynFlags-  liftIO $ Ppr.printForUser dflags stdout unqual DefaultDepth doc---- | Run a single Haskell expression-runStmt-  :: GhciMonad m-  => GhciLStmt GhcPs -> String -> GHC.SingleStep -> m (Maybe GHC.ExecResult)-runStmt stmt stmt_text step = do-  st <- getGHCiState-  GHC.handleSourceError (\e -> do GHC.printException e; dapSaveRunStmtDeclException e; return Nothing) $ do    -- DAP modified.-    let opts = GHC.execOptions-                  { GHC.execSourceFile = progname st-                  , GHC.execLineNumber = line_number st-                  , GHC.execSingleStep = step-                  , GHC.execWrap = \fhv -> EvalApp (EvalThis (evalWrapper st))-                                                   (EvalThis fhv) }-    Just <$> GHC.execStmt' stmt stmt_text opts--runDecls :: GhciMonad m => String -> m (Maybe [GHC.Name])-runDecls decls = do-  st <- getGHCiState-  reifyGHCi $ \x ->-    withProgName (progname st) $-    withArgs (args st) $-      reflectGHCi x $ do-        GHC.handleSourceError (\e -> do GHC.printException e;-                                        dapSaveRunStmtDeclException e;         -- DAP added.-                                        return Nothing) $ do-          r <- GHC.runDeclsWithLocation (progname st) (line_number st) decls-          return (Just r)--runDecls' :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe [GHC.Name])-runDecls' decls = do-  st <- getGHCiState-  reifyGHCi $ \x ->-    withProgName (progname st) $-    withArgs (args st) $-    reflectGHCi x $-      GHC.handleSourceError-        (\e -> do GHC.printException e;-                  return Nothing)-        (Just <$> GHC.runParsedDecls decls)--resume :: GhciMonad m => (SrcSpan -> Bool) -> GHC.SingleStep -> Maybe Int -> m GHC.ExecResult-resume canLogSpan step mbIgnoreCnt = do-  st <- getGHCiState-  reifyGHCi $ \x ->-    withProgName (progname st) $-    withArgs (args st) $-      reflectGHCi x $ do-        GHC.resumeExec canLogSpan step mbIgnoreCnt---- ----------------------------------------------------------------------------- timing & statistics--data ActionStats = ActionStats-  { actionAllocs :: Maybe Integer-  , actionElapsedTime :: Double-  } deriving Show--runAndPrintStats-  :: GhciMonad m-  => (a -> Maybe Integer)-  -> m a-  -> m (ActionStats, Either SomeException a)-runAndPrintStats getAllocs action = do-  result <- runWithStats getAllocs action-  case result of-    (stats, Right{}) -> do-      showTiming <- isOptionSet ShowTiming-      when showTiming $ do-        dflags  <- getDynFlags-        liftIO $ printStats dflags stats-    _ -> return ()-  return result--runWithStats-  :: ExceptionMonad m-  => (a -> Maybe Integer) -> m a -> m (ActionStats, Either SomeException a)-runWithStats getAllocs action = do-  t0 <- liftIO getCurrentTime-  result <- MC.try action-  let allocs = either (const Nothing) getAllocs result-  t1 <- liftIO getCurrentTime-  let elapsedTime = realToFrac $ t1 `diffUTCTime` t0-  return (ActionStats allocs elapsedTime, result)--printStats :: DynFlags -> ActionStats -> IO ()-printStats dflags ActionStats{actionAllocs = mallocs, actionElapsedTime = secs}-   = do let secs_str = showFFloat (Just 2) secs-        putStrLn (Ppr.showSDoc dflags (-                 parens (text (secs_str "") <+> text "secs" <> comma <+>-                         case mallocs of-                           Nothing -> empty-                           Just allocs ->-                             text (separateThousands allocs) <+> text "bytes")))-  where-    separateThousands n = reverse . sep . reverse . show $ n-      where sep n'-              | n' `lengthAtMost` 3 = n'-              | otherwise           = take 3 n' ++ "," ++ sep (drop 3 n')---------------------------------------------------------------------------------- reverting CAFs--revertCAFs :: GhciMonad m => m ()-revertCAFs = do-  interp <- hscInterp <$> GHC.getSession-  liftIO $ interpCmd interp RtsRevertCAFs-  s <- getGHCiState-  when (not (ghc_e s)) turnOffBuffering-     -- Have to turn off buffering again, because we just-     -- reverted stdout, stderr & stdin to their defaults.----------------------------------------------------------------------------------- To flush buffers for the *interpreted* computation we need--- to refer to *its* stdout/stderr handles---- | Compile "hFlush stdout; hFlush stderr" once, so we can use it repeatedly-initInterpBuffering :: Ghc (ForeignHValue, ForeignHValue)-initInterpBuffering = do-  let mkHelperExpr :: OccName -> Ghc ForeignHValue-      mkHelperExpr occ =-        GHC.compileParsedExprRemote-        $ GHC.nlHsVar $ RdrName.mkOrig gHC_GHCI_HELPERS occ-  nobuf <- mkHelperExpr $ mkVarOcc "disableBuffering"-  flush <- mkHelperExpr $ mkVarOcc "flushAll"-  return (nobuf, flush)---- | Invoke "hFlush stdout; hFlush stderr" in the interpreter-flushInterpBuffers :: GhciMonad m => m ()-flushInterpBuffers = do-  st <- getGHCiState-  interp <- hscInterp <$> GHC.getSession-  liftIO $ evalIO interp (flushStdHandles st)---- | Turn off buffering for stdin, stdout, and stderr in the interpreter-turnOffBuffering :: GhciMonad m => m ()-turnOffBuffering = do-  st <- getGHCiState-  turnOffBuffering_ (noBuffering st)--turnOffBuffering_ :: GhcMonad m => ForeignHValue -> m ()-turnOffBuffering_ fhv = do-  interp <- hscInterp <$> getSession-  liftIO $ evalIO interp fhv--mkEvalWrapper :: GhcMonad m => String -> [String] ->  m ForeignHValue-mkEvalWrapper progname args =-  runInternal $ GHC.compileParsedExprRemote-  $ evalWrapper `GHC.mkHsApp` nlHsString progname-                `GHC.mkHsApp` nlList (map nlHsString args)-  where-    nlHsString = nlHsLit . mkHsString-    evalWrapper =-      GHC.nlHsVar $ RdrName.mkOrig gHC_GHCI_HELPERS (mkVarOcc "evalWrapper")---- | Run a 'GhcMonad' action to compile an expression for internal usage.-runInternal :: GhcMonad m => m a -> m a-runInternal =-    withTempSession mkTempSession-  where-    mkTempSession = hscUpdateFlags (\dflags -> dflags-      { -- Running GHCi's internal expression is incompatible with -XSafe.-          -- We temporarily disable any Safe Haskell settings while running-          -- GHCi internal expressions. (see #12509)-        safeHaskell = Sf_None,-          -- Disable dumping of any data during evaluation of GHCi's internal-          -- expressions. (#17500)-        dumpFlags = EnumSet.empty-      }-        -- RebindableSyntax can wreak havoc with GHCi in several ways-          -- (see #13385 and #14342 for examples), so we temporarily-          -- disable it too.-          `xopt_unset` LangExt.RebindableSyntax-          -- We heavily depend on -fimplicit-import-qualified to compile expr-          -- with fully qualified names without imports.-          `gopt_set` Opt_ImplicitImportQualified-      )--compileGHCiExpr :: GhcMonad m => String -> m ForeignHValue-compileGHCiExpr expr = runInternal $ GHC.compileExprRemote expr------------------------------------------------------------------------------------------------------  DAP Utility----------------------------------------------------------------------------------------------------- |----dapSaveRunStmtDeclException :: GhciMonad m => SourceError -> m SourceError-dapSaveRunStmtDeclException res = do-  mvarCtx <- dapContextGHCiState <$> getGHCiState--  ctx <- liftIO $ takeMVar mvarCtx-  liftIO $ putMVar mvarCtx ctx{DAP.runStmtDeclExceptionDAPContext = Just res}--  return res----- |----dapLookupMaxBreakLocation :: GhciMonad m => m (Maybe (Int, BreakLocation))-dapLookupMaxBreakLocation = do-  newSt <- getGHCiState-  return $ IntMap.lookupMax (breaks newSt)--
− app-ghc-9.4/GHCi/UI/Tags.hs
@@ -1,223 +0,0 @@------------------------------------------------------------------------------------ GHCi's :ctags and :etags commands------ (c) The GHC Team 2005-2007-----------------------------------------------------------------------------------{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-module GHCi.UI.Tags (-  createCTagsWithLineNumbersCmd,-  createCTagsWithRegExesCmd,-  createETagsFileCmd-) where--import GHC.Utils.Exception-import GHC-import GHCi.UI.Monad-import GHC.Utils.Outputable---- ToDo: figure out whether we need these, and put something appropriate--- into the GHC API instead-import GHC.Types.Name (nameOccName)-import GHC.Types.Name.Occurrence (pprOccName)-import GHC.Core.ConLike-import GHC.Utils.Monad-import GHC.Unit.State-import GHC.Driver.Env--import Control.Monad-import Data.Function-import Data.List (sort, sortBy, groupBy)-import Data.Maybe-import Data.Ord-import GHC.Driver.Phases-import GHC.Driver.Ppr-import GHC.Utils.Panic-import Prelude-import System.Directory-import System.IO-import System.IO.Error---------------------------------------------------------------------------------- create tags file for currently loaded modules.--createCTagsWithLineNumbersCmd, createCTagsWithRegExesCmd,-  createETagsFileCmd :: String -> GHCi ()--createCTagsWithLineNumbersCmd ""   =-  ghciCreateTagsFile CTagsWithLineNumbers "tags"-createCTagsWithLineNumbersCmd file =-  ghciCreateTagsFile CTagsWithLineNumbers file--createCTagsWithRegExesCmd ""   =-  ghciCreateTagsFile CTagsWithRegExes "tags"-createCTagsWithRegExesCmd file =-  ghciCreateTagsFile CTagsWithRegExes file--createETagsFileCmd ""    = ghciCreateTagsFile ETags "TAGS"-createETagsFileCmd file  = ghciCreateTagsFile ETags file--data TagsKind = ETags | CTagsWithLineNumbers | CTagsWithRegExes--ghciCreateTagsFile :: TagsKind -> FilePath -> GHCi ()-ghciCreateTagsFile kind file = do-  liftIO $ putStrLn "Tags generation from GHCi will be deprecated in future releases"-  liftIO $ putStrLn "Use the method described in https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/GHCi/Tags"-  createTagsFile kind file---- ToDo:---      - remove restriction that all modules must be interpreted---        (problem: we don't know source locations for entities unless---        we compiled the module.------      - extract createTagsFile so it can be used from the command-line---        (probably need to fix first problem before this is useful).----createTagsFile :: TagsKind -> FilePath -> GHCi ()-createTagsFile tagskind tagsFile = do-  graph <- GHC.getModuleGraph-  mtags <- mapM listModuleTags (map GHC.ms_mod $ GHC.mgModSummaries graph)-  either_res <- liftIO $ collateAndWriteTags tagskind tagsFile $ concat mtags-  case either_res of-    Left e  -> liftIO $ hPutStrLn stderr $ ioeGetErrorString e-    Right _ -> return ()---listModuleTags :: GHC.Module -> GHCi [TagInfo]-listModuleTags m = do-  is_interpreted <- GHC.moduleIsInterpreted m-  -- should we just skip these?-  when (not is_interpreted) $-    let mName = GHC.moduleNameString (GHC.moduleName m) in-    throwGhcException (CmdLineError ("module '" ++ mName ++ "' is not interpreted"))-  mbModInfo <- GHC.getModuleInfo m-  case mbModInfo of-    Nothing -> return []-    Just mInfo -> do-       dflags <- getDynFlags-       unit_state <- hsc_units <$> getSession-       mb_print_unqual <- GHC.mkPrintUnqualifiedForModule mInfo-       let unqual = fromMaybe GHC.alwaysQualify mb_print_unqual-       let names = fromMaybe [] $ GHC.modInfoTopLevelScope mInfo-       let localNames = filter ((m==) . nameModule) names-       mbTyThings <- mapM GHC.lookupName localNames-       return $! [ tagInfo dflags unit_state unqual exported kind name realLoc-                     | tyThing <- catMaybes mbTyThings-                     , let name = getName tyThing-                     , let exported = GHC.modInfoIsExportedName mInfo name-                     , let kind = tyThing2TagKind tyThing-                     , let loc = srcSpanStart (nameSrcSpan name)-                     , RealSrcLoc realLoc _ <- [loc]-                     ]--  where-    tyThing2TagKind (AnId _)                 = 'v'-    tyThing2TagKind (AConLike RealDataCon{}) = 'd'-    tyThing2TagKind (AConLike PatSynCon{})   = 'p'-    tyThing2TagKind (ATyCon _)               = 't'-    tyThing2TagKind (ACoAxiom _)             = 'x'---data TagInfo = TagInfo-  { tagExported :: Bool -- is tag exported-  , tagKind :: Char   -- tag kind-  , tagName :: String -- tag name-  , tagFile :: String -- file name-  , tagLine :: Int    -- line number-  , tagCol :: Int     -- column number-  , tagSrcInfo :: Maybe (String,Integer)  -- source code line and char offset-  }----- get tag info, for later translation into Vim or Emacs style-tagInfo :: DynFlags -> UnitState -> PrintUnqualified-        -> Bool -> Char -> Name -> RealSrcLoc-        -> TagInfo-tagInfo dflags unit_state unqual exported kind name loc-    = TagInfo exported kind-        (showSDocForUser dflags unit_state unqual $ pprOccName (nameOccName name))-        (showSDocForUser dflags unit_state unqual $ ftext (srcLocFile loc))-        (srcLocLine loc) (srcLocCol loc) Nothing---- throw an exception when someone tries to overwrite existing source file (fix for #10989)-writeTagsSafely :: FilePath -> String -> IO ()-writeTagsSafely file str = do-    dfe <- doesFileExist file-    if dfe && isSourceFilename file-        then throwGhcException (CmdLineError (file ++ " is existing source file. " ++-             "Please specify another file name to store tags data"))-        else writeFile file str--collateAndWriteTags :: TagsKind -> FilePath -> [TagInfo] -> IO (Either IOError ())--- ctags style with the Ex expression being just the line number, Vim et al-collateAndWriteTags CTagsWithLineNumbers file tagInfos = do-  let tags = unlines $ sort $ map showCTag tagInfos-  tryIO (writeTagsSafely file tags)---- ctags style with the Ex expression being a regex searching the line, Vim et al-collateAndWriteTags CTagsWithRegExes file tagInfos = do -- ctags style, Vim et al-  tagInfoGroups <- makeTagGroupsWithSrcInfo tagInfos-  let tags = unlines $ sort $ map showCTag $ concat tagInfoGroups-  tryIO (writeTagsSafely file tags)--collateAndWriteTags ETags file tagInfos = do -- etags style, Emacs/XEmacs-  tagInfoGroups <- makeTagGroupsWithSrcInfo $ filter tagExported tagInfos-  let tagGroups = map processGroup tagInfoGroups-  tryIO (writeTagsSafely file $ concat tagGroups)--  where-    processGroup [] = throwGhcException (CmdLineError "empty tag file group??")-    processGroup group@(tagInfo:_) =-      let tags = unlines $ map showETag group in-      "\x0c\n" ++ tagFile tagInfo ++ "," ++ show (length tags) ++ "\n" ++ tags---makeTagGroupsWithSrcInfo :: [TagInfo] -> IO [[TagInfo]]-makeTagGroupsWithSrcInfo tagInfos = do-  let groups = groupBy ((==) `on` tagFile) $ sortBy (comparing tagFile) tagInfos-  mapM addTagSrcInfo groups--  where-    addTagSrcInfo [] = throwGhcException (CmdLineError "empty tag file group??")-    addTagSrcInfo group@(tagInfo:_) = do-      file <- readFile $ tagFile tagInfo-      let sortedGroup = sortBy (comparing tagLine) group-      return $ perFile sortedGroup 1 0 $ lines file--    perFile allTags@(tag:tags) cnt pos allLs@(l:ls)-     | tagLine tag > cnt =-         perFile allTags (cnt+1) (pos+fromIntegral(length l)) ls-     | tagLine tag == cnt =-         tag{ tagSrcInfo = Just(l,pos) } : perFile tags cnt pos allLs-    perFile _ _ _ _ = []----- ctags format, for Vim et al-showCTag :: TagInfo -> String-showCTag ti =-  tagName ti ++ "\t" ++ tagFile ti ++ "\t" ++ tagCmd ++ ";\"\t" ++-    tagKind ti : ( if tagExported ti then "" else "\tfile:" )--  where-    tagCmd =-      case tagSrcInfo ti of-        Nothing -> show $ tagLine ti-        Just (srcLine,_) -> "/^"++ foldr escapeSlashes [] srcLine ++"$/"--      where-        escapeSlashes '/' r = '\\' : '/' : r-        escapeSlashes '\\' r = '\\' : '\\' : r-        escapeSlashes c r = c : r----- etags format, for Emacs/XEmacs-showETag :: TagInfo -> String-showETag TagInfo{ tagName = tag, tagLine = lineNo, tagCol = colNo,-                  tagSrcInfo = Just (srcLine,charPos) }-    =  take (colNo - 1) srcLine ++ tag-    ++ "\x7f" ++ tag-    ++ "\x01" ++ show lineNo-    ++ "," ++ show charPos-showETag _ = throwGhcException (CmdLineError "missing source file info in showETag")
− app-ghc-9.4/GHCi/Util.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE MagicHash, UnboxedTuples #-}---- | Utilities for GHCi.-module GHCi.Util where---- NOTE: Avoid importing GHC modules here, because the primary purpose--- of this module is to not use UnboxedTuples in a module that imports--- lots of other modules.  See issue#13101 for more info.--import GHC.Exts-import GHC.Types--anyToPtr :: a -> IO (Ptr ())-anyToPtr x =-  IO (\s -> case anyToAddr# x s of-              (# s', addr #) -> (# s', Ptr addr #)) :: IO (Ptr ())
ghci-dap.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           ghci-dap-version:        0.0.22.0+version:        0.0.23.0 synopsis:       ghci-dap is a GHCi having DAP interface. description:    Please see README.md category:       Development@@ -13,7 +13,7 @@ bug-reports:    https://github.com/phoityne/ghci-dap/issues author:         phoityne_hs maintainer:     phoityne.hs@gmail.com-copyright:      2017-2023 phoityne_hs+copyright:      2017-2024 phoityne_hs license:        BSD3 license-file:   LICENSE build-type:     Simple@@ -103,7 +103,7 @@         GHCMain     hs-source-dirs:         app-ghc-8.10-  if (impl(ghc >= 9.4.1)) && (impl(ghc < 9.5.0))+  if (impl(ghc >= 9.6.1)) && (impl(ghc < 9.7.0))     other-modules:         GHCi.GhcApiCompat         GHCi.Leak@@ -114,20 +114,20 @@         GHCi.Util         GHCMain     hs-source-dirs:-        app-ghc-9.4-  if (impl(ghc >= 9.6.1)) && (impl(ghc < 9.7.0))+        app-ghc-9.6+  if (impl(ghc >= 9.8.1)) && (impl(ghc < 9.9.0))     other-modules:         GHCi.GhcApiCompat         GHCi.Leak         GHCi.UI         GHCi.UI.Info         GHCi.UI.Monad-        GHCi.UI.Tags+        GHCi.UI.Exception         GHCi.Util         GHCMain     hs-source-dirs:-        app-ghc-9.6-  if (impl(ghc >= 9.8.1)) && (impl(ghc < 9.9.0))+        app-ghc-9.8+  if (impl(ghc >= 9.10.1)) && (impl(ghc < 9.11.0))     other-modules:         GHCi.GhcApiCompat         GHCi.Leak@@ -138,7 +138,7 @@         GHCi.Util         GHCMain     hs-source-dirs:-        app-ghc-9.8+        app-ghc-9.10   if os(windows)     build-depends:         Win32