2 % (c) The AQUA Project, Glasgow University, 1993-2000
4 \section[CmSummarise]{Module summariser for GHCI}
7 module CmSummarise ( ModImport(..), mi_name,
8 ModSummary(..), summarise )
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 type Fingerprint = Int
40 summarise :: ModLocation -> IO ModSummary
44 InPackage mod path -- if in a package, investigate no further
45 -> return (ModSummary loc Nothing Nothing)
46 SourceOnly mod path -- source; read, cache and get imports
47 -> readFile path >>= \ modsrc ->
48 let imps = getImports modsrc
49 fp = fingerprint modsrc
50 in return (ModSummary loc (Just (modsrc,fp)) (Just imps))
51 ObjectCode mod oPath hiPath -- can we get away with the src summariser
52 -- for interface files?
53 -> readFile hiPath >>= \ hisrc ->
54 let imps = getImports hisrc
55 in return (ModSummary loc Nothing (Just imps))
57 -> pprPanic "summarise:NotFound" (text (show loc))
59 fingerprint :: String -> Int
63 -- Copied from hash() in Hugs' storage.c.
64 dofp :: String -> Int -> Int -> Int
66 dofp (c:cs) m fp = dofp cs (m+1) (iabs (fp + m * ord c))
68 iabs n = if n < 0 then -n else n
71 Collect up the imports from a Haskell source module. This is
72 approximate: we don't parse the module, but we do eliminate comments
73 and strings. Doesn't currently know how to unlit or cppify the module
78 getImports :: String -> [ModImport]
79 getImports = nub . gmiBase . clean
81 -- really get the imports from a de-litted, cpp'd, de-literal'd string
82 gmiBase :: String -> [ModImport]
86 f ("foreign" : "import" : ws) = f ws
87 f ("import" : "{-#" : "SOURCE" : "#-}" : "qualified" : m : ws)
88 = MISource (takeWhile isModId m) : f ws
89 f ("import" : "{-#" : "SOURCE" : "#-}" : m : ws)
90 = MISource (takeWhile isModId m) : f ws
91 f ("import" : "qualified" : m : ws)
92 = MINormal (takeWhile isModId m) : f ws
94 = MINormal (takeWhile isModId m) : f ws
98 isModId c = isAlphaNum c || c `elem` "'_"
100 -- remove literals and comments from a string
101 clean :: String -> String
105 -- running through text we want to keep
107 keep ('"':cs) = dquote cs
108 -- try to eliminate single quotes when they're part of
110 keep (c:'\'':cs) | isAlphaNum c || c == '_' = keep (dropWhile (=='\'') cs)
111 keep ('\'':cs) = squote cs
112 keep ('-':'-':cs) = linecomment cs
113 keep ('{':'-':'#':' ':cs) = "{-# " ++ keep cs
114 keep ('{':'-':cs) = runcomment cs
115 keep (c:cs) = c : keep cs
117 -- in a double-quoted string
119 dquote ('\\':'\"':cs) = dquote cs
120 dquote ('\\':'\\':cs) = dquote cs
121 dquote ('\"':cs) = keep cs
122 dquote (c:cs) = dquote cs
124 -- in a single-quoted string
126 squote ('\\':'\'':cs) = squote cs
127 squote ('\\':'\\':cs) = squote cs
128 squote ('\'':cs) = keep cs
129 squote (c:cs) = squote cs
133 linecomment ('\n':cs) = '\n':keep cs
134 linecomment (c:cs) = linecomment cs
136 -- in a running comment
138 runcomment ('-':'}':cs) = keep cs
139 runcomment (c:cs) = runcomment cs