summaryrefslogtreecommitdiff
path: root/ghc/InteractiveUI.hs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/InteractiveUI.hs')
-rw-r--r--ghc/InteractiveUI.hs183
1 files changed, 178 insertions, 5 deletions
diff --git a/ghc/InteractiveUI.hs b/ghc/InteractiveUI.hs
index 2dcedb0b0b..4deab1c13f 100644
--- a/ghc/InteractiveUI.hs
+++ b/ghc/InteractiveUI.hs
@@ -1,5 +1,11 @@
-{-# LANGUAGE CPP, MagicHash, NondecreasingIndentation, TupleSections,
- RecordWildCards #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE NondecreasingIndentation #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
+
{-# OPTIONS -fno-cse #-}
-- -fno-cse is needed for GLOBAL_VAR's to behave properly
@@ -25,6 +31,9 @@ module InteractiveUI (
import qualified GhciMonad ( args, runStmt )
import GhciMonad hiding ( args, runStmt )
import GhciTags
+import GhciTypes
+import GhciInfo
+import GhciFind
import Debugger
-- The GHC interface
@@ -33,7 +42,7 @@ import ErrUtils
import GhcMonad ( modifySession )
import qualified GHC
import GHC ( LoadHowMuch(..), Target(..), TargetId(..), InteractiveImport(..),
- TyThing(..), Phase, BreakIndex, Resume, SingleStep, Ghc,
+ TyThing(..), Phase, BreakIndex, Resume, SingleStep, Ghc, getModuleGraph,
handleSourceError )
import HsImpExp
import HsSyn
@@ -80,6 +89,7 @@ import Data.IORef ( IORef, modifyIORef, newIORef, readIORef, writeIORef )
import Data.List ( find, group, intercalate, intersperse, isPrefixOf, nub,
partition, sort, sortBy )
import Data.Maybe
+import qualified Data.Map as M
import Exception hiding (catch)
@@ -192,6 +202,10 @@ ghciCommands = [
("steplocal", keepGoing stepLocalCmd, completeIdentifier),
("stepmodule",keepGoing stepModuleCmd, completeIdentifier),
("type", keepGoing' typeOfExpr, completeExpression),
+ ("type-at", keepGoing' typeAt, completeExpression),
+ ("all-types", keepGoing' allTypes, completeExpression),
+ ("uses", keepGoing' findAllUses, completeExpression),
+ ("loc-at", keepGoing' locationAt, completeExpression),
("trace", keepGoing traceCmd, completeExpression),
("undef", keepGoing undefineMacro, completeMacro),
("unset", keepGoing unsetOptions, completeSetOptions)
@@ -268,6 +282,15 @@ defFullHelpText =
" :run function [<arguments> ...] run the function with the given arguments\n" ++
" :script <filename> run the script <filename>\n" ++
" :type <expr> show the type of <expr>\n" ++
+ " :type-at <loc> show the type of <loc> of format: \n" ++
+ " <filename> <line> <col> <end-line> <end-col> <text>\n" ++
+ " text is used for when the span is out of date\n" ++
+ " :undef <cmd> undefine user-defined command :<cmd>\n" ++
+ " :loc-at <loc> return the location of the identifier at <loc> of format: \n" ++
+ " <filename> <line> <col> <end-line> <end-col> <text>\n" ++
+ " text is used for when the span is out of date\n" ++
+ " :all-types return a list of all types in the project including\n" ++
+ " sub-expressions and local bindings\n" ++
" :undef <cmd> undefine user-defined command :<cmd>\n" ++
" :!<command> run the shell command <command>\n" ++
"\n" ++
@@ -314,6 +337,7 @@ defFullHelpText =
" +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"++
@@ -439,6 +463,7 @@ interactiveUI config srcs maybe_exprs = do
ghc_e = isJust maybe_exprs,
short_help = shortHelpText config,
long_help = fullHelpText config,
+ mod_infos = M.empty,
lastErrorLocations = lastErrLocationsRef
}
@@ -1463,8 +1488,16 @@ loadModule' files = do
_ <- GHC.load LoadAllTargets
GHC.setTargets targets
- doLoad False LoadAllTargets
-
+ flag <- doLoad False LoadAllTargets
+ doCollectInfo <- lift (isOptionSet CollectInfo)
+ case flag of
+ Succeeded | doCollectInfo -> do
+ loaded <- getModuleGraph >>= filterM GHC.isLoaded . map GHC.ms_mod_name
+ v <- lift (fmap mod_infos getGHCiState)
+ !newInfos <- collectInfo v loaded
+ lift (modifyGHCiState (\s -> s { mod_infos = newInfos }))
+ _ -> return ()
+ return flag
-- :add
addModule :: [FilePath] -> InputT GHCi ()
@@ -1616,6 +1649,144 @@ typeOfExpr str
printForUser $ sep [text str, nest 2 (dcolon <+> pprTypeForUser ty)]
-----------------------------------------------------------------------------
+-- :type-at
+
+typeAt :: String -> InputT GHCi ()
+typeAt str =
+ handleSourceError
+ GHC.printException
+ (case parseSpan str of
+ Left err -> liftIO (putStr err)
+ Right (fp,sl,sc,el,ec,sample) ->
+ do infos <- fmap mod_infos (lift getGHCiState)
+ result <- findType infos fp sample sl sc el ec
+ case result of
+ Left err -> liftIO (putStrLn err)
+ Right (info, ty) ->
+ printForUserModInfo (modinfoInfo info)
+ (sep [text sample,nest 2 (dcolon <+> ppr ty)]))
+
+-----------------------------------------------------------------------------
+-- :uses
+
+findAllUses :: String -> InputT GHCi ()
+findAllUses str =
+ handleSourceError GHC.printException $
+ case parseSpan str of
+ Left err -> liftIO (putStr err)
+ Right (fp,sl,sc,el,ec,sample) ->
+ do infos <- fmap mod_infos (lift getGHCiState)
+ result <- findNameUses infos fp sample sl sc el ec
+ case result of
+ Left err -> liftIO (putStrLn err)
+ Right uses ->
+ forM_ uses
+ (\sp ->
+ case sp of
+ RealSrcSpan rs ->
+ liftIO (putStrLn (showSpan rs))
+ UnhelpfulSpan fs ->
+ liftIO (putStrLn (unpackFS fs)))
+ where showSpan span' =
+ unpackFS (srcSpanFile span') ++
+ ":(" ++
+ show (srcSpanStartLine span') ++
+ "," ++
+ show (srcSpanStartCol span') ++
+ ")-(" ++
+ show (srcSpanEndLine span') ++
+ "," ++
+ show (srcSpanEndCol span') ++
+ ")"
+
+-----------------------------------------------------------------------------
+-- :all-types
+
+allTypes :: String -> InputT GHCi ()
+allTypes _ =
+ handleSourceError
+ GHC.printException
+ (do infos <- fmap mod_infos (lift getGHCiState)
+ forM_ (M.elems infos)
+ (\mi ->
+ forM_ (modinfoSpans mi) (printSpan mi)))
+ where printSpan mi (SpanInfo sl sc el ec mty _) =
+ do df <- GHC.getSessionDynFlags
+ case (ml_hs_file (GHC.ms_location (modinfoSummary mi))) of
+ Just fp ->
+ case mty of
+ Nothing -> return ()
+ Just ty ->
+ liftIO
+ (putStrLn
+ (concat [fp ++":"
+ -- GHC exposes a 1-based column number because reasons.
+ ,"(" ++ show sl ++ "," ++ show (1+sc) ++ ")-(" ++
+ show el ++ "," ++ show (1+ec) ++ "): "
+ ,flatten (showSDocForUser
+ df
+ neverQualify
+ (pprTypeForUser ty))]))
+ Nothing -> return ()
+ where flatten = unwords . words
+
+-----------------------------------------------------------------------------
+-- :loc-at
+
+locationAt :: String -> InputT GHCi ()
+locationAt str =
+ handleSourceError GHC.printException $
+ case parseSpan str of
+ Left err -> liftIO (putStr err)
+ Right (fp,sl,sc,el,ec,sample) ->
+ do infos <- fmap mod_infos (lift getGHCiState)
+ result <- findLoc infos fp sample sl sc el ec
+ case result of
+ Left err -> liftIO (putStrLn err)
+ Right sp ->
+ case sp of
+ RealSrcSpan rs ->
+ liftIO (putStrLn (showSpan rs))
+ UnhelpfulSpan fs ->
+ liftIO (putStrLn (unpackFS fs))
+ where showSpan span' =
+ unpackFS (srcSpanFile span') ++ ":(" ++
+ show (srcSpanStartLine span') ++ "," ++
+ show (srcSpanStartCol span') ++
+ ")-(" ++
+ show (srcSpanEndLine span') ++ "," ++
+ show (srcSpanEndCol span') ++ ")"
+
+-----------------------------------------------------------------------------
+-- Helpers for locationAt/typeAt
+
+-- | Parse a span: <module-name/filepath> <sl> <sc> <el> <ec> <string>
+parseSpan :: String -> Either String (FilePath,Int,Int,Int,Int,String)
+parseSpan s =
+ case result of
+ Left err -> Left err
+ Right r -> Right r
+ where result =
+ case span (/= ' ') s of
+ (fp,s') ->
+ do (sl,s1) <- extractInt s'
+ (sc,s2) <- extractInt s1
+ (el,s3) <- extractInt s2
+ (ec,st) <- extractInt s3
+ -- GHC exposes a 1-based column number because reasons.
+ Right (fp,sl,sc-1,el,ec-1,st)
+ extractInt s' =
+ case span (/= ' ') (dropWhile1 (== ' ') s') of
+ (reads -> [(i,_)],s'') ->
+ Right (i,dropWhile1 (== ' ') s'')
+ _ ->
+ Left ("Expected integer in " ++ s')
+ where dropWhile1 _ [] = []
+ dropWhile1 p xs@(x:xs')
+ | p x = xs'
+ | otherwise = xs
+
+-----------------------------------------------------------------------------
-- :kind
kindOfType :: Bool -> String -> InputT GHCi ()
@@ -2325,6 +2496,7 @@ 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
@@ -2332,6 +2504,7 @@ optToStr Multiline = "m"
optToStr ShowTiming = "s"
optToStr ShowType = "t"
optToStr RevertCAFs = "r"
+optToStr CollectInfo = "c"
-- ---------------------------------------------------------------------------