aboutsummaryrefslogtreecommitdiff
path: root/src/Main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Main.hs')
-rw-r--r--src/Main.hs355
1 files changed, 85 insertions, 270 deletions
diff --git a/src/Main.hs b/src/Main.hs
index 7a2ad007..96425a46 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -8,14 +8,12 @@ module Main (main) where
import HaddockRename
import HaddockParse
-import HaddockLex
-import HaddockDB
+--import HaddockDB -- not compiling
import HaddockHtml
import HaddockTypes
import HaddockUtil
import Digraph
-import HsLexer hiding (Token)
import HsParser
import HsParseMonad
import HsSyn
@@ -25,8 +23,7 @@ import FiniteMap
--import Pretty
-import RegexString
-import Maybe ( maybeToList )
+import Maybe ( isJust, maybeToList )
import List ( nub )
import Monad ( when )
import Char ( isSpace )
@@ -126,8 +123,8 @@ run flags files = do
module_map <- loop emptyFM sorted_mods files
let mod_ifaces = fmToList module_map
- when (Flag_DocBook `elem` flags) $
- putStr (ppDocBook odir mod_ifaces)
+-- when (Flag_DocBook `elem` flags) $
+-- putStr (ppDocBook odir mod_ifaces)
when (Flag_Html `elem` flags) $
ppHtml title source_url mod_ifaces odir css_file libdir
@@ -155,7 +152,7 @@ mkInterface
)
mkInterface mod_map filename
- (HsModule mod exps imps decls maybe_opts maybe_doc) = do
+ (HsModule mod exps imps decls maybe_opts maybe_info maybe_doc) = do
-- Process the options, if available
options <- case maybe_opts of
@@ -163,13 +160,17 @@ mkInterface mod_map filename
Nothing -> return []
let
- locally_defined_names = collectNames decls
+ -- first, attach documentation to declarations
+ annotated_decls = collectDoc decls
+
+ -- now find the defined names
+ locally_defined_names = collectNames annotated_decls
qual_local_names = map (Qual mod) locally_defined_names
unqual_local_names = map UnQual locally_defined_names
local_env = listToFM (zip unqual_local_names qual_local_names ++
- zip qual_local_names qual_local_names)
+ zip qual_local_names qual_local_names)
-- both qualified and unqualifed names are in scope for local things
-- build the orig_env, which maps names to *original* names (so we can
@@ -184,7 +185,7 @@ mkInterface mod_map filename
= runRnFM orig_env (mapMaybeM renameExportList exps)
(orig_decls, missing_names2)
- = runRnFM orig_env (mapM renameDecl decls)
+ = runRnFM orig_env (mapM renameDecl annotated_decls)
orig_decl_map :: FiniteMap HsName HsDecl
orig_decl_map = listToFM [ (n,d) | d <- orig_decls, n <- declBinders d ]
@@ -194,45 +195,9 @@ mkInterface mod_map filename
locally_defined_names orig_exports
orig_decl_map options
- -- Parse the module header
- (module_doc, maybe_info, missing_names_doc1) <-
- case maybe_doc of
- Nothing -> return (Nothing, Nothing, [])
- Just doc -> do
- let (doc1, maybe_info) = parseModuleHeader doc
- (doc2,ns) <- formatDocString mod (lookupForDoc import_env) doc1
- return (Just doc2, maybe_info, ns)
-
let
final_decls = concat (map expandDecl orig_decls)
- -- match documentation to names, and resolve identifiers in the
- -- documentation
- local_docstrings :: [(HsName,DocString)]
- local_docstrings = collectDoc final_decls
-
- formatLocalDoc (n,doc) = do
- doc' <- formatDocString mod (lookupForDoc orig_env) doc
- return (n,doc')
-
- local_docs_formatted <- mapM formatLocalDoc local_docstrings
-
- let
- local_docs :: [(HsName,Doc)] -- with *original* names
- local_docs = [ (n,doc) | (n,(doc,_)) <- local_docs_formatted ]
-
- -- collect the list of names which we couldn't resolve in the documentation
- missing_names_doc2 = concat [ ns | (n,(doc,ns)) <- local_docs_formatted ]
-
- -- get the documentation associated with entities exported from this module
- -- ToDo: we should really store the documentation in both orig and imported
- -- forms, like the export items.
- doc_map :: FiniteMap HsName Doc -- with *imported* names
- doc_map = listToFM
- [ (nameOfQName n, doc)
- | n <- exported_names,
- Just doc <- [lookupDoc mod_map mod local_docs import_env n] ]
-
decl_map :: FiniteMap HsName HsDecl
decl_map = listToFM [ (n,d) | d <- final_decls, n <- declBinders d ]
@@ -244,23 +209,21 @@ mkInterface mod_map filename
-- prune the export list to just those declarations that have
-- documentation, if the 'prune' option is on.
pruned_export_list
- | OptPrune `elem` options = pruneExportItems doc_map orig_export_list
+ | OptPrune `elem` options = pruneExportItems orig_export_list
| otherwise = orig_export_list
-- rename names in the exported declarations to point to things that
-- are closer, or maybe even exported by, the current module.
- (renamed_export_list, missing_names3)
+ (renamed_export_list, _missing_names3)
= runRnFM import_env (renameExportItems pruned_export_list)
name_env = listToFM [ (nameOfQName n, n) | n <- exported_names ]
-- report any names we couldn't find/resolve
- let missing_names_doc = missing_names_doc1 ++ missing_names_doc2
- missing_names = missing_names1 ++ missing_names2
+ let missing_names = missing_names1 ++ missing_names2
--ignore missing_names3 for now,
-
- name_strings = nub (map show missing_names ++ missing_names_doc)
+ name_strings = nub (map show missing_names)
when (not (null name_strings)) $
tell ["Warning: in module " ++ show mod ++
@@ -269,40 +232,18 @@ mkInterface mod_map filename
]
return (mod, Interface {
- iface_filename = filename,
- iface_env = name_env,
- iface_exports = renamed_export_list,
+ iface_filename = filename,
+ iface_env = name_env,
+ iface_exports = renamed_export_list,
iface_orig_exports = pruned_export_list,
- iface_decls = decl_map,
- iface_info = maybe_info,
- iface_name_docs = doc_map,
- iface_doc = module_doc,
- iface_options = options
+ iface_decls = decl_map,
+ iface_info = maybe_info,
+ iface_doc = maybe_doc,
+ iface_options = options
}
)
-- -----------------------------------------------------------------------------
--- Find the documentation for a particular name, and rename the
--- original identifiers embedded in it to imported names.
-
-lookupDoc :: ModuleMap -> Module -> [(HsName,Doc)]
- -> FiniteMap HsQName HsQName -> HsQName -> Maybe Doc
-lookupDoc mod_map this_mod local_doc env name
- = case name of
- UnQual n -> Nothing
- Qual mod n
- | mod == this_mod ->
- fst (runRnFM env (mapMaybeM renameDoc (lookup n local_doc)))
- -- ToDo: report missing names
- | otherwise ->
- case lookupFM mod_map mod of
- Nothing -> Nothing
- Just iface ->
- fst (runRnFM env (mapMaybeM renameDoc
- (lookupFM (iface_name_docs iface) n)))
- -- ToDo: report missing names
-
--- -----------------------------------------------------------------------------
-- Build the list of items that will become the documentation, from the
-- export list. At the same time we rename *original* names in the declarations
-- to *imported* names.
@@ -327,8 +268,8 @@ mkExportItems mod_map mod env decl_map decls options maybe_exps
lookupExport (HsEVar x)
| Just decl <- findDecl x
- = let decl' | HsTypeSig loc ns ty <- decl
- = HsTypeSig loc [nameOfQName x] ty
+ = let decl' | HsTypeSig loc ns ty doc <- decl
+ = HsTypeSig loc [nameOfQName x] ty doc
| otherwise
= decl
in
@@ -344,21 +285,15 @@ mkExportItems mod_map mod env decl_map decls options maybe_exps
| Just decl <- findDecl t
= return [ ExportDecl (restrictTo (map nameOfQName cs) decl) ]
lookupExport (HsEModuleContents m) = fullContentsOf m
- lookupExport (HsEGroup lev str)
- = do (doc, _names) <- formatDocHeading mod (lookupForDoc env) str
- return [ ExportGroup lev "" doc ]
- -- ToDo: report the unresolved names
- lookupExport (HsEDoc str)
- = do (doc, _names) <- formatDocString mod (lookupForDoc env) str
- return [ ExportDoc doc ]
- -- ToDo: report the unresolved names
+ lookupExport (HsEGroup lev doc)
+ = return [ ExportGroup lev "" doc ]
+ lookupExport (HsEDoc doc)
+ = return [ ExportDoc doc ]
lookupExport (HsEDocNamed str)
= do r <- findNamedDoc str decls
case r of
Nothing -> return []
- Just found -> do
- (doc, _nms) <- formatDocString mod (lookupForDoc env) found
- return [ ExportDoc doc ]
+ Just found -> return [ ExportDoc found ]
lookupExport _ = return [] -- didn't find it?
@@ -385,12 +320,10 @@ mkExportItems mod_map mod env decl_map decls options maybe_exps
fullContentsOfThisModule mod decls env =
mapM mkExportItem (filter keepDecl decls)
- where mkExportItem (HsDocGroup lev str) = do
- (doc, _names) <- formatDocHeading mod (lookupForDoc env) str
+ where mkExportItem (HsDocGroup loc lev doc) =
return (ExportGroup lev "" doc)
- -- ToDo: report the unresolved names
- mkExportItem decl = return (ExportDecl decl)
-
+ mkExportItem decl =
+ return (ExportDecl decl)
keepDecl HsTypeSig{} = True
keepDecl HsTypeDecl{} = True
@@ -403,9 +336,9 @@ keepDecl _ = False
-- -----------------------------------------------------------------------------
-- Pruning
-pruneExportItems :: FiniteMap HsName Doc -> [ExportItem] -> [ExportItem]
-pruneExportItems doc_map items = filter has_doc items
- where has_doc (ExportDecl d) | Just n <- declMainBinder d = n `elemFM` doc_map
+pruneExportItems :: [ExportItem] -> [ExportItem]
+pruneExportItems items = filter has_doc items
+ where has_doc (ExportDecl d) = isJust (declDoc d)
has_doc _ = True
-- -----------------------------------------------------------------------------
@@ -487,190 +420,72 @@ buildEnv mod_map this_mod exported_names (HsImportDecl _ mod qual maybe_as _)
-- Expand multiple type signatures
expandDecl :: HsDecl -> [HsDecl]
-expandDecl (HsTypeSig loc fs qt) = [ HsTypeSig loc [f] qt | f <- fs ]
-expandDecl (HsClassDecl loc ty fds decls)
- = [ HsClassDecl loc ty fds (concat (map expandDecl decls)) ]
+expandDecl (HsTypeSig loc fs qt doc) = [ HsTypeSig loc [f] qt doc | f <- fs ]
+expandDecl (HsClassDecl loc ty fds decls doc)
+ = [ HsClassDecl loc ty fds (concat (map expandDecl decls)) doc ]
expandDecl d = [ d ]
-----------------------------------------------------------------------------
--- Collecting documentation and associating it with declarations
+-- Collecting documentation and attach it to the right declarations
-collectDoc :: [HsDecl] -> [(HsName, DocString)]
-collectDoc decls = collect Nothing "" decls
+collectDoc :: [HsDecl] -> [HsDecl]
+collectDoc decls = collect Nothing DocEmpty decls
-collect name doc_so_far [] =
- case name of
+collect d doc_so_far [] =
+ case d of
Nothing -> []
- Just n -> finishedDoc n doc_so_far []
+ Just d -> finishedDoc d doc_so_far []
-collect name doc_so_far (decl:ds) =
+collect d doc_so_far (decl:ds) =
case decl of
- HsDocCommentNext str ->
- case name of
- Nothing -> collect name (doc_so_far ++ str) ds
- Just n -> finishedDoc n doc_so_far (collect Nothing str ds)
+ HsDocCommentNext loc str ->
+ case d of
+ Nothing -> collect d (docAppend doc_so_far str) ds
+ Just d -> finishedDoc d doc_so_far (collect Nothing str ds)
- HsDocCommentPrev str -> collect name (doc_so_far ++ str) ds
+ HsDocCommentPrev loc str -> collect d (docAppend doc_so_far str) ds
_other ->
- docsFromDecl decl ++
- case name of
- Nothing -> collect bndr doc_so_far ds
- Just n -> finishedDoc n doc_so_far (collect bndr "" ds)
- where
- bndr = declMainBinder decl
-
-finishedDoc n s rest | all isSpace s = rest
- | otherwise = (n,s) : rest
-
--- look inside a declaration and get docs for the bits
--- (constructors, record fields, class methods)
-docsFromDecl :: HsDecl -> [(HsName, DocString)]
-docsFromDecl (HsDataDecl loc ctxt nm tvs cons drvs)
- = concat (map docsFromConDecl cons)
-docsFromDecl (HsNewTypeDecl loc ctxt nm tvs con drvs)
- = docsFromConDecl con
-docsFromDecl (HsClassDecl loc ty fds decls)
- = collect Nothing "" decls
-docsFromDecl _
- = []
-
-docsFromConDecl :: HsConDecl -> [(HsName, DocString)]
-docsFromConDecl (HsConDecl loc nm tvs ctxt tys (Just doc))
- = finishedDoc nm doc []
-docsFromConDecl (HsRecDecl loc nm tvs ctxt fields (Just doc))
- = finishedDoc nm doc (foldr docsFromField [] fields)
-docsFromConDecl (HsRecDecl loc nm tvs ctxt fields Nothing)
- = foldr docsFromField [] fields
-docsFromConDecl _
- = []
-
-docsFromField (HsFieldDecl nms ty (Just doc)) rest
- = foldr (\n -> finishedDoc n doc) rest nms
-docsFromField (HsFieldDecl nms ty Nothing) rest
- = rest
-
------------------------------------------------------------------------------
--- formatting is done in two stages. Firstly we partially apply
--- formatDocString to the lookup function and the DocString to get a
--- markup-independent string. Finally the back ends apply the markup
--- description to this function to get the marked-up text.
-
--- this one formats a heading
-formatDocHeading :: Module -> (String -> Maybe HsQName) -> DocString
- -> ErrMsgM (Doc,[String])
-formatDocHeading mod lookup string = format mod parseString lookup string
-
--- this one formats a sequence of paragraphs
-formatDocString :: Module -> (String -> Maybe HsQName) -> DocString
- -> ErrMsgM (Doc,[String])
-formatDocString mod lookup string = format mod parseParas lookup string
-
-format :: Module -- for error messages only
- -> ([Token] -> Either String ParsedDoc)
- -> (String -> Maybe HsQName)
- -> DocString
- -> ErrMsgM (Doc, [String])
-format mod parse lookup string
- = case parse (tokenise string) of
- Left error -> do
- tell ["Warning: in " ++ show mod ++
- ", parse error in doc string beginning:\n\
- \ " ++ take 40 string]
- return (DocEmpty, [])
- Right doc ->
- return (runRn lookup (resolveDoc doc))
-
--- ---------------------------------------------------------------------------
--- Looking up names in documentation
-
-lookupForDoc :: FiniteMap HsQName HsQName -> (String -> Maybe HsQName)
-lookupForDoc fm str
- = case [ n | Just n <- map (lookupFM fm) (strToHsQNames str) ] of
- (n:_) -> Just n
- [] -> Nothing
-
-strToHsQNames :: String -> [ HsQName ]
-strToHsQNames str
- = case lexer (\t -> returnP t) str (SrcLoc 1 1) 1 1 [] of
- Ok _ (VarId str)
- -> [ UnQual (HsVarName (HsIdent str)) ]
- Ok _ (QVarId (mod,str))
- -> [ Qual (Module mod) (HsVarName (HsIdent str)) ]
- Ok _ (ConId str)
- -> [ UnQual (HsTyClsName (HsIdent str)),
- UnQual (HsVarName (HsIdent str)) ]
- Ok _ (QConId (mod,str))
- -> [ Qual (Module mod) (HsTyClsName (HsIdent str)),
- Qual (Module mod) (HsVarName (HsIdent str)) ]
- Ok _ (VarSym str)
- -> [ UnQual (HsVarName (HsSymbol str)) ]
- Ok _ (ConSym str)
- -> [ UnQual (HsTyClsName (HsSymbol str)),
- UnQual (HsVarName (HsSymbol str)) ]
- Ok _ (QVarSym (mod,str))
- -> [ Qual (Module mod) (HsVarName (HsSymbol str)) ]
- Ok _ (QConSym (mod,str))
- -> [ Qual (Module mod) (HsTyClsName (HsSymbol str)),
- Qual (Module mod) (HsVarName (HsSymbol str)) ]
- other -> []
-
--- -----------------------------------------------------------------------------
--- Parsing module headers
-
-parseModuleHeader :: String -> (String, Maybe ModuleInfo)
-parseModuleHeader str =
- case matchRegexAll moduleHeaderRE str of
- Just (before, match, after, _, (_:_:_:s1:s2:s3:_)) ->
- (after, Just (ModuleInfo {
- portability = s3,
- stability = s2,
- maintainer = s1 }))
- _other -> (str, Nothing)
-
-moduleHeaderRE = mkRegexWithOpts
- "^([ \t\n]*Module[ \t]*:.*\n)?\
- \([ \t\n]*Copyright[ \t]*:.*\n)?\
- \([ \t\n]*License[ \t]*:.*\n)?\
- \[ \t\n]*Maintainer[ \t]*:(.*)\n\
- \[ \t\n]*Stability[ \t]*:(.*)\n\
- \[ \t\n]*Portability[ \t]*:([^\n]*)\n"
- True -- match "\n" with "."
- False -- not case sensitive
- -- All fields except the last (Portability) may be multi-line.
- -- This is so that the portability field doesn't swallow up the
- -- rest of the module documentation - we might want to revist
- -- this at some point (perhaps have a separator between the
- -- portability field and the module documentation?).
-
-#if __GLASGOW_HASKELL__ < 500
-mkRegexWithOpts :: String -> Bool -> Bool -> Regex
-mkRegexWithOpts s single_line case_sensitive
- = unsafePerformIO (re_compile_pattern (packString s)
- single_line case_sensitive)
-#endif
+ let decl' = collectInDecl decl in
+ case d of
+ Nothing -> collect (Just decl') doc_so_far ds
+ Just d -> finishedDoc d doc_so_far (collect (Just decl') DocEmpty ds)
+
+finishedDoc d DocEmpty rest = d : rest
+finishedDoc d doc rest = d' : rest
+ where d' =
+ case d of
+ HsTypeDecl loc n ns ty _ ->
+ HsTypeDecl loc n ns ty (Just doc)
+ HsDataDecl loc ctxt n ns cons drv _ ->
+ HsDataDecl loc ctxt n ns cons drv (Just doc)
+ HsNewTypeDecl loc ctxt n ns con drv _ ->
+ HsNewTypeDecl loc ctxt n ns con drv (Just doc)
+ HsClassDecl loc ty fds meths _ ->
+ HsClassDecl loc ty fds meths (Just doc)
+ HsTypeSig loc ns ty _ ->
+ HsTypeSig loc ns ty (Just doc)
+ HsForeignImport loc cc sf str n ty _ ->
+ HsForeignImport loc cc sf str n ty (Just doc)
+ _other -> d
+
+collectInDecl (HsClassDecl loc ty fds meths doc)
+ = HsClassDecl loc ty fds (collect Nothing DocEmpty meths) doc
+collectInDecl decl
+ = decl
-- -----------------------------------------------------------------------------
-- Named documentation
-findNamedDoc :: String -> [HsDecl] -> ErrMsgM (Maybe String)
-findNamedDoc str decls =
- case matchRegex docNameRE str of
- Just (name:_) -> search decls
+findNamedDoc :: String -> [HsDecl] -> ErrMsgM (Maybe Doc)
+findNamedDoc name decls = search decls
where search [] = do
tell ["Cannot find documentation for: $" ++ name]
return Nothing
- search (HsDocCommentNamed str : rest) =
- case matchRegexAll docNameRE str of
- Just (_, _, after, _, name':_)
- | name == name' -> return (Just after)
- _otherwise -> search rest
+ search (HsDocCommentNamed loc name' doc : rest)
+ | name == name' = return (Just doc)
+ | otherwise = search rest
search (_other_decl : rest) = search rest
- _other -> do
- tell ["Invalid documentation name: $" ++ str]
- return Nothing
-
-docNameRE = mkRegex "[ \t]*([A-Za-z0-9_]*)"
-- -----------------------------------------------------------------------------
-- Haddock options embedded in the source file
@@ -702,13 +517,13 @@ sortModules hsmodules = mapM for_each_scc sccs
edges :: [(HsModule, Module, [Module])]
edges = [ (hsmod, mod, [ imp | HsImportDecl _ imp _ _ _ <- impdecls ])
- | hsmod@(HsModule mod _ impdecls _ _ _) <- hsmodules
+ | hsmod@(HsModule mod _ impdecls _ _ _ _) <- hsmodules
]
for_each_scc (AcyclicSCC hsmodule) = return hsmodule
for_each_scc (CyclicSCC hsmodules) =
dieMsg ("modules are recursive: " ++
- unwords (map show [ mod | HsModule mod _ _ _ _ _
+ unwords (map show [ mod | HsModule mod _ _ _ _ _ _
<- hsmodules ]))
-- -----------------------------------------------------------------------------