@@ -16,13 +16,12 @@ module Development.IDE.Core.Compile
18import Development.IDE.Core.RuleTypes
18import Development.IDE.Core.RuleTypes
19−import Development.IDE.GHC.CPP
19+import Development.IDE.Core.Preprocessor
20import Development.IDE.GHC.Error
20import Development.IDE.GHC.Error
21import Development.IDE.GHC.Warnings
21import Development.IDE.GHC.Warnings
22import Development.IDE.Types.Diagnostics
22import Development.IDE.Types.Diagnostics
23import Development.IDE.GHC.Orphans()
23import Development.IDE.GHC.Orphans()
24import Development.IDE.GHC.Util
24import Development.IDE.GHC.Util
25−import Development.IDE.GHC.Compat
26import qualified GHC.LanguageExtensions.Type as GHC
25import qualified GHC.LanguageExtensions.Type as GHC
27import Development.IDE.Types.Options
26import Development.IDE.Types.Options
28import Development.IDE.Types.Location
27import Development.IDE.Types.Location
@@ -33,14 +32,12 @@ import Lexer
33import ErrUtils
32import ErrUtils
35import qualified GHC
34import qualified GHC
37import GhcMonad
35import GhcMonad
38import GhcPlugins as GHC hiding (fst3, (<>))
36import GhcPlugins as GHC hiding (fst3, (<>))
39import qualified HeaderInfo as Hdr
37import qualified HeaderInfo as Hdr
40import MkIface
38import MkIface
41import StringBuffer as SB
39import StringBuffer as SB
42import TidyPgm
40import TidyPgm
43−import qualified GHC.LanguageExtensions as LangExt
45import Control.Monad.Extra
42import Control.Monad.Extra
46import Control.Monad.Except
43import Control.Monad.Except
@@ -54,10 +51,6 @@ import Data.Maybe
54import Data.Tuple.Extra
51import Data.Tuple.Extra
55import qualified Data.Map.Strict as Map
52import qualified Data.Map.Strict as Map
56import System.FilePath
53import System.FilePath
57−import System.IO.Extra
60−import SysTools (Option (..), runUnlit)
63-- | Given a string buffer, return a pre-processed @ParsedModule@.
56-- | Given a string buffer, return a pre-processed @ParsedModule@.
@@ -270,69 +263,6 @@ getModSummaryFromBuffer fp contents dflags parsed = do
270 then (HsBootFile, \newExt -> stem <.> newExt ++ "-boot")
263 then (HsBootFile, \newExt -> stem <.> newExt ++ "-boot")
271 else (HsSrcFile , \newExt -> stem <.> newExt)
264 else (HsSrcFile , \newExt -> stem <.> newExt)
273−-- | Run (unlit) literate haskell preprocessor on a file, or buffer if set
274−runLhs :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
275−runLhs dflags filename contents = withTempDir $ \dir -> do
276− let fout = dir </> takeFileName filename <.> "unlit"
277− filesrc <- case contents of
278− Nothing -> return filename
280− let fsrc = dir </> takeFileName filename <.> "literate"
281− withBinaryFile fsrc WriteMode $ \h ->
282− hPutStringBuffer h cnts
285− SB.hGetStringBuffer fout
287− unlit filein fileout = SysTools.runUnlit dflags (args filein fileout)
288− args filein fileout = [
289− SysTools.Option "-h"
290− , SysTools.Option (escape filename) -- name this file
291− , SysTools.FileOption "" filein -- input file
292− , SysTools.FileOption "" fileout ] -- output file
293− -- taken from ghc's DriverPipeline.hs
294− escape ('\\':cs) = '\\':'\\': escape cs
295− escape ('\"':cs) = '\\':'\"': escape cs
296− escape ('\'':cs) = '\\':'\'': escape cs
297− escape (c:cs) = c : escape cs
300−-- | Run CPP on a file
301−runCpp :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
302−runCpp dflags filename contents = withTempDir $ \dir -> do
303− let out = dir </> takeFileName filename <.> "out"
306− -- Happy case, file is not modified, so run CPP on it in-place
307− -- which also makes things like relative #include files work
308− -- and means location information is correct
309− doCpp dflags True filename out
310− liftIO $ SB.hGetStringBuffer out
313− -- Sad path, we have to create a version of the path in a temp dir
314− -- __FILE__ macro is wrong, ignoring that for now (likely not a real issue)
316− -- Relative includes aren't going to work, so we fix that by adding to the include path.
317− dflags <- return $ addIncludePathsQuote (takeDirectory filename) dflags
319− -- Location information is wrong, so we fix that by patching it afterwards.
320− let inp = dir </> "___GHCIDE_MAGIC___"
321− withBinaryFile inp WriteMode $ \h ->
322− hPutStringBuffer h contents
323− doCpp dflags True inp out
325− -- Fix up the filename in lines like:
326− -- # 1 "C:/Temp/extra-dir-914611385186/___GHCIDE_MAGIC___"
328− | Just x <- stripPrefix "# " x
329− , "___GHCIDE_MAGIC___" `isInfixOf` x
330− , let num = takeWhile (not . isSpace) x
331− -- important to use /, and never \ for paths, even on Windows, since then C escapes them
332− -- and GHC gets all confused
333− = "# " <> num <> " \"" <> map (\x -> if isPathSeparator x then '/' else x) filename <> "\""
335− stringToStringBuffer . unlines . map tweak . lines <$> readFileUTF8' out
337-- | Given a buffer, flags, file path and module summary, produce a
267-- | Given a buffer, flags, file path and module summary, produce a
338-- parsed module (or errors) and any parse warnings.
268-- parsed module (or errors) and any parse warnings.
@@ -342,28 +272,9 @@ parseFileContents
342 -> FilePath -- ^ the filename (for source locations)
272 -> FilePath -- ^ the filename (for source locations)
343 -> Maybe SB.StringBuffer -- ^ Haskell module source text (full Unicode is supported)
273 -> Maybe SB.StringBuffer -- ^ Haskell module source text (full Unicode is supported)
344 -> ExceptT [FileDiagnostic] m ([FileDiagnostic], ParsedModule)
274 -> ExceptT [FileDiagnostic] m ([FileDiagnostic], ParsedModule)
345−parseFileContents preprocessor filename mbContents = do
275+parseFileContents customPreprocessor filename mbContents = do
276+ (contents, dflags) <- preprocessor filename mbContents
346 let loc = mkRealSrcLoc (mkFastString filename) 1 1
277 let loc = mkRealSrcLoc (mkFastString filename) 1 1
347− contents <- liftIO $ maybe (hGetStringBuffer filename) return mbContents
348− let isOnDisk = isNothing mbContents
350− -- unlit content if literate Haskell ending
351− (isOnDisk, contents) <- if ".lhs" `isSuffixOf` filename
353− dflags <- getDynFlags
354− newcontent <- liftIO $ runLhs dflags filename mbContents
355− return (False, newcontent)
356− else return (isOnDisk, contents)
358− dflags <- ExceptT $ parsePragmasIntoDynFlags filename contents
359− (contents, dflags) <-
360− if not $ xopt LangExt.Cpp dflags then
361− return (contents, dflags)
363− contents <- liftIO $ runCpp dflags filename $ if isOnDisk then Nothing else Just contents
364− dflags <- ExceptT $ parsePragmasIntoDynFlags filename contents
365− return (contents, dflags)
367 case unP Parser.parseModule (mkPState dflags contents loc) of
278 case unP Parser.parseModule (mkPState dflags contents loc) of
368 PFailed _ locErr msgErr ->
279 PFailed _ locErr msgErr ->
369 throwE $ diagFromErrMsg "parser" dflags $ mkPlainErrMsg dflags locErr msgErr
280 throwE $ diagFromErrMsg "parser" dflags $ mkPlainErrMsg dflags locErr msgErr
@@ -388,7 +299,7 @@ parseFileContents preprocessor filename mbContents = do
388 throwE $ diagFromErrMsgs "parser" dflags $ snd $ getMessages pst dflags
299 throwE $ diagFromErrMsgs "parser" dflags $ snd $ getMessages pst dflags
390 -- Ok, we got here. It's safe to continue.
301 -- Ok, we got here. It's safe to continue.
391− let (errs, parsed) = preprocessor rdr_module
302+ let (errs, parsed) = customPreprocessor rdr_module
392 unless (null errs) $ throwE $ diagFromStrings "parser" errs
303 unless (null errs) $ throwE $ diagFromStrings "parser" errs
393 ms <- getModSummaryFromBuffer filename contents dflags parsed
304 ms <- getModSummaryFromBuffer filename contents dflags parsed
@@ -400,28 +311,3 @@ parseFileContents preprocessor filename mbContents = do
401 warnings = diagFromErrMsgs "parser" dflags warns
312 warnings = diagFromErrMsgs "parser" dflags warns
402 pure (warnings, pm)
313 pure (warnings, pm)
405−-- | This reads the pragma information directly from the provided buffer.
406−parsePragmasIntoDynFlags
410− -> m (Either [FileDiagnostic] DynFlags)
411−parsePragmasIntoDynFlags fp contents = catchSrcErrors "pragmas" $ do
412− dflags0 <- getSessionDynFlags
413− let opts = Hdr.getOptions dflags0 contents fp
414− (dflags, _, _) <- parseDynamicFilePragma dflags0 opts
417−-- | Run something in a Ghc monad and catch the errors (SourceErrors and
418−-- compiler-internal exceptions like Panic or InstallationError).
419−catchSrcErrors :: GhcMonad m => T.Text -> m a -> m (Either [FileDiagnostic] a)
420−catchSrcErrors fromWhere ghcM = do
421− dflags <- getDynFlags
422− handleGhcException (ghcExceptionToDiagnostics dflags) $
423− handleSourceError (sourceErrorToDiagnostics dflags) $
426− ghcExceptionToDiagnostics dflags = return . Left . diagFromGhcException fromWhere dflags
427− sourceErrorToDiagnostics dflags = return . Left . diagFromErrMsgs fromWhere dflags . srcErrorMessages