leksah-0.4.2: src/IDE/Metainfo/GHCUtils.hs
-----------------------------------------------------------------------------
--
-- Module : IDE.Metainfo.GHCUtils
-- Copyright : 2007-2009 Jürgen Nicklisch-Franken
-- License : GPL
--
-- Maintainer : Jutaro <jutaro@leksah.org>
-- Stability : provisional
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------
module IDE.Metainfo.GHCUtils (
inGhc
, inGhcIO
, getInstalledPackageInfos
, findFittingPackages
, myParseModule
, parseHeader
) where
import IDE.Core.State (MessageLevel(..),sysMessage,IDEM(..),readIDE,IDE(..),IDEPackage(..))
import UniqFM (eltsUFM)
import Distribution.Simple (withinRange,PackageIdentifier(..),Dependency(..))
import qualified Distribution.InstalledPackageInfo as IPI (package)
import GHC
import StringBuffer (StringBuffer(..),hGetStringBuffer)
import FastString (mkFastString)
import Lexer (mkPState,ParseResult(..),getMessages,unP)
import Outputable (ppr)
import Bag (unitBag)
import IDE.FileUtils (getSysLibDir)
import ErrUtils (dumpIfSet_dyn,printErrorsAndWarnings,mkPlainErrMsg,showPass,ErrMsg(..),printBagOfErrors)
import PackageConfig (PackageConfig(..))
import Data.Foldable (maximumBy)
import DynFlags (defaultDynFlags)
import qualified Parser as P (parseModule,parseHeader)
import HscStats (ppSourceStats)
import Control.Monad.Trans
import DriverPipeline (preprocess)
import System.FilePath (takeDirectory)
inGhc :: Ghc a -> IDEM a
inGhc = liftIO . inGhcIO
inGhcIO :: Ghc a -> IO a
inGhcIO f = do
libDir <- getSysLibDir
runGhc (Just libDir) $ do
getSessionDynFlags >>= setSessionDynFlags
f
getInstalledPackageInfos :: Ghc [PackageConfig]
getInstalledPackageInfos = do
dflags1 <- getSessionDynFlags
setSessionDynFlags dflags1{flags = Opt_ReadUserPackageConf : (flags dflags1)}
pkgInfos <- case pkgDatabase dflags1 of
Nothing -> return []
Just fm -> return (eltsUFM fm)
return pkgInfos
findFittingPackages :: [Dependency] -> Ghc [PackageIdentifier]
findFittingPackages dependencyList = do
knownPackages <- getInstalledPackageInfos
let packages = map IPI.package knownPackages
return (concatMap (fittingKnown packages) dependencyList)
where
fittingKnown packages (Dependency dname versionRange) =
let filtered = filter (\ (PackageIdentifier name version) ->
name == dname && withinRange version versionRange)
packages
in if length filtered > 1
then [maximumBy (\a b -> compare (pkgVersion a) (pkgVersion b)) filtered]
else filtered
parseHeader :: FilePath -> String -> IDEM (Maybe [LImportDecl RdrName])
parseHeader fp str = do
activePack' <- readIDE activePack
case activePack' of
Nothing -> return Nothing
Just pack -> inGhc $ do
dflags <- getSessionDynFlags
let dflags2 = dflags {
topDir = takeDirectory (cabalFile pack),
hscTarget = HscNothing,
ghcMode = OneShot,
ghcLink = NoLink}
setSessionDynFlags dflags2
session <- getSession
dynFlags <- getSessionDynFlags
(_,fp) <- preprocess session (fp,Nothing)
dynFlags <- getSessionDynFlags
liftIO $ do
stringBuffer <- hGetStringBuffer fp
parseResult <- myParseModuleHeader dynFlags fp (Just stringBuffer)
case parseResult of
Right (L _ mod) -> return (Just (hsmodImports mod))
Left errMsg -> do
sysMessage Normal $ "Failed to parse " ++ fp
printBagOfErrors defaultDynFlags (unitBag errMsg)
return (Nothing)
---------------------------------------------------------------------
-- | Parser function copied here, because it is not exported
myParseModule :: DynFlags -> FilePath -> Maybe StringBuffer
-> IO (Either ErrMsg (Located (HsModule RdrName)))
myParseModule dflags src_filename maybe_src_buf
= -------------------------- Parser ----------------
showPass dflags "Parser" >>
{-# SCC "Parser" #-} do
-- sometimes we already have the buffer in memory, perhaps
-- because we needed to parse the imports out of it, or get the
-- module name.
buf <- case maybe_src_buf of
Just b -> return b
Nothing -> hGetStringBuffer src_filename
let loc = mkSrcLoc (mkFastString src_filename) 1 0
case unP P.parseModule (mkPState buf loc dflags) of {
PFailed span err -> return (Left (mkPlainErrMsg span err));
POk pst rdr_module -> do {
let {ms = getMessages pst};
printErrorsAndWarnings dflags ms;
-- when (errorsFound dflags ms) $ exitWith (ExitFailure 1);
dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr rdr_module) ;
dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"
(ppSourceStats False rdr_module) ;
return (Right rdr_module)
-- ToDo: free the string buffer later.
}}
---------------------------------------------------------------------
-- | Parser function copied here, because it is not exported
myParseModuleHeader :: DynFlags -> FilePath -> Maybe StringBuffer
-> IO (Either ErrMsg (Located (HsModule RdrName)))
myParseModuleHeader dflags src_filename maybe_src_buf
= -------------------------- Parser ----------------
showPass dflags "Parser" >>
{-# SCC "Parser" #-} do
-- sometimes we already have the buffer in memory, perhaps
-- because we needed to parse the imports out of it, or get the
-- module name.
buf <- case maybe_src_buf of
Just b -> return b
Nothing -> hGetStringBuffer src_filename
let loc = mkSrcLoc (mkFastString src_filename) 1 0
case unP P.parseHeader (mkPState buf loc dflags) of {
PFailed span err -> return (Left (mkPlainErrMsg span err));
POk pst rdr_module -> do {
let {ms = getMessages pst};
printErrorsAndWarnings dflags ms;
-- when (errorsFound dflags ms) $ exitWith (ExitFailure 1);
dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr rdr_module) ;
dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"
(ppSourceStats False rdr_module) ;
return (Right rdr_module)
-- ToDo: free the string buffer later.
}}