diff options
-rw-r--r-- | src/HaddockHtml.hs | 14 | ||||
-rw-r--r-- | src/HaddockRename.hs | 2 | ||||
-rw-r--r-- | src/HaddockTypes.hs | 12 | ||||
-rw-r--r-- | src/HsLexer.lhs | 5 | ||||
-rw-r--r-- | src/HsParser.ly | 20 | ||||
-rw-r--r-- | src/HsSyn.lhs | 6 | ||||
-rw-r--r-- | src/Main.hs | 363 |
7 files changed, 268 insertions, 154 deletions
diff --git a/src/HaddockHtml.hs b/src/HaddockHtml.hs index 5059070e..7d7700a4 100644 --- a/src/HaddockHtml.hs +++ b/src/HaddockHtml.hs @@ -48,14 +48,17 @@ ppHtml title source_url ifaces odir maybe_css libdir = do icon_file = libdir ++ pathSeparator:iconFile icon_destination = odir ++ pathSeparator:iconFile + visible_ifaces = filter visible ifaces + visible (m,i) = OptHide `notElem` iface_options i + css_contents <- readFile css_file writeFile css_destination css_contents icon_contents <- readFile icon_file writeFile icon_destination icon_contents - ppHtmlContents odir title source_url (map fst ifaces) - ppHtmlIndex odir title ifaces - mapM_ (ppHtmlModule odir title source_url) ifaces + ppHtmlContents odir title source_url (map fst visible_ifaces) + ppHtmlIndex odir title visible_ifaces + mapM_ (ppHtmlModule odir title source_url) visible_ifaces moduleHtmlFile :: String -> FilePath moduleHtmlFile mod = mod ++ ".html" -- ToDo: Z-encode filename? @@ -359,8 +362,6 @@ ppModuleContents exports process :: Int -> [ExportItem] -> ([Html],[ExportItem]) process n [] = ([], []) - process n (ExportDecl _ : rest) = process n rest - process n (ExportDoc _ : rest) = process n rest process n items@(ExportGroup lev id doc : rest) | lev <= n = ( [], items ) | otherwise = ( html:sections, rest2 ) @@ -369,6 +370,7 @@ ppModuleContents exports +++ mk_subsections subsections (subsections, rest1) = process lev rest (sections, rest2) = process n rest1 + process n (_ : rest) = process n rest mk_subsections [] = noHtml mk_subsections ss = ddef << dlist << concatHtml ss @@ -392,6 +394,8 @@ processExport doc_map summary (ExportDecl decl) processExport doc_map summary (ExportDoc doc) | summary = Html.emptyTable | otherwise = docBox (markup htmlMarkup doc) +processExport doc_map summary (ExportModule (Module mod)) + = declBox (toHtml "module" <+> ppHsModule mod) ppDocGroup lev doc | lev == 1 = tda [ theclass "section1" ] << doc diff --git a/src/HaddockRename.hs b/src/HaddockRename.hs index ce954a52..f897c600 100644 --- a/src/HaddockRename.hs +++ b/src/HaddockRename.hs @@ -194,6 +194,8 @@ lookupIdString str = do renameExportItems items = mapM rn items where + rn (ExportModule mod) + = return (ExportModule mod) rn (ExportGroup lev id doc) = do doc <- renameDoc doc return (ExportGroup lev id doc) diff --git a/src/HaddockTypes.hs b/src/HaddockTypes.hs index f99d2893..5af102d4 100644 --- a/src/HaddockTypes.hs +++ b/src/HaddockTypes.hs @@ -7,6 +7,7 @@ module HaddockTypes ( -- * Module interfaces NameEnv, Interface(..), ModuleInfo(..), ExportItem(..), ModuleMap, + DocOption(..), -- * User documentation strings DocString, GenDoc(..), Doc, ParsedDoc, DocMarkup(..), @@ -52,8 +53,11 @@ data Interface iface_info :: Maybe ModuleInfo, -- ^ information from the module header - iface_doc :: Maybe Doc + iface_doc :: Maybe Doc, -- ^ documentation from the module header + + iface_options :: [DocOption] + -- ^ module-wide doc options } data ModuleInfo = ModuleInfo @@ -61,6 +65,9 @@ data ModuleInfo = ModuleInfo stability :: String, maintainer :: String } +data DocOption = OptHide | OptPrune | OptIgnoreExports + deriving (Eq) + type DocString = String data ExportItem @@ -75,6 +82,9 @@ data ExportItem | ExportDoc -- some documentation Doc + | ExportModule -- a cross-reference to another module + Module + type ModuleMap = FiniteMap Module Interface -- ----------------------------------------------------------------------------- diff --git a/src/HsLexer.lhs b/src/HsLexer.lhs index 8f5c0174..1899dda5 100644 --- a/src/HsLexer.lhs +++ b/src/HsLexer.lhs @@ -1,5 +1,5 @@ ----------------------------------------------------------------------------- --- $Id: HsLexer.lhs,v 1.4 2002/04/25 14:40:05 simonmar Exp $ +-- $Id: HsLexer.lhs,v 1.5 2002/05/08 11:21:56 simonmar Exp $ -- -- (c) The GHC Team, 1997-2000 -- @@ -68,6 +68,7 @@ data Token | DocCommentPrev String -- something beginning '-- ^' | DocCommentNamed String -- something beginning '-- $' | DocSection Int String -- a section heading + | DocOptions String -- Reserved operators @@ -223,6 +224,7 @@ lexer cont input (SrcLoc _ x) y col = doc (' ':'^':_) = True doc (' ':'*':_) = True doc (' ':'$':_) = True + doc (' ':'#':_) = True doc _ = False nextTab x = x + (tAB_LENGTH - (x-1) `mod` tAB_LENGTH) @@ -283,6 +285,7 @@ lexToken cont s loc y x = '-':'-':' ':'^':s -> docComment DocCommentPrev cont s loc y x '-':'-':' ':'$':s -> docComment DocCommentNamed cont s loc y x '-':'-':' ':'*':s -> docSection cont ('*':s) loc y x + '-':'-':' ':'#':s -> docComment DocOptions cont s loc y x '\'':s -> lexChar cont s loc y (x+1) '\"':s{-"-} -> lexString cont s loc y (x+1) diff --git a/src/HsParser.ly b/src/HsParser.ly index 5a254ec1..2ca9c88f 100644 --- a/src/HsParser.ly +++ b/src/HsParser.ly @@ -1,5 +1,5 @@ ----------------------------------------------------------------------------- -$Id: HsParser.ly,v 1.7 2002/05/06 12:32:32 simonmar Exp $ +$Id: HsParser.ly,v 1.8 2002/05/08 11:21:56 simonmar Exp $ (c) Simon Marlow, Sven Panne 1997-2000 @@ -72,6 +72,7 @@ Docs > DOCPREV { DocCommentPrev $$ } > DOCNAMED { DocCommentNamed $$ } > DOCGROUP { DocSection _ _ } +> DOCOPTIONS { DocOptions $$ } Symbols @@ -152,13 +153,18 @@ Module Header > module :: { HsModule } > : optdoc 'module' modid maybeexports 'where' body -> { HsModule $3 $4 (reverse (fst $6)) (reverse (snd $6)) $1 } +> { HsModule $3 $4 (reverse (fst $6)) (reverse (snd $6)) +> (fst $1) (snd $1) } > | body -> { HsModule main_mod Nothing (reverse (fst $1)) (reverse (snd $1)) Nothing } - -> optdoc :: { Maybe String } -> : DOCNEXT { Just $1 } -> | {- empty -} { Nothing } +> { HsModule main_mod Nothing (reverse (fst $1)) (reverse (snd $1)) +> Nothing Nothing } + +> optdoc :: { (Maybe String, Maybe String) } +> : DOCNEXT { (Nothing, Just $1) } +> | DOCOPTIONS { (Just $1, Nothing) } +> | DOCOPTIONS DOCNEXT { (Just $1, Just $2) } +> | DOCNEXT DOCOPTIONS { (Just $2, Just $1) } +> | {- empty -} { (Nothing, Nothing) } > body :: { ([HsImportDecl],[HsDecl]) } > : '{' bodyaux '}' { $2 } diff --git a/src/HsSyn.lhs b/src/HsSyn.lhs index e732f2f8..5054a8df 100644 --- a/src/HsSyn.lhs +++ b/src/HsSyn.lhs @@ -1,5 +1,5 @@ % ----------------------------------------------------------------------------- -% $Id: HsSyn.lhs,v 1.5 2002/04/26 11:18:57 simonmar Exp $ +% $Id: HsSyn.lhs,v 1.6 2002/05/08 11:21:56 simonmar Exp $ % % (c) The GHC Team, 1997-2002 % @@ -68,7 +68,9 @@ instance Show HsIdentifier where showsPrec _ (HsSpecial s) = showString s data HsModule = HsModule Module (Maybe [HsExportSpec]) - [HsImportDecl] [HsDecl] (Maybe String) + [HsImportDecl] [HsDecl] + (Maybe String) -- the doc options + (Maybe String) -- the module doc deriving Show -- Export/Import Specifications diff --git a/src/Main.hs b/src/Main.hs index 08a70bde..c5d39844 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -25,12 +25,15 @@ import FiniteMap --import Pretty import RegexString +import Maybe ( maybeToList ) import List ( nub ) import Monad ( when ) import Char ( isSpace ) import IO import IOExts +import MonadWriter + #if __GLASGOW_HASKELL__ < 500 import Regex import PackedString @@ -106,14 +109,15 @@ run flags files = do writeIORef saved_flags flags parsed_mods <- sequence (map parse_file files) - let ifaces = [ mkInterface module_map file parsed + let ifaces = [ runWriter (mkInterface module_map file parsed) | (file,parsed) <- zip files parsed_mods ] - mod_ifaces = [ (m,i) | (m,i,_,_) <- ifaces ] + mod_ifaces = [ (m,i) | ((m,i),msgs) <- ifaces ] + all_msgs = concat (map snd ifaces) + module_map = listToFM mod_ifaces - sequence [ reportMissingNames m ns_docs ns_decls - | (m, _, ns_docs, ns_decls) <- ifaces ] + mapM (hPutStrLn stderr) all_msgs when (Flag_DocBook `elem` flags) $ putStr (ppDocBook odir mod_ifaces) @@ -133,116 +137,142 @@ parse_file file = do exitWith (ExitFailure 1) ) -reportMissingNames m [] [] = return () -reportMissingNames (Module m) ns_docs ns_decls = do - hPutStrLn stderr ("Warning: in module " ++ m ++ - ", the following names could not be resolved:") - let name_strings = nub (map show ns_decls ++ ns_docs) - hPutStrLn stderr (" " ++ concat (map (' ':) name_strings)) - ----------------------------------------------------------------------------- -- Figuring out the definitions that are exported from a module -mkInterface :: ModuleMap -> FilePath -> HsModule - -> (Module, -- the module name - Interface, -- its "interface" - [String], -- a list of names we couldn't resolve in the docs - [HsQName] -- a list of names we couldn't resolve in the decls - ) +mkInterface + :: ModuleMap -> FilePath -> HsModule + -> ErrMsgM ( + Module, -- the module name + Interface -- its "interface" + ) -mkInterface mod_map filename (HsModule mod exps imps decls maybe_doc) - = (mod, Interface { - iface_filename = filename, - iface_env = name_env, - iface_exports = renamed_export_list, - iface_orig_exports = orig_export_list, - iface_decls = decl_map, - iface_info = maybe_info, - iface_name_docs = doc_map, - iface_doc = module_doc - }, - missing_names_doc1 ++ missing_names_doc2, - missing_names1 ++ missing_names2 --ignore missing_names3 for now, - ) - where - (module_doc, maybe_info, missing_names_doc1) = - case maybe_doc of - Nothing -> (Nothing, Nothing, []) - Just doc -> (Just doc2, maybe_info, ns) - where - (doc1, maybe_info) = parseModuleHeader doc - (doc2,ns) = formatDocString (lookupForDoc import_env) doc1 +mkInterface mod_map filename + (HsModule mod exps imps decls maybe_opts maybe_doc) = do - locally_defined_names = collectNames decls + -- Process the options, if available + options <- case maybe_opts of + Just opt_str -> processOptions opt_str + Nothing -> return [] - qual_local_names = map (Qual mod) locally_defined_names - unqual_local_names = map UnQual locally_defined_names + let + locally_defined_names = collectNames decls - local_env = listToFM (zip unqual_local_names qual_local_names ++ - zip qual_local_names qual_local_names) + 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) -- both qualified and unqualifed names are in scope for local things - -- build the orig_env, which maps names to *original* names (so we can - -- find the original declarations & docs for things). - (ext_orig_envs, ext_import_envs) + -- build the orig_env, which maps names to *original* names (so we can + -- find the original declarations & docs for things). + (ext_orig_envs, ext_import_envs) = unzip (map (buildEnv mod_map mod exported_names) imps) - orig_env = foldr plusFM local_env ext_orig_envs - import_env = foldr plusFM local_env ext_import_envs + orig_env = foldr plusFM local_env ext_orig_envs + import_env = foldr plusFM local_env ext_import_envs - -- convert names in source code to original, fully qualified, names - (orig_exports, missing_names1) + -- convert names in source code to original, fully qualified, names + (orig_exports, missing_names1) = runRnFM orig_env (mapMaybeM renameExportList exps) - (orig_decls, missing_names2) + (orig_decls, missing_names2) = runRnFM orig_env (mapM renameDecl decls) - orig_decl_map :: FiniteMap HsName HsDecl - orig_decl_map = listToFM [ (n,d) | d <- orig_decls, n <- declBinders d ] + orig_decl_map :: FiniteMap HsName HsDecl + orig_decl_map = listToFM [ (n,d) | d <- orig_decls, n <- declBinders d ] - -- gather up a list of entities that are exported (original names) - exported_names = exportedNames mod mod_map orig_decls + -- gather up a list of entities that are exported (original names) + exported_names = exportedNames mod mod_map orig_decls locally_defined_names orig_exports - orig_decl_map - - 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 - - local_docs_formatted :: [(HsName,(Doc,[String]))] - local_docs_formatted = - [ (n, formatDocString (lookupForDoc orig_env) doc) - | (n, doc) <- local_docstrings ] - - 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 ] + 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 (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 (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 ] -- make the "export items", which will be converted into docs later - orig_export_list = mkExportItems mod_map mod orig_env - decl_map final_decls orig_exports - - -- 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) - = runRnFM import_env (renameExportItems orig_export_list) - - name_env = listToFM [ (nameOfQName n, n) | n <- exported_names ] + orig_export_list <- mkExportItems mod_map mod orig_env + decl_map final_decls options orig_exports + + let + -- 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 + | 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) + = 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 + --ignore missing_names3 for now, + + name_strings = nub (map show missing_names ++ missing_names_doc) + + when (not (null name_strings)) $ + tell ["Warning: in module " ++ (case mod of Module m -> m) ++ + ", the following names could not be resolved:\n\ + \ " ++ concat (map (' ':) name_strings) + ] + + return (mod, Interface { + 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 + } + ) -- ----------------------------------------------------------------------------- -- Find the documentation for a particular name, and rename the @@ -274,13 +304,20 @@ mkExportItems :: ModuleMap -> Module -> FiniteMap HsQName HsQName -- maps orig to imported names -> FiniteMap HsName HsDecl -- maps local names to declarations -> [HsDecl] -- decls in the current module + -> [DocOption] -> Maybe [HsExportSpec] - -> [ExportItem] -mkExportItems mod_map mod env decl_map decls Nothing - = fullContentsOfThisModule decls env -- everything exported -mkExportItems mod_map mod env decl_map decls (Just specs) - = concat (map lookupExport specs) + -> ErrMsgM [ExportItem] +mkExportItems mod_map mod env decl_map decls options maybe_exps + | Nothing <- maybe_exps = everything_local_exported + | OptIgnoreExports `elem` options = everything_local_exported + | Just specs <- maybe_exps = do + exps <- mapM lookupExport specs + return (concat exps) where + + everything_local_exported = + fullContentsOfThisModule decls env -- everything exported + lookupExport (HsEVar x) | Just decl <- findDecl x = let decl' | HsTypeSig loc ns ty <- decl @@ -288,39 +325,46 @@ mkExportItems mod_map mod env decl_map decls (Just specs) | otherwise = decl in - [ ExportDecl decl' ] + return [ ExportDecl decl' ] -- ToDo: cope with record selectors here lookupExport (HsEAbs t) | Just decl <- findDecl t - = [ ExportDecl (restrictTo [] decl) ] + = return [ ExportDecl (restrictTo [] decl) ] lookupExport (HsEThingAll t) | Just decl <- findDecl t - = [ ExportDecl decl ] + = return [ ExportDecl decl ] lookupExport (HsEThingWith t cs) | Just decl <- findDecl t - = [ ExportDecl (restrictTo (map nameOfQName cs) decl) ] + = return [ ExportDecl (restrictTo (map nameOfQName cs) decl) ] lookupExport (HsEModuleContents m) = fullContentsOf m lookupExport (HsEGroup lev str) - = [ ExportGroup lev "" doc ] - where (doc, _names) = formatDocHeading (lookupForDoc env) str - -- ToDo: report the unresolved names + = do (doc, _names) <- formatDocHeading (lookupForDoc env) str + return [ ExportGroup lev "" doc ] + -- ToDo: report the unresolved names lookupExport (HsEDoc str) - = [ ExportDoc doc ] - where (doc, _names) = formatDocString (lookupForDoc env) str + = do (doc, _names) <- formatDocString (lookupForDoc env) str + return [ ExportDoc doc ] -- ToDo: report the unresolved names lookupExport (HsEDocNamed str) - | Just found <- findNamedDoc str decls - = let (doc, _names) = formatDocString (lookupForDoc env) found in - [ ExportDoc doc ] + = do r <- findNamedDoc str decls + case r of + Nothing -> return [] + Just found -> do + (doc, _nms) <- formatDocString (lookupForDoc env) found + return [ ExportDoc doc ] - lookupExport _ = [] -- didn't find it? + lookupExport _ = return [] -- didn't find it? fullContentsOf m | m == mod = fullContentsOfThisModule decls env | otherwise = case lookupFM mod_map m of - Just iface -> iface_orig_exports iface - Nothing -> trace ("Warning: module not found: " ++ show m) [] + Just iface + | OptHide `elem` iface_options iface + -> return (iface_orig_exports iface) + | otherwise -> return [ ExportModule m ] + Nothing -> do tell ["Warning: module not found: " ++ show m] + return [] findDecl :: HsQName -> Maybe HsDecl findDecl (UnQual n) @@ -330,17 +374,15 @@ mkExportItems mod_map mod env decl_map decls (Just specs) | otherwise = case lookupFM mod_map m of Just iface -> lookupFM (iface_decls iface) n - Nothing -> - trace ("Warning: module not found: " ++ show m) Nothing + Nothing -> Nothing fullContentsOfThisModule decls env = - [ mkExportItem decl | decl <- decls, keepDecl decl ] - where mkExportItem (HsDocGroup lev str) = - ExportGroup lev "" doc - where - (doc, _names) = formatDocHeading (lookupForDoc env) str + mapM mkExportItem (filter keepDecl decls) + where mkExportItem (HsDocGroup lev str) = do + (doc, _names) <- formatDocHeading (lookupForDoc env) str + return (ExportGroup lev "" doc) -- ToDo: report the unresolved names - mkExportItem decl = ExportDecl decl + mkExportItem decl = return (ExportDecl decl) keepDecl HsTypeSig{} = True @@ -352,17 +394,29 @@ keepDecl HsDocGroup{} = True 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 + has_doc _ = True + +-- ----------------------------------------------------------------------------- -- Gather a list of original names exported from this module exportedNames :: Module -> ModuleMap -> [HsDecl] -> [HsName] -> Maybe [HsExportSpec] -> FiniteMap HsName HsDecl + -> [DocOption] -> [HsQName] -exportedNames mod mod_scope decls local_names Nothing decl_map - = map (Qual mod) local_names -exportedNames mod mod_scope decls local_names (Just expspecs) decl_map - = concat (map extract expspecs) + +exportedNames mod mod_scope decls local_names maybe_exps decl_map options + | Nothing <- maybe_exps = all_local_names + | OptIgnoreExports `elem` options = all_local_names + | Just expspecs <- maybe_exps = concat (map extract expspecs) where + all_local_names = map (Qual mod) local_names + extract e = case e of HsEVar x -> [x] @@ -493,24 +547,26 @@ docsFromField (HsFieldDecl nms ty Nothing) rest -- this one formats a heading formatDocHeading :: (String -> Maybe HsQName) -> DocString - -> (Doc,[String]) + -> ErrMsgM (Doc,[String]) formatDocHeading lookup string = format parseString lookup string -- this one formats a sequence of paragraphs formatDocString :: (String -> Maybe HsQName) -> DocString - -> (Doc,[String]) + -> ErrMsgM (Doc,[String]) formatDocString lookup string = format parseParas lookup string format :: ([Token] -> Either String ParsedDoc) -> (String -> Maybe HsQName) -> DocString - -> (Doc, [String]) + -> ErrMsgM (Doc, [String]) format parse lookup string = case parse (tokenise string) of - Left error -> trace ("Warning: parse error in doc string beginning:\n\ - \ " ++ take 40 string) (DocEmpty, []) - Right doc -> runRn lookup (resolveDoc doc) - + Left error -> do + tell ["Warning: parse error in doc string beginning:\n\ + \ " ++ take 40 string] + return (DocEmpty, []) + Right doc -> + return (runRn lookup (resolveDoc doc)) -- --------------------------------------------------------------------------- -- Looking up names in documentation @@ -584,17 +640,48 @@ mkRegexWithOpts s single_line case_sensitive -- ----------------------------------------------------------------------------- -- Named documentation -findNamedDoc :: String -> [HsDecl] -> Maybe String +findNamedDoc :: String -> [HsDecl] -> ErrMsgM (Maybe String) findNamedDoc str decls = case matchRegex docNameRE str of Just (name:_) -> search decls - where search [] = Nothing + 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' -> Just after + | name == name' -> return (Just after) _otherwise -> search rest search (_other_decl : rest) = search rest - _other -> Nothing + _other -> do + tell ["Invalid documentation name: $" ++ str] + return Nothing docNameRE = mkRegex "[ \t]*([A-Za-z0-9_]*)" + +-- ----------------------------------------------------------------------------- +-- Haddock options embedded in the source file + +processOptions :: String -> ErrMsgM [DocOption] +processOptions str = do + case break (== ',') str of + (this, ',':rest) -> do + opt <- parseOption this + opts <- processOptions rest + return (maybeToList opt ++ opts) + (this, _) + | all isSpace this -> return [] + | otherwise -> do opt <- parseOption this; return (maybeToList opt) + +parseOption :: String -> ErrMsgM (Maybe DocOption) +parseOption "hide" = return (Just OptHide) +parseOption "prune" = return (Just OptPrune) +parseOption "ignore-exports" = return (Just OptIgnoreExports) +parseOption other = do tell ["Unrecognised option: " ++ other]; return Nothing + +-- ----------------------------------------------------------------------------- +-- A monad which collects error messages + +type ErrMsg = String +type ErrMsgM a = Writer [ErrMsg] a + |