2 % (c) The University of Glasgow, 2000
4 \section[CmSummarise]{Module summariser for GHCI}
7 module CmSummarise ( ModImport(..), mi_name,
8 ModSummary(..), summarise, ms_get_imports,
9 name_of_summary, deps_of_summary,
13 #include "HsVersions.h"
16 import Char ( ord, isAlphaNum )
18 import CmFind ( ModName, ModLocation(..), ml_modname )
25 -- The ModLocation contains the original source filename of the module.
26 -- The ms_ppsource field contains another filename, which is intended to
27 -- be the cleaned-up source file after all preprocessing has happened to
28 -- it. The point is that the summariser will have to cpp/unlit/whatever
29 -- all files anyway, and there's no point in doing this twice -- just
30 -- park the result in a temp file, put the name of it in ms_ppsource,
31 -- and let @compile@ read from that file on the way back up.
34 ms_loc :: ModLocation, -- location and kind
35 ms_ppsource :: (Maybe (FilePath, Fingerprint)), -- preprocessed and sig if .hs
36 ms_imports :: (Maybe [ModImport]) -- imports if .hs or .hi
39 instance Outputable ModSummary where
41 = sep [text "ModSummary {",
42 nest 3 (sep [text "ms_loc =" <+> ppr (ms_loc ms),
43 text "ms_ppsource =" <+> fooble (ms_ppsource ms),
44 text "ms_imports=" <+> ppr (ms_imports ms)]),
48 fooble Nothing = text "Nothing"
49 fooble (Just (cppd_source_name,fp))
50 = text "(fp =" <+> int fp <> text ","
51 <+> text (show cppd_source_name) <> text ")"
54 = MINormal ModName | MISource ModName
57 instance Outputable ModImport where
58 ppr (MINormal nm) = text nm
59 ppr (MISource nm) = text "{-# SOURCE #-}" <+> text nm
62 mi_name (MINormal nm) = nm
63 mi_name (MISource nm) = nm
65 name_of_summary :: ModSummary -> ModName
66 name_of_summary = ml_modname . ms_loc
68 deps_of_summary :: ModSummary -> [ModName]
69 deps_of_summary = map mi_name . ms_get_imports
71 ms_get_imports :: ModSummary -> [ModImport]
73 = case ms_imports summ of { Just is -> is; Nothing -> [] }
75 type Fingerprint = Int
77 summarise :: ModLocation -> IO ModSummary
81 InPackage mod path -- if in a package, investigate no further
82 -> return (ModSummary loc Nothing Nothing)
83 SourceOnly mod path -- source; read, cache and get imports
84 -> readFile path >>= \ modsrc ->
85 let imps = getImports modsrc
86 fp = fingerprint modsrc
87 in return (ModSummary loc (Just (path,fp)) (Just imps))
88 ObjectCode mod oPath hiPath -- can we get away with the src summariser
89 -- for interface files?
90 -> readFile hiPath >>= \ hisrc ->
91 let imps = getImports hisrc
92 in return (ModSummary loc Nothing (Just imps))
94 -> pprPanic "summarise:NotFound" (ppr loc)
96 fingerprint :: String -> Int
100 -- Copied from hash() in Hugs' storage.c.
101 dofp :: String -> Int# -> Int# -> Int
103 dofp (c:cs) m fp = dofp cs (m +# 1#) (iabs (fp +# m *# unbox (ord c)))
106 iabs n = if n <# 0# then 0# -# n else n
109 Collect up the imports from a Haskell source module. This is
110 approximate: we don't parse the module, but we do eliminate comments
111 and strings. Doesn't currently know how to unlit or cppify the module
116 getImports :: String -> [ModImport]
117 getImports = nub . gmiBase . clean
119 -- really get the imports from a de-litted, cpp'd, de-literal'd string
120 gmiBase :: String -> [ModImport]
124 f ("foreign" : "import" : ws) = f ws
125 f ("import" : "{-#" : "SOURCE" : "#-}" : "qualified" : m : ws)
126 = MISource (takeWhile isModId m) : f ws
127 f ("import" : "{-#" : "SOURCE" : "#-}" : m : ws)
128 = MISource (takeWhile isModId m) : f ws
129 f ("import" : "qualified" : m : ws)
130 = MINormal (takeWhile isModId m) : f ws
131 f ("import" : m : ws)
132 = MINormal (takeWhile isModId m) : f ws
136 isModId c = isAlphaNum c || c `elem` "'_"
138 -- remove literals and comments from a string
139 clean :: String -> String
143 -- running through text we want to keep
145 keep ('"':cs) = dquote cs
146 -- try to eliminate single quotes when they're part of
148 keep (c:'\'':cs) | isAlphaNum c || c == '_' = keep (dropWhile (=='\'') cs)
149 keep ('\'':cs) = squote cs
150 keep ('-':'-':cs) = linecomment cs
151 keep ('{':'-':'#':' ':cs) = "{-# " ++ keep cs
152 keep ('{':'-':cs) = runcomment cs
153 keep (c:cs) = c : keep cs
155 -- in a double-quoted string
157 dquote ('\\':'\"':cs) = dquote cs
158 dquote ('\\':'\\':cs) = dquote cs
159 dquote ('\"':cs) = keep cs
160 dquote (c:cs) = dquote cs
162 -- in a single-quoted string
164 squote ('\\':'\'':cs) = squote cs
165 squote ('\\':'\\':cs) = squote cs
166 squote ('\'':cs) = keep cs
167 squote (c:cs) = squote cs
171 linecomment ('\n':cs) = '\n':keep cs
172 linecomment (c:cs) = linecomment cs
174 -- in a running comment
176 runcomment ('-':'}':cs) = keep cs
177 runcomment (c:cs) = runcomment cs