PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/leksah-server-0.12.1.2/src/IDE/Utils/GHCUtils.hs

#
Haskell | 252 lines | 191 code | 30 blank | 31 comment | 6 complexity | 089224b95c565f2ff547cc3d142f2454 MD5 | raw file
Possible License(s): GPL-2.0
  1. {-# OPTIONS_GHC -XCPP -fno-warn-orphans #-}
  2. -----------------------------------------------------------------------------
  3. --
  4. -- Module : IDE.Utils.GHCUtils
  5. -- Copyright : 2007-2011 Juergen Nicklisch-Franken, Hamish Mackenzie
  6. -- License : GPL
  7. --
  8. -- Maintainer : Jutaro <jutaro@leksah.org>
  9. -- Stability : provisional
  10. -- Portability :
  11. --
  12. -- |
  13. --
  14. -----------------------------------------------------------------------------
  15. module IDE.Utils.GHCUtils (
  16. inGhcIO
  17. , getInstalledPackageInfos
  18. , findFittingPackages
  19. , myParseModule
  20. , myParseHeader
  21. ) where
  22. #if MIN_VERSION_Cabal(1,8,0)
  23. #else
  24. import UniqFM (eltsUFM)
  25. #endif
  26. import Distribution.Simple (withinRange,PackageIdentifier(..),Dependency(..))
  27. #if MIN_VERSION_Cabal(1,8,0)
  28. import qualified Distribution.InstalledPackageInfo as IPI (sourcePackageId)
  29. #else
  30. import qualified Distribution.InstalledPackageInfo as IPI (package)
  31. #endif
  32. import GHC
  33. import DriverPipeline(preprocess)
  34. import StringBuffer (StringBuffer(..),hGetStringBuffer)
  35. import FastString (mkFastString)
  36. import Lexer (mkPState,ParseResult(..),getMessages,unP)
  37. import Outputable (ppr)
  38. #if MIN_VERSION_ghc(7,2,0)
  39. import ErrUtils (dumpIfSet_dyn,printBagOfErrors,printBagOfWarnings,errorsFound,mkPlainErrMsg,showPass,ErrMsg(..))
  40. import Control.Monad (unless)
  41. #else
  42. import ErrUtils (dumpIfSet_dyn,printErrorsAndWarnings,mkPlainErrMsg,showPass,ErrMsg(..))
  43. #endif
  44. import PackageConfig (PackageConfig)
  45. import Data.Foldable (maximumBy)
  46. import qualified Parser as P (parseModule,parseHeader)
  47. import HscStats (ppSourceStats)
  48. #if MIN_VERSION_ghc(7,2,0)
  49. import GhcMonad (Ghc(..))
  50. import SrcLoc (mkRealSrcLoc)
  51. #else
  52. import HscTypes (Ghc(..))
  53. #endif
  54. import IDE.Utils.FileUtils (getSysLibDir)
  55. import DynFlags (dopt_set)
  56. import System.Log.Logger(debugM)
  57. import Control.Monad.IO.Class (MonadIO(..), MonadIO)
  58. -- this should not be repeated here, why is it necessary?
  59. instance MonadIO Ghc where
  60. liftIO ioA = Ghc $ \_ -> ioA
  61. inGhcIO :: [String] -> [DynFlag] -> (DynFlags -> Ghc a) -> IO a
  62. inGhcIO flags' udynFlags ghcAct = do
  63. debugM "leksah-server" $ "inGhcIO called with: " ++ show flags'
  64. libDir <- getSysLibDir
  65. -- (restFlags, _) <- parseStaticFlags (map noLoc flags')
  66. runGhc (Just libDir) $ do
  67. dynflags <- getSessionDynFlags
  68. let dynflags' = foldl (\ flags'' flag' -> dopt_set flags'' flag') dynflags udynFlags
  69. let dynflags'' = dynflags' {
  70. hscTarget = HscNothing,
  71. ghcMode = CompManager,
  72. ghcLink = NoLink
  73. }
  74. dynflags''' <- parseGhcFlags dynflags'' (map noLoc flags') flags'
  75. res <- defaultCleanupHandler dynflags''' $ do
  76. setSessionDynFlags dynflags'''
  77. ghcAct dynflags'''
  78. unload
  79. return res
  80. where
  81. parseGhcFlags :: DynFlags -> [Located String]
  82. -> [String] -> Ghc DynFlags
  83. parseGhcFlags dynflags flags_ _origFlags = do
  84. (dynflags', rest, _) <- parseDynamicFlags dynflags flags_
  85. if not (null rest)
  86. then do
  87. liftIO $ debugM "leksah-server" ("No dynamic GHC options: " ++ (unwords (map unLoc rest)))
  88. return dynflags'
  89. else return dynflags'
  90. -- | Unload whatever is currently loaded.
  91. unload :: Ghc ()
  92. unload = do
  93. setTargets []
  94. load LoadAllTargets
  95. return ()
  96. getInstalledPackageInfos :: Ghc [PackageConfig]
  97. getInstalledPackageInfos = do
  98. dflags1 <- getSessionDynFlags
  99. setSessionDynFlags $ dopt_set dflags1 Opt_ReadUserPackageConf
  100. pkgInfos <- case pkgDatabase dflags1 of
  101. Nothing -> return []
  102. #if MIN_VERSION_Cabal(1,8,0)
  103. Just fm -> return fm
  104. #else
  105. Just fm -> return (eltsUFM fm)
  106. #endif
  107. return pkgInfos
  108. findFittingPackages :: [Dependency] -> Ghc [PackageIdentifier]
  109. findFittingPackages dependencyList = do
  110. knownPackages <- getInstalledPackageInfos
  111. #if MIN_VERSION_Cabal(1,8,0)
  112. let packages = map IPI.sourcePackageId knownPackages
  113. #else
  114. let packages = map IPI.package knownPackages
  115. #endif
  116. return (concatMap (fittingKnown packages) dependencyList)
  117. where
  118. fittingKnown packages (Dependency dname versionRange) =
  119. let filtered = filter (\ (PackageIdentifier name version) ->
  120. name == dname && withinRange version versionRange)
  121. packages
  122. in if length filtered > 1
  123. then [maximumBy (\a b -> compare (pkgVersion a) (pkgVersion b)) filtered]
  124. else filtered
  125. ---------------------------------------------------------------------
  126. -- | Parser function copied here, because it is not exported
  127. myParseModule :: DynFlags -> FilePath -> Maybe StringBuffer
  128. -> IO (Either ErrMsg (Located (HsModule RdrName)))
  129. myParseModule dflags src_filename maybe_src_buf
  130. = -------------------------- Parser ----------------
  131. showPass dflags "Parser" >>
  132. {-# SCC "Parser" #-} do
  133. -- sometimes we already have the buffer in memory, perhaps
  134. -- because we needed to parse the imports out of it, or get the
  135. -- module name.
  136. buf' <- case maybe_src_buf of
  137. Just b -> return b
  138. Nothing -> hGetStringBuffer src_filename
  139. #if MIN_VERSION_ghc(7,2,0)
  140. let loc = mkRealSrcLoc (mkFastString src_filename) 1 0
  141. #else
  142. let loc = mkSrcLoc (mkFastString src_filename) 1 0
  143. #endif
  144. #if MIN_VERSION_ghc(7,0,1)
  145. case unP P.parseModule (mkPState dflags buf' loc) of {
  146. #else
  147. case unP P.parseModule (mkPState buf' loc dflags) of {
  148. #endif
  149. PFailed span' err -> return (Left (mkPlainErrMsg span' err));
  150. POk pst rdr_module -> do {
  151. #if MIN_VERSION_ghc(7,2,0)
  152. let {ms@(warnings, errors) = getMessages pst};
  153. printBagOfErrors dflags errors;
  154. unless (errorsFound dflags ms) $ printBagOfWarnings dflags warnings;
  155. #else
  156. let {ms = getMessages pst};
  157. printErrorsAndWarnings dflags ms;
  158. #endif
  159. -- when (errorsFound dflags ms) $ exitWith (ExitFailure 1);
  160. dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr rdr_module) ;
  161. dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"
  162. (ppSourceStats False rdr_module) ;
  163. return (Right rdr_module)
  164. -- ToDo: free the string buffer later.
  165. }}
  166. myParseHeader :: FilePath -> String -> [String] -> IO (Either String (HsModule RdrName))
  167. myParseHeader fp _str opts = inGhcIO (opts++["-cpp"]) [] $ \ _dynFlags -> do
  168. session <- getSession
  169. #if MIN_VERSION_ghc(7,2,0)
  170. (dynFlags',fp') <- liftIO $ preprocess session (fp,Nothing)
  171. #else
  172. (dynFlags',fp') <- preprocess session (fp,Nothing)
  173. #endif
  174. liftIO $ do
  175. stringBuffer <- hGetStringBuffer fp'
  176. parseResult <- myParseModuleHeader dynFlags' fp (Just stringBuffer)
  177. case parseResult of
  178. Right (L _ mod') -> return (Right mod')
  179. Left errMsg -> do
  180. let str = "Failed to parse " ++ show errMsg
  181. return (Left str)
  182. ---------------------------------------------------------------------
  183. -- | Parser function copied here, because it is not exported
  184. myParseModuleHeader :: DynFlags -> FilePath -> Maybe StringBuffer
  185. -> IO (Either ErrMsg (Located (HsModule RdrName)))
  186. myParseModuleHeader dflags src_filename maybe_src_buf
  187. = -------------------------- Parser ----------------
  188. showPass dflags "Parser" >>
  189. {-# SCC "Parser" #-} do
  190. -- sometimes we already have the buffer in memory, perhaps
  191. -- because we needed to parse the imports out of it, or get the
  192. -- module name.
  193. buf' <- case maybe_src_buf of
  194. Just b -> return b
  195. Nothing -> hGetStringBuffer src_filename
  196. #if MIN_VERSION_ghc(7,2,0)
  197. let loc = mkRealSrcLoc (mkFastString src_filename) 1 0
  198. #else
  199. let loc = mkSrcLoc (mkFastString src_filename) 1 0
  200. #endif
  201. #if MIN_VERSION_ghc(7,0,1)
  202. case unP P.parseHeader (mkPState dflags buf' loc) of {
  203. #else
  204. case unP P.parseHeader (mkPState buf' loc dflags) of {
  205. #endif
  206. PFailed span' err -> return (Left (mkPlainErrMsg span' err));
  207. POk pst rdr_module -> do {
  208. #if MIN_VERSION_ghc(7,2,0)
  209. let {ms@(warnings, errors) = getMessages pst};
  210. printBagOfErrors dflags errors;
  211. unless (errorsFound dflags ms) $ printBagOfWarnings dflags warnings;
  212. #else
  213. let {ms = getMessages pst};
  214. printErrorsAndWarnings dflags ms;
  215. #endif
  216. -- when (errorsFound dflags ms) $ exitWith (ExitFailure 1);
  217. dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr rdr_module) ;
  218. dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"
  219. (ppSourceStats False rdr_module) ;
  220. return (Right rdr_module)
  221. -- ToDo: free the string buffer later.
  222. }}