+#ifdef GHCI
+-----------------------------------------------------------------------------
+-- Setting the context doesn't throw away any bindings; the bindings
+-- we've built up in the InteractiveContext simply move to the new
+-- module. They always shadow anything in scope in the current context.
+
+cmSetContext
+ :: CmState -> DynFlags
+ -> [String] -- take the top-level scopes of these modules
+ -> [String] -- and the just the exports from these
+ -> IO CmState
+cmSetContext cmstate dflags toplevs exports = do
+ let CmState{ hpt=hpt, pcs=pcs, ic=old_ic } = cmstate
+ hsc_env = HscEnv { hsc_mode = Interactive, hsc_dflags = dflags,
+ hsc_HPT = hpt }
+
+ toplev_mods <- mapM (getTopLevModule hpt) (map mkModuleName toplevs)
+ export_mods <- mapM (moduleNameToModule hpt) (map mkModuleName exports)
+
+ (new_pcs, maybe_env)
+ <- mkGlobalContext hsc_env pcs toplev_mods export_mods
+
+ case maybe_env of
+ Nothing -> return cmstate
+ Just env -> return cmstate{ pcs = new_pcs,
+ ic = old_ic{ ic_toplev_scope = toplev_mods,
+ ic_exports = export_mods,
+ ic_rn_gbl_env = env } }
+
+getTopLevModule hpt mn =
+ case lookupModuleEnvByName hpt mn of
+
+ Just mod_info
+ | isJust (mi_globals iface) -> return (mi_module iface)
+ where
+ iface = hm_iface mod_info
+
+ _other -> throwDyn (CmdLineError (
+ "cannot enter the top-level scope of a compiled module (module `" ++
+ moduleNameUserString mn ++ "')"))
+
+moduleNameToModule :: HomePackageTable -> ModuleName -> IO Module
+moduleNameToModule hpt mn = do
+ case lookupModuleEnvByName hpt mn of
+ Just mod_info -> return (mi_module (hm_iface mod_info))
+ _not_a_home_module -> do
+ maybe_stuff <- findModule mn
+ case maybe_stuff of
+ Left _ -> throwDyn (CmdLineError ("can't find module `"
+ ++ moduleNameUserString mn ++ "'"))
+ Right (m,_) -> return m
+
+cmGetContext :: CmState -> IO ([String],[String])
+cmGetContext CmState{ic=ic} =
+ return (map moduleUserString (ic_toplev_scope ic),
+ map moduleUserString (ic_exports ic))
+
+cmModuleIsInterpreted :: CmState -> String -> IO Bool
+cmModuleIsInterpreted cmstate str
+ = case lookupModuleEnvByName (hpt cmstate) (mkModuleName str) of
+ Just details -> return (isJust (mi_globals (hm_iface details)))
+ _not_a_home_module -> return False
+
+-----------------------------------------------------------------------------
+-- cmInfoThing: convert a String to a TyThing
+
+-- A string may refer to more than one TyThing (eg. a constructor,
+-- and type constructor), so we return a list of all the possible TyThings.
+
+cmInfoThing :: CmState -> DynFlags -> String -> IO (CmState, [(TyThing,Fixity)])
+cmInfoThing cmstate dflags id
+ = do (new_pcs, things) <- hscThing hsc_env pcs icontext id
+ let new_pit = eps_PIT (pcs_EPS new_pcs)
+ pairs = map (\x -> (x, getFixity new_pit (getName x))) things
+ return (cmstate{ pcs=new_pcs }, pairs)
+ where
+ CmState{ hpt=hpt, pcs=pcs, ic=icontext } = cmstate
+ hsc_env = HscEnv { hsc_mode = Interactive,
+ hsc_dflags = dflags,
+ hsc_HPT = hpt }
+
+ getFixity :: PackageIfaceTable -> Name -> Fixity
+ getFixity pit name
+ | isExternalName name,
+ Just iface <- lookupIface hpt pit (nameModule name),
+ Just (FixitySig _ fixity _) <- lookupNameEnv (mi_fixities iface) name
+ = fixity
+ | otherwise
+ = defaultFixity
+
+-- ---------------------------------------------------------------------------
+-- cmBrowseModule: get all the TyThings defined in a module
+
+cmBrowseModule :: CmState -> DynFlags -> String -> Bool
+ -> IO (CmState, [TyThing])
+cmBrowseModule cmstate dflags str exports_only = do
+ let mn = mkModuleName str
+ mod <- moduleNameToModule hpt mn
+ (pcs1, maybe_ty_things)
+ <- getModuleContents hsc_env pcs mod exports_only
+ case maybe_ty_things of
+ Nothing -> return (cmstate{pcs=pcs1}, [])
+ Just ty_things -> return (cmstate{pcs=pcs1}, ty_things)
+ where
+ hsc_env = HscEnv { hsc_mode = Interactive, hsc_dflags = dflags,
+ hsc_HPT = hpt }
+ CmState{ hpt=hpt, pcs=pcs, ic=icontext } = cmstate
+
+-----------------------------------------------------------------------------
+-- cmRunStmt: Run a statement/expr.
+
+data CmRunResult
+ = CmRunOk [Name] -- names bound by this evaluation
+ | CmRunFailed
+ | CmRunException Exception -- statement raised an exception
+
+cmRunStmt :: CmState -> DynFlags -> String -> IO (CmState, CmRunResult)
+cmRunStmt cmstate@CmState{ hpt=hpt, pcs=pcs, ic=icontext }
+ dflags expr
+ = do
+ let hsc_env = HscEnv { hsc_mode = Interactive,
+ hsc_dflags = dflags,
+ hsc_HPT = hpt }
+
+ (new_pcs, maybe_stuff)
+ <- hscStmt hsc_env pcs icontext expr
+
+ case maybe_stuff of
+ Nothing -> return (cmstate{ pcs=new_pcs }, CmRunFailed)
+ Just (new_ic, names, hval) -> do
+
+ let thing_to_run = unsafeCoerce# hval :: IO [HValue]
+ either_hvals <- sandboxIO thing_to_run
+
+ case either_hvals of
+ Left e -> do
+ -- on error, keep the *old* interactive context,
+ -- so that 'it' is not bound to something
+ -- that doesn't exist.
+ return ( cmstate{ pcs=new_pcs }, CmRunException e )
+
+ Right hvals -> do
+ -- Get the newly bound things, and bind them.
+ -- Don't need to delete any shadowed bindings;
+ -- the new ones override the old ones.
+ extendLinkEnv (zip names hvals)
+
+ return (cmstate{ pcs=new_pcs, ic=new_ic },
+ CmRunOk names)
+
+
+-- We run the statement in a "sandbox" to protect the rest of the
+-- system from anything the expression might do. For now, this
+-- consists of just wrapping it in an exception handler, but see below
+-- for another version.
+
+sandboxIO :: IO a -> IO (Either Exception a)
+sandboxIO thing = Exception.try thing
+
+{-
+-- This version of sandboxIO runs the expression in a completely new
+-- RTS main thread. It is disabled for now because ^C exceptions
+-- won't be delivered to the new thread, instead they'll be delivered
+-- to the (blocked) GHCi main thread.
+
+-- SLPJ: when re-enabling this, reflect a wrong-stat error as an exception
+
+sandboxIO :: IO a -> IO (Either Int (Either Exception a))
+sandboxIO thing = do
+ st_thing <- newStablePtr (Exception.try thing)
+ alloca $ \ p_st_result -> do
+ stat <- rts_evalStableIO st_thing p_st_result
+ freeStablePtr st_thing
+ if stat == 1
+ then do st_result <- peek p_st_result
+ result <- deRefStablePtr st_result
+ freeStablePtr st_result
+ return (Right result)
+ else do
+ return (Left (fromIntegral stat))
+
+foreign import "rts_evalStableIO" {- safe -}
+ rts_evalStableIO :: StablePtr (IO a) -> Ptr (StablePtr a) -> IO CInt
+ -- more informative than the C type!
+-}
+
+-----------------------------------------------------------------------------
+-- cmTypeOfExpr: returns a string representing the type of an expression
+
+cmTypeOfExpr :: CmState -> DynFlags -> String -> IO (CmState, Maybe String)
+cmTypeOfExpr cmstate dflags expr
+ = do (new_pcs, maybe_stuff) <- hscTcExpr hsc_env pcs ic expr
+
+ let new_cmstate = cmstate{pcs = new_pcs}
+
+ case maybe_stuff of
+ Nothing -> return (new_cmstate, Nothing)
+ Just ty -> return (new_cmstate, Just str)
+ where
+ str = showSDocForUser unqual (text expr <+> dcolon <+> ppr tidy_ty)
+ unqual = icPrintUnqual ic
+ tidy_ty = tidyType emptyTidyEnv ty
+ where
+ CmState{ hpt=hpt, pcs=pcs, ic=ic } = cmstate
+ hsc_env = HscEnv { hsc_mode = Interactive,
+ hsc_dflags = dflags,
+ hsc_HPT = hpt }
+
+
+
+-----------------------------------------------------------------------------
+-- cmTypeOfName: returns a string representing the type of a name.
+
+cmTypeOfName :: CmState -> Name -> IO (Maybe String)
+cmTypeOfName CmState{ pcs=pcs, ic=ic } name
+ = do
+ hPutStrLn stderr ("cmTypeOfName: " ++ showSDoc (ppr name))
+ case lookupNameEnv (ic_type_env ic) name of
+ Nothing -> return Nothing
+ Just (AnId id) -> return (Just str)
+ where
+ unqual = icPrintUnqual ic
+ ty = tidyType emptyTidyEnv (idType id)
+ str = showSDocForUser unqual (ppr ty)
+
+ _ -> panic "cmTypeOfName"
+
+-----------------------------------------------------------------------------
+-- cmCompileExpr: compile an expression and deliver an HValue
+
+cmCompileExpr :: CmState -> DynFlags -> String -> IO (CmState, Maybe HValue)
+cmCompileExpr cmstate dflags expr
+ = do
+ let hsc_env = HscEnv { hsc_mode = Interactive,
+ hsc_dflags = dflags,
+ hsc_HPT = hpt }
+
+ (new_pcs, maybe_stuff)
+ <- hscStmt hsc_env pcs icontext
+ ("let __cmCompileExpr = "++expr)
+
+ case maybe_stuff of
+ Nothing -> return (cmstate{ pcs=new_pcs }, Nothing)
+ Just (new_ic, names, hval) -> do
+
+ -- Run it!
+ hvals <- (unsafeCoerce# hval) :: IO [HValue]
+
+ case (names,hvals) of
+ ([n],[hv]) -> return (cmstate{ pcs=new_pcs }, Just hv)
+ _ -> panic "cmCompileExpr"
+