eb75ca481853b61029be40e443e4bc1ffeedfa46
[ghc-hetmet.git] / ghc / compiler / ghci / CmSummarise.lhs
1 %
2 % (c) The University of Glasgow, 2000
3 %
4 \section[CmSummarise]{Module summariser for GHCI}
5
6 \begin{code}
7 module CmSummarise ( ModImport(..), mimp_name,
8                      ModSummary(..), summarise, ms_get_imports,
9                      name_of_summary, deps_of_summary,
10                      getImports )
11 where
12
13 #include "HsVersions.h"
14
15 import List             ( nub )
16 import Char             ( isAlphaNum )
17 import Util             ( unJust )
18 import HscTypes         ( ModuleLocation(..) )
19
20 import Module
21 import Outputable
22 \end{code}
23
24 \begin{code}
25
26
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.
34 data ModSummary
35    = ModSummary {
36         ms_mod      :: Module,                          -- name, package
37         ms_location :: ModuleLocation,                  -- location
38         ms_imports  :: (Maybe [ModImport])              -- imports if .hs or .hi
39      }
40
41 instance Outputable ModSummary where
42    ppr ms
43       = sep [text "ModSummary {",
44              nest 3 (sep [text "ms_mod =" <+> ppr (ms_mod ms),
45              text "ms_imports=" <+> ppr (ms_imports ms)]),
46              char '}'
47             ]
48
49 data ModImport
50    = MINormal ModuleName | MISource ModuleName
51      deriving Eq
52
53 instance Outputable ModImport where
54    ppr (MINormal nm) = ppr nm
55    ppr (MISource nm) = text "{-# SOURCE #-}" <+> ppr nm
56
57
58 mimp_name (MINormal nm) = nm
59 mimp_name (MISource nm) = nm
60
61 name_of_summary :: ModSummary -> ModuleName
62 name_of_summary = moduleName . ms_mod
63
64 deps_of_summary :: ModSummary -> [ModuleName]
65 deps_of_summary = map mimp_name . ms_get_imports
66
67 ms_get_imports :: ModSummary -> [ModImport]
68 ms_get_imports summ
69    = case ms_imports summ of { Just is -> is; Nothing -> [] }
70
71 type Fingerprint = Int
72
73 summarise :: Module -> ModuleLocation -> IO ModSummary
74 summarise mod location
75    | isModuleInThisPackage mod
76    = do let hspp_fn = unJust (ml_hspp_file location) "summarise"
77         modsrc <- readFile hspp_fn
78         let imps = getImports modsrc
79         return (ModSummary mod location (Just imps))
80    | otherwise
81    = return (ModSummary mod location Nothing)
82 \end{code}
83
84 Collect up the imports from a Haskell source module.  This is
85 approximate: we don't parse the module, but we do eliminate comments
86 and strings.  Doesn't currently know how to unlit or cppify the module
87 first.
88
89 \begin{code}
90
91 getImports :: String -> [ModImport]
92 getImports = nub . gmiBase . clean
93
94 -- really get the imports from a de-litted, cpp'd, de-literal'd string
95 gmiBase :: String -> [ModImport]
96 gmiBase s
97    = f (words s)
98      where
99         f ("foreign" : "import" : ws) = f ws
100         f ("import" : "{-#" : "SOURCE" : "#-}" : "qualified" : m : ws) 
101            = MISource (mkMN m) : f ws
102         f ("import" : "{-#" : "SOURCE" : "#-}" : m : ws) 
103            = MISource (mkMN m) : f ws
104         f ("import" : "qualified" : m : ws) 
105            = MINormal (mkMN m) : f ws
106         f ("import" : m : ws) 
107            = MINormal (mkMN m) : f ws
108         f (w:ws) = f ws
109         f [] = []
110
111         mkMN str = mkModuleName (takeWhile isModId str)
112         isModId c = isAlphaNum c || c `elem` "'_"
113
114 -- remove literals and comments from a string
115 clean :: String -> String
116 clean s
117    = keep s
118      where
119         -- running through text we want to keep
120         keep []                   = []
121         keep ('"':cs)             = dquote cs           -- "
122                 -- try to eliminate single quotes when they're part of
123                 -- an identifier...
124         keep (c:'\'':cs) | isAlphaNum c || c == '_' = keep (dropWhile (=='\'') cs)
125         keep ('\'':cs)            = squote cs
126         keep ('-':'-':cs)         = linecomment cs
127         keep ('{':'-':'#':' ':cs) = "{-# " ++ keep cs
128         keep ('{':'-':cs)         = runcomment cs       -- -}
129         keep (c:cs)               = c : keep cs
130
131         -- in a double-quoted string
132         dquote []             = []
133         dquote ('\\':'\"':cs) = dquote cs               -- "
134         dquote ('\\':'\\':cs) = dquote cs
135         dquote ('\"':cs)      = keep cs                 -- "
136         dquote (c:cs)         = dquote cs
137
138         -- in a single-quoted string
139         squote []             = []
140         squote ('\\':'\'':cs) = squote cs
141         squote ('\\':'\\':cs) = squote cs
142         squote ('\'':cs)      = keep cs
143         squote (c:cs)         = squote cs
144
145         -- in a line comment
146         linecomment []        = []
147         linecomment ('\n':cs) = '\n':keep cs
148         linecomment (c:cs)    = linecomment cs
149
150         -- in a running comment
151         runcomment []           = []
152         runcomment ('-':'}':cs) = keep cs
153         runcomment (c:cs)       = runcomment cs
154 \end{code}