2 % (c) The University of Glasgow, 2000
4 \section[CmSummarise]{Module summariser for GHCI}
7 module CmSummarise ( ModImport(..), mimp_name,
8 ModSummary(..), summarise, ms_get_imports,
9 name_of_summary, deps_of_summary,
13 #include "HsVersions.h"
16 import Char ( isAlphaNum )
17 import Util ( unJust )
18 import HscTypes ( ModuleLocation(..) )
27 -- The Module contains the original source filename of the module.
28 -- The ms_ppsource field contains another filename, which is intended to
29 -- be the cleaned-up source file after all preprocessing has happened to
30 -- it. The point is that the summariser will have to cpp/unlit/whatever
31 -- all files anyway, and there's no point in doing this twice -- just
32 -- park the result in a temp file, put the name of it in ms_ppsource,
33 -- and let @compile@ read from that file on the way back up.
36 ms_mod :: Module, -- name, package
37 ms_location :: ModuleLocation, -- location
38 ms_imports :: (Maybe [ModImport]) -- imports if .hs or .hi
41 instance Outputable ModSummary where
43 = sep [text "ModSummary {",
44 nest 3 (sep [text "ms_mod =" <+> ppr (ms_mod ms) <> comma,
45 text "ms_imports =" <+> ppr (ms_imports ms)]),
50 = MINormal ModuleName | MISource ModuleName
53 instance Outputable ModImport where
54 ppr (MINormal nm) = ppr nm
55 ppr (MISource nm) = text "{-# SOURCE #-}" <+> ppr nm
58 mimp_name (MINormal nm) = nm
59 mimp_name (MISource nm) = nm
61 name_of_summary :: ModSummary -> ModuleName
62 name_of_summary = moduleName . ms_mod
64 deps_of_summary :: ModSummary -> [ModuleName]
65 deps_of_summary = map mimp_name . ms_get_imports
67 ms_get_imports :: ModSummary -> [ModImport]
69 = case ms_imports summ of { Just is -> is; Nothing -> [] }
71 type Fingerprint = Int
73 -- The first arg is supposed to be DriverPipeline.preprocess.
74 -- Passed in here to avoid a hard-to-avoid circular dependency
75 -- between CmSummarise and DriverPipeline.
76 summarise :: (FilePath -> IO FilePath)
77 -> Module -> ModuleLocation -> IO ModSummary
78 summarise preprocess mod location
79 | isModuleInThisPackage mod
80 = do let hs_fn = unJust (ml_hs_file location) "summarise"
81 hspp_fn <- preprocess hs_fn
82 modsrc <- readFile hspp_fn
83 let imps = getImports modsrc
84 return (ModSummary mod location{ml_hspp_file=Just hspp_fn} (Just imps))
86 = return (ModSummary mod location Nothing)
89 Collect up the imports from a Haskell source module. This is
90 approximate: we don't parse the module, but we do eliminate comments
91 and strings. Doesn't currently know how to unlit or cppify the module
96 getImports :: String -> [ModImport]
97 getImports = nub . gmiBase . clean
99 -- really get the imports from a de-litted, cpp'd, de-literal'd string
100 gmiBase :: String -> [ModImport]
104 f ("foreign" : "import" : ws) = f ws
105 f ("import" : "{-#" : "SOURCE" : "#-}" : "qualified" : m : ws)
106 = MISource (mkMN m) : f ws
107 f ("import" : "{-#" : "SOURCE" : "#-}" : m : ws)
108 = MISource (mkMN m) : f ws
109 f ("import" : "qualified" : m : ws)
110 = MINormal (mkMN m) : f ws
111 f ("import" : m : ws)
112 = MINormal (mkMN m) : f ws
116 mkMN str = mkModuleName (takeWhile isModId str)
117 isModId c = isAlphaNum c || c `elem` "'_"
119 -- remove literals and comments from a string
120 clean :: String -> String
124 -- running through text we want to keep
126 keep ('"':cs) = dquote cs -- "
127 -- try to eliminate single quotes when they're part of
129 keep (c:'\'':cs) | isAlphaNum c || c == '_' = keep (dropWhile (=='\'') cs)
130 keep ('\'':cs) = squote cs
131 keep ('-':'-':cs) = linecomment cs
132 keep ('{':'-':'#':' ':cs) = "{-# " ++ keep cs
133 keep ('{':'-':cs) = runcomment cs -- -}
134 keep (c:cs) = c : keep cs
136 -- in a double-quoted string
138 dquote ('\\':'\"':cs) = dquote cs -- "
139 dquote ('\\':'\\':cs) = dquote cs
140 dquote ('\"':cs) = keep cs -- "
141 dquote (c:cs) = dquote cs
143 -- in a single-quoted string
145 squote ('\\':'\'':cs) = squote cs
146 squote ('\\':'\\':cs) = squote cs
147 squote ('\'':cs) = keep cs
148 squote (c:cs) = squote cs
152 linecomment ('\n':cs) = '\n':keep cs
153 linecomment (c:cs) = linecomment cs
155 -- in a running comment
157 runcomment ('-':'}':cs) = keep cs
158 runcomment (c:cs) = runcomment cs