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 )
11 #include "HsVersions.h"
14 import Char ( ord, isAlphaNum )
16 import CmFind ( ModName, ModLocation(..) )
17 import Outputable ( pprPanic, text )
25 ms_loc :: ModLocation, -- location and kind
26 ms_source :: (Maybe (String, Fingerprint)), -- source and sig if .hs
27 ms_imports :: (Maybe [ModImport]) -- imports if .hs or .hi
32 = MINormal ModName | MISource ModName
35 mi_name (MINormal nm) = nm
36 mi_name (MISource nm) = nm
38 ms_get_imports :: ModSummary -> [ModImport]
40 = case ms_imports summ of { Just is -> is; Nothing -> [] }
42 type Fingerprint = Int
44 summarise :: ModLocation -> IO ModSummary
48 InPackage mod path -- if in a package, investigate no further
49 -> return (ModSummary loc Nothing Nothing)
50 SourceOnly mod path -- source; read, cache and get imports
51 -> readFile path >>= \ modsrc ->
52 let imps = getImports modsrc
53 fp = fingerprint modsrc
54 in return (ModSummary loc (Just (modsrc,fp)) (Just imps))
55 ObjectCode mod oPath hiPath -- can we get away with the src summariser
56 -- for interface files?
57 -> readFile hiPath >>= \ hisrc ->
58 let imps = getImports hisrc
59 in return (ModSummary loc Nothing (Just imps))
61 -> pprPanic "summarise:NotFound" (text (show loc))
63 fingerprint :: String -> Int
67 -- Copied from hash() in Hugs' storage.c.
68 dofp :: String -> Int -> Int -> Int
70 dofp (c:cs) m fp = dofp cs (m+1) (iabs (fp + m * ord c))
72 iabs n = if n < 0 then -n else n
75 Collect up the imports from a Haskell source module. This is
76 approximate: we don't parse the module, but we do eliminate comments
77 and strings. Doesn't currently know how to unlit or cppify the module
82 getImports :: String -> [ModImport]
83 getImports = nub . gmiBase . clean
85 -- really get the imports from a de-litted, cpp'd, de-literal'd string
86 gmiBase :: String -> [ModImport]
90 f ("foreign" : "import" : ws) = f ws
91 f ("import" : "{-#" : "SOURCE" : "#-}" : "qualified" : m : ws)
92 = MISource (takeWhile isModId m) : f ws
93 f ("import" : "{-#" : "SOURCE" : "#-}" : m : ws)
94 = MISource (takeWhile isModId m) : f ws
95 f ("import" : "qualified" : m : ws)
96 = MINormal (takeWhile isModId m) : f ws
98 = MINormal (takeWhile isModId m) : f ws
102 isModId c = isAlphaNum c || c `elem` "'_"
104 -- remove literals and comments from a string
105 clean :: String -> String
109 -- running through text we want to keep
111 keep ('"':cs) = dquote cs
112 -- try to eliminate single quotes when they're part of
114 keep (c:'\'':cs) | isAlphaNum c || c == '_' = keep (dropWhile (=='\'') cs)
115 keep ('\'':cs) = squote cs
116 keep ('-':'-':cs) = linecomment cs
117 keep ('{':'-':'#':' ':cs) = "{-# " ++ keep cs
118 keep ('{':'-':cs) = runcomment cs
119 keep (c:cs) = c : keep cs
121 -- in a double-quoted string
123 dquote ('\\':'\"':cs) = dquote cs
124 dquote ('\\':'\\':cs) = dquote cs
125 dquote ('\"':cs) = keep cs
126 dquote (c:cs) = dquote cs
128 -- in a single-quoted string
130 squote ('\\':'\'':cs) = squote cs
131 squote ('\\':'\\':cs) = squote cs
132 squote ('\'':cs) = keep cs
133 squote (c:cs) = squote cs
137 linecomment ('\n':cs) = '\n':keep cs
138 linecomment (c:cs) = linecomment cs
140 -- in a running comment
142 runcomment ('-':'}':cs) = keep cs
143 runcomment (c:cs) = runcomment cs