Skip to content

Commit 18ee98f

Browse files
committed
Pull the preprocessor functions into a separate module
1 parent f66c886 commit 18ee98f

File tree

3 files changed

+92
-70
lines changed

3 files changed

+92
-70
lines changed

ghcide.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ library
9999
other-modules:
100100
Development.IDE.Core.Debouncer
101101
Development.IDE.Core.Compile
102+
Development.IDE.Core.Preprocessor
102103
Development.IDE.GHC.Compat
103104
Development.IDE.GHC.CPP
104105
Development.IDE.GHC.Error

src/Development/IDE/Core/Compile.hs

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ module Development.IDE.Core.Compile
1616
) where
1717

1818
import Development.IDE.Core.RuleTypes
19-
import Development.IDE.GHC.CPP
19+
import Development.IDE.Core.Preprocessor
2020
import Development.IDE.GHC.Error
2121
import Development.IDE.GHC.Warnings
2222
import Development.IDE.Types.Diagnostics
2323
import Development.IDE.GHC.Orphans()
2424
import Development.IDE.GHC.Util
25-
import Development.IDE.GHC.Compat
2625
import qualified GHC.LanguageExtensions.Type as GHC
2726
import Development.IDE.Types.Options
2827
import Development.IDE.Types.Location
@@ -54,10 +53,6 @@ import Data.Maybe
5453
import Data.Tuple.Extra
5554
import qualified Data.Map.Strict as Map
5655
import System.FilePath
57-
import System.IO.Extra
58-
import Data.Char
59-
60-
import SysTools (Option (..), runUnlit)
6156

6257

6358
-- | Given a string buffer, return a pre-processed @ParsedModule@.
@@ -270,70 +265,6 @@ getModSummaryFromBuffer fp contents dflags parsed = do
270265
then (HsBootFile, \newExt -> stem <.> newExt ++ "-boot")
271266
else (HsSrcFile , \newExt -> stem <.> newExt)
272267

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
279-
Just cnts -> do
280-
let fsrc = dir </> takeFileName filename <.> "literate"
281-
withBinaryFile fsrc WriteMode $ \h ->
282-
hPutStringBuffer h cnts
283-
return fsrc
284-
unlit filesrc fout
285-
SB.hGetStringBuffer fout
286-
where
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
298-
escape [] = []
299-
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"
304-
case contents of
305-
Nothing -> do
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
311-
312-
Just contents -> do
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)
315-
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
318-
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
324-
325-
-- Fix up the filename in lines like:
326-
-- # 1 "C:/Temp/extra-dir-914611385186/___GHCIDE_MAGIC___"
327-
let tweak x
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 <> "\""
334-
| otherwise = x
335-
stringToStringBuffer . unlines . map tweak . lines <$> readFileUTF8' out
336-
337268
-- | Given a buffer, flags, file path and module summary, produce a
338269
-- parsed module (or errors) and any parse warnings.
339270
parseFileContents
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2+
-- SPDX-License-Identifier: Apache-2.0
3+
4+
{-# LANGUAGE RankNTypes #-}
5+
{-# LANGUAGE CPP #-}
6+
7+
-- | Based on https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/API.
8+
-- Given a list of paths to find libraries, and a file to compile, produce a list of 'CoreModule' values.
9+
module Development.IDE.Core.Preprocessor
10+
( runLhs
11+
, runCpp
12+
) where
13+
14+
import Development.IDE.GHC.CPP
15+
import Development.IDE.GHC.Orphans()
16+
import Development.IDE.GHC.Compat
17+
import GHC
18+
import GhcMonad
19+
import StringBuffer as SB
20+
21+
import Data.List.Extra
22+
import System.FilePath
23+
import System.IO.Extra
24+
import Data.Char
25+
26+
import SysTools (Option (..), runUnlit)
27+
28+
-- | Run (unlit) literate haskell preprocessor on a file, or buffer if set
29+
runLhs :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
30+
runLhs dflags filename contents = withTempDir $ \dir -> do
31+
let fout = dir </> takeFileName filename <.> "unlit"
32+
filesrc <- case contents of
33+
Nothing -> return filename
34+
Just cnts -> do
35+
let fsrc = dir </> takeFileName filename <.> "literate"
36+
withBinaryFile fsrc WriteMode $ \h ->
37+
hPutStringBuffer h cnts
38+
return fsrc
39+
unlit filesrc fout
40+
SB.hGetStringBuffer fout
41+
where
42+
unlit filein fileout = SysTools.runUnlit dflags (args filein fileout)
43+
args filein fileout = [
44+
SysTools.Option "-h"
45+
, SysTools.Option (escape filename) -- name this file
46+
, SysTools.FileOption "" filein -- input file
47+
, SysTools.FileOption "" fileout ] -- output file
48+
-- taken from ghc's DriverPipeline.hs
49+
escape ('\\':cs) = '\\':'\\': escape cs
50+
escape ('\"':cs) = '\\':'\"': escape cs
51+
escape ('\'':cs) = '\\':'\'': escape cs
52+
escape (c:cs) = c : escape cs
53+
escape [] = []
54+
55+
-- | Run CPP on a file
56+
runCpp :: DynFlags -> FilePath -> Maybe SB.StringBuffer -> IO SB.StringBuffer
57+
runCpp dflags filename contents = withTempDir $ \dir -> do
58+
let out = dir </> takeFileName filename <.> "out"
59+
case contents of
60+
Nothing -> do
61+
-- Happy case, file is not modified, so run CPP on it in-place
62+
-- which also makes things like relative #include files work
63+
-- and means location information is correct
64+
doCpp dflags True filename out
65+
liftIO $ SB.hGetStringBuffer out
66+
67+
Just contents -> do
68+
-- Sad path, we have to create a version of the path in a temp dir
69+
-- __FILE__ macro is wrong, ignoring that for now (likely not a real issue)
70+
71+
-- Relative includes aren't going to work, so we fix that by adding to the include path.
72+
dflags <- return $ addIncludePathsQuote (takeDirectory filename) dflags
73+
74+
-- Location information is wrong, so we fix that by patching it afterwards.
75+
let inp = dir </> "___GHCIDE_MAGIC___"
76+
withBinaryFile inp WriteMode $ \h ->
77+
hPutStringBuffer h contents
78+
doCpp dflags True inp out
79+
80+
-- Fix up the filename in lines like:
81+
-- # 1 "C:/Temp/extra-dir-914611385186/___GHCIDE_MAGIC___"
82+
let tweak x
83+
| Just x <- stripPrefix "# " x
84+
, "___GHCIDE_MAGIC___" `isInfixOf` x
85+
, let num = takeWhile (not . isSpace) x
86+
-- important to use /, and never \ for paths, even on Windows, since then C escapes them
87+
-- and GHC gets all confused
88+
= "# " <> num <> " \"" <> map (\x -> if isPathSeparator x then '/' else x) filename <> "\""
89+
| otherwise = x
90+
stringToStringBuffer . unlines . map tweak . lines <$> readFileUTF8' out

0 commit comments

Comments
 (0)