diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/HaddockDB.hs | 15 | ||||
-rw-r--r-- | src/HaddockHtml.hs | 220 | ||||
-rw-r--r-- | src/HaddockParse.y | 51 | ||||
-rw-r--r-- | src/HaddockRename.hs | 112 | ||||
-rw-r--r-- | src/HaddockTypes.hs | 121 | ||||
-rw-r--r-- | src/HaddockUtil.hs | 94 | ||||
-rw-r--r-- | src/HsLexer.lhs | 47 | ||||
-rw-r--r-- | src/HsParser.ly | 147 | ||||
-rw-r--r-- | src/HsSyn.lhs | 180 | ||||
-rw-r--r-- | src/Main.hs | 355 |
10 files changed, 678 insertions, 664 deletions
diff --git a/src/HaddockDB.hs b/src/HaddockDB.hs index a2a4a8e7..ebd0ccb2 100644 --- a/src/HaddockDB.hs +++ b/src/HaddockDB.hs @@ -6,7 +6,7 @@ module HaddockDB (ppDocBook) where -import HaddockTypes hiding (Doc) +import HaddockTypes import HaddockUtil import HsSyn @@ -16,6 +16,8 @@ import FiniteMap ----------------------------------------------------------------------------- -- Printing the results in DocBook format +ppDocBook = error "not working" +{- ppDocBook :: FilePath -> [(Module, Interface)] -> String ppDocBook odir mods = render (ppIfaces mods) @@ -55,22 +57,22 @@ ppIfaces mods $$ text "</varlistentry>" do_export _ _ = empty - do_decl (HsTypeSig _ [nm] ty) + do_decl (HsTypeSig _ [nm] ty _) = ppHsName nm <> text " :: " <> ppHsType ty - do_decl (HsTypeDecl _ nm args ty) + do_decl (HsTypeDecl _ nm args ty _) = hsep ([text "type", ppHsName nm ] ++ map ppHsName args ++ [equals, ppHsType ty]) - do_decl (HsNewTypeDecl loc ctx nm args con drv) + do_decl (HsNewTypeDecl loc ctx nm args con drv _) = hsep ([text "data", ppHsName nm] -- data, not newtype ++ map ppHsName args ) <+> equals <+> ppHsConstr con -- ToDo: derivings - do_decl (HsDataDecl loc ctx nm args cons drv) + do_decl (HsDataDecl loc ctx nm args cons drv _) = hsep ([text "data", {-ToDo: context-}ppHsName nm] ++ map ppHsName args) <+> vcat (zipWith (<+>) (equals : repeat (char '|')) (map ppHsConstr cons)) - do_decl (HsClassDecl loc ty fds decl) + do_decl (HsClassDecl loc ty fds decl _) = hsep [text "class", ppHsType ty] do_decl decl = empty @@ -158,3 +160,4 @@ ubxParenList :: [Doc] -> Doc ubxParenList = ubxparens . fsep . punctuate comma ubxparens p = text "(#" <> p <> text "#)" +-} diff --git a/src/HaddockHtml.hs b/src/HaddockHtml.hs index 2bd6b102..01d01d69 100644 --- a/src/HaddockHtml.hs +++ b/src/HaddockHtml.hs @@ -12,12 +12,13 @@ import HaddockTypes import HaddockUtil import HsSyn +import IO import Maybe ( fromJust, isNothing, isJust ) import FiniteMap import List ( sortBy ) import Char ( toUpper, toLower ) import Monad ( when ) ---import IOExts +import IOExts import Html import qualified Html @@ -79,8 +80,7 @@ src_button source_url mod file | Just u <- source_url = let src_url = if (last u == '/') then u ++ file else u ++ '/':file in - (tda [theclass "topbut", nowrap] << - anchor ! [href src_url] << toHtml "Source code") + topButBox (anchor ! [href src_url] << toHtml "Source code") | otherwise = Html.emptyTable @@ -88,16 +88,15 @@ src_button source_url mod file parent_button mod = case span (/= '.') (reverse mod) of (m, '.':rest) -> - (tda [theclass "topbut", nowrap] << + topButBox ( anchor ! [href (moduleHtmlFile (reverse rest))] << toHtml "Parent") _ -> Html.emptyTable -contentsButton = tda [theclass "topbut", nowrap] << - anchor ! [href contentsHtmlFile] << toHtml "Contents" +contentsButton = topButBox (anchor ! [href contentsHtmlFile] << + toHtml "Contents") -indexButton = tda [theclass "topbut", nowrap] << - anchor ! [href indexHtmlFile] << toHtml "Index" +indexButton = topButBox (anchor ! [href indexHtmlFile] << toHtml "Index") simpleHeader title = (tda [theclass "topbar"] << @@ -319,10 +318,8 @@ ifaceToHtml mod iface (contents </> description </> synopsis </> maybe_hr </> body) where exports = numberSectionHeadings (iface_exports iface) - doc_map = iface_name_docs iface - has_doc (ExportDecl d) - | Just x <- declMainBinder d = isJust (lookupFM doc_map x) + has_doc (ExportDecl d) = isJust (declDoc d) has_doc (ExportModule _) = False has_doc _ = True @@ -344,14 +341,14 @@ ifaceToHtml mod iface = (tda [theclass "section1"] << toHtml "Synopsis") </> (tda [width "100%", theclass "synopsis"] << table ! [width "100%", cellpadding 0, cellspacing 8, border 0] << - aboves (map (processExport doc_map True) exports)) + aboves (map (processExport True) exports)) maybe_hr | not (no_doc_at_all), ExportGroup 1 _ _ <- head exports = td << hr | otherwise = Html.emptyTable - body = aboves (map (processExport doc_map False) exports) + body = aboves (map (processExport False) exports) ppModuleContents :: [ExportItem] -> HtmlTable ppModuleContents exports @@ -386,16 +383,16 @@ numberSectionHeadings exports = go 1 exports go n (other:es) = other : go n es -processExport :: FiniteMap HsName Doc -> Bool -> ExportItem -> HtmlTable -processExport doc_map summary (ExportGroup lev id doc) +processExport :: Bool -> ExportItem -> HtmlTable +processExport summary (ExportGroup lev id doc) | summary = Html.emptyTable | otherwise = ppDocGroup lev (anchor ! [name id] << markup htmlMarkup doc) -processExport doc_map summary (ExportDecl decl) - = doDecl doc_map summary decl -processExport doc_map summary (ExportDoc doc) +processExport summary (ExportDecl decl) + = doDecl summary decl +processExport summary (ExportDoc doc) | summary = Html.emptyTable | otherwise = docBox (markup htmlMarkup doc) -processExport doc_map summary (ExportModule (Module mod)) +processExport summary (ExportModule (Module mod)) = declBox (toHtml "module" <+> ppHsModule mod) ppDocGroup lev doc @@ -415,43 +412,36 @@ declWithDoc False (Just doc) html_decl = vanillaTable << (declBox html_decl </> docBox (markup htmlMarkup doc)) -doDecl :: FiniteMap HsName Doc -> Bool -> HsDecl -> HtmlTable -doDecl doc_map summary decl = do_decl decl +doDecl :: Bool -> HsDecl -> HtmlTable +doDecl summary decl = do_decl decl where - doc | Just n <- declMainBinder decl = lookupFM doc_map n - | otherwise = Nothing + do_decl (HsTypeSig _ [nm] ty doc) + = ppFunSig summary nm ty doc - do_decl (HsTypeSig _ [nm] ty) = - declWithDoc summary doc (ppTypeSig summary nm ty) - - do_decl (HsTypeSig _ nms ty) - = declWithDoc summary doc ( - vanillaTable << aboves (map do_one nms)) - where do_one nm = declBox (ppTypeSig summary nm ty) - - do_decl (HsForeignImport _ _ _ _ n ty) + do_decl (HsForeignImport _ _ _ _ n ty doc) = declWithDoc summary doc (ppTypeSig summary n ty) - do_decl (HsTypeDecl _ nm args ty) + do_decl (HsTypeDecl _ nm args ty doc) = declWithDoc summary doc ( hsep ([keyword "type", ppHsBinder summary nm] ++ map ppHsName args) <+> equals <+> ppHsType ty) - do_decl (HsNewTypeDecl loc ctx nm args con drv) - = ppHsDataDecl doc_map summary True{-is newtype-} - (HsDataDecl loc ctx nm args [con] drv) + do_decl (HsNewTypeDecl loc ctx nm args con drv doc) + = ppHsDataDecl summary True{-is newtype-} + (HsDataDecl loc ctx nm args [con] drv doc) -- print it as a single-constructor datatype - do_decl decl@(HsDataDecl loc ctx nm args cons drv) - = ppHsDataDecl doc_map summary False{-not newtype-} decl + do_decl decl@(HsDataDecl loc ctx nm args cons drv doc) + = ppHsDataDecl summary False{-not newtype-} decl - do_decl decl@(HsClassDecl _ _ _ _) - = ppHsClassDecl doc_map summary decl + do_decl decl@(HsClassDecl _ _ _ _ _) + = ppHsClassDecl summary decl - do_decl (HsDocGroup lev str) - = if summary then Html.emptyTable else ppDocGroup lev str + do_decl (HsDocGroup loc lev str) + = if summary then Html.emptyTable + else ppDocGroup lev (markup htmlMarkup str) - do_decl _ = error (show decl) + do_decl _ = error ("do_decl: " ++ show decl) ppTypeSig summary nm ty = ppHsBinder summary nm <+> toHtml "::" <+> ppHsType ty @@ -469,11 +459,11 @@ keepDecl _ = False ppShortDataDecl :: Bool -> Bool -> HsDecl -> Html ppShortDataDecl summary is_newty - (HsDataDecl loc ctx nm args [con] drv) = + (HsDataDecl loc ctx nm args [con] drv _doc) = ppHsDataHeader summary is_newty nm args <+> equals <+> ppShortConstr summary con ppShortDataDecl summary is_newty - (HsDataDecl loc ctx nm args cons drv) = + (HsDataDecl loc ctx nm args cons drv _doc) = vanillaTable << ( aboves ( (declBox (ppHsDataHeader summary is_newty nm args) : @@ -486,16 +476,14 @@ ppShortDataDecl summary is_newty -- First, the abstract case: -ppHsDataDecl doc_map summary is_newty (HsDataDecl loc ctx nm args [] drv) = - declWithDoc summary (lookupFM doc_map nm) - (ppHsDataHeader summary is_newty nm args) +ppHsDataDecl summary is_newty (HsDataDecl loc ctx nm args [] drv doc) = + declWithDoc summary doc (ppHsDataHeader summary is_newty nm args) -- The rest of the cases: -ppHsDataDecl doc_map summary is_newty decl@(HsDataDecl loc ctx nm args cons drv) +ppHsDataDecl summary is_newty decl@(HsDataDecl loc ctx nm args cons drv doc) | summary || no_constr_docs - = declWithDoc summary (lookupFM doc_map nm) - (ppShortDataDecl summary is_newty decl) + = declWithDoc summary doc (ppShortDataDecl summary is_newty decl) | otherwise = td << vanillaTable << (header </> datadoc </> constrs) @@ -516,20 +504,17 @@ ppHsDataDecl doc_map summary is_newty decl@(HsDataDecl loc ctx nm args cons drv) aboves (constr_hdr : map do_constr cons) ) - do_constr con = ppHsFullConstr doc_map con - - Just c = declMainBinder decl - doc = lookupFM doc_map c + do_constr con = ppHsFullConstr con no_constr_docs = all constr_has_no_doc cons - constr_has_no_doc (HsConDecl _ nm _ _ _ _) - = isNothing (lookupFM doc_map nm) - constr_has_no_doc (HsRecDecl _ nm _ _ fields _) - = isNothing (lookupFM doc_map nm) && all field_has_no_doc fields + constr_has_no_doc (HsConDecl _ nm _ _ _ doc) + = isNothing doc + constr_has_no_doc (HsRecDecl _ nm _ _ fields doc) + = isNothing doc && all field_has_no_doc fields - field_has_no_doc (HsFieldDecl nms _ _) - = all isNothing (map (lookupFM doc_map) nms) + field_has_no_doc (HsFieldDecl nms _ doc) + = isNothing doc ppShortConstr :: Bool -> HsConDecl -> Html @@ -548,14 +533,12 @@ ppHsConstrHdr tvs ctxt +++ (if null ctxt then noHtml else ppHsContext ctxt <+> toHtml "=> ") -ppHsFullConstr doc_map (HsConDecl pos nm tvs ctxt typeList _maybe_doc) = +ppHsFullConstr (HsConDecl pos nm tvs ctxt typeList doc) = declWithDoc False doc ( hsep ((ppHsConstrHdr tvs ctxt +++ ppHsBinder False nm) : map ppHsBangType typeList) ) - where - doc = lookupFM doc_map nm -ppHsFullConstr doc_map (HsRecDecl pos nm tvs ctxt fields maybe_doc) = +ppHsFullConstr (HsRecDecl pos nm tvs ctxt fields doc) = td << vanillaTable << ( case doc of Nothing -> aboves [hdr, fields_html] @@ -571,10 +554,8 @@ ppHsFullConstr doc_map (HsRecDecl pos nm tvs ctxt fields maybe_doc) = fields_html = td << table ! [width "100%", cellpadding 0, cellspacing 8] << ( - aboves (map (ppFullField doc_map) - (concat (map expandField fields))) + aboves (map ppFullField (concat (map expandField fields))) ) - doc = lookupFM doc_map nm ppShortField summary (HsFieldDecl ns ty _doc) @@ -583,11 +564,11 @@ ppShortField summary (HsFieldDecl ns ty _doc) <+> toHtml "::" <+> ppHsBangType ty ) -ppFullField doc_map (HsFieldDecl [n] ty _doc) - = declWithDoc False (lookupFM doc_map n) ( +ppFullField (HsFieldDecl [n] ty doc) + = declWithDoc False doc ( ppHsBinder False n <+> toHtml "::" <+> ppHsBangType ty ) -ppFullField _ _ = error "ppFullField" +ppFullField _ = error "ppFullField" expandField (HsFieldDecl ns ty doc) = [ HsFieldDecl [n] ty doc | n <- ns ] @@ -610,16 +591,16 @@ ppClassHdr ty fds = fundep (vars1,vars2) = hsep (map ppHsName vars1) <+> toHtml "->" <+> hsep (map ppHsName vars2) -ppShortClassDecl doc_map summary decl@(HsClassDecl loc ty fds decls) = +ppShortClassDecl summary decl@(HsClassDecl loc ty fds decls doc) = if null decls then declBox hdr else td << ( vanillaTable << ( declBox (hdr <+> keyword "where") </> - tda [theclass "cbody"] << ( + tda [theclass "body"] << ( vanillaTable << ( - aboves (map (doDecl doc_map summary) (filter keepDecl decls)) + aboves (map (doDecl summary) (filter keepDecl decls)) )) )) where @@ -627,15 +608,14 @@ ppShortClassDecl doc_map summary decl@(HsClassDecl loc ty fds decls) = hdr | not summary = linkTarget c +++ ppClassHdr ty fds | otherwise = ppClassHdr ty fds -ppHsClassDecl doc_map summary decl@(HsClassDecl loc ty fds decls) +ppHsClassDecl summary decl@(HsClassDecl loc ty fds decls doc) | summary || (isNothing doc && all decl_has_no_doc kept_decls) - = ppShortClassDecl doc_map summary decl + = ppShortClassDecl summary decl | otherwise = td << vanillaTable << (header </> classdoc </> body) where - doc = lookupFM doc_map c Just c = declMainBinder decl header @@ -654,14 +634,56 @@ ppHsClassDecl doc_map summary decl@(HsClassDecl loc ty fds decls) | otherwise = td << table ! [width "100%", cellpadding 0, cellspacing 8] << ( meth_hdr </> - aboves (map (doDecl doc_map False) kept_decls) + aboves (map (doDecl False) kept_decls) ) kept_decls = filter keepDecl decls - decl_has_no_doc decl - | Just b <- declMainBinder decl = isNothing (lookupFM doc_map b) - | otherwise = True + decl_has_no_doc decl = isNothing (declDoc decl) + +-- ----------------------------------------------------------------------------- +-- Type signatures + +ppFunSig summary nm ty doc + | summary || no_arg_docs ty = + declWithDoc summary doc (ppTypeSig summary nm ty) + + | otherwise = + td << vanillaTable << ( + declBox (ppHsBinder False nm) </> + (tda [theclass "body"] << narrowTable << ( + (if (isJust doc) + then ndocBox (markup htmlMarkup (fromJust doc)) + else Html.emptyTable) </> + do_args True ty + )) + ) + where + no_arg_docs (HsForAllType _ _ ty) = no_arg_docs ty + no_arg_docs (HsTyFun (HsTyDoc _ _) _) = False + no_arg_docs (HsTyFun _ r) = no_arg_docs r + no_arg_docs (HsTyDoc _ _) = False + no_arg_docs _ = True + + do_args :: Bool -> HsType -> HtmlTable + do_args first (HsForAllType maybe_tvs ctxt ty) + = declBox (leader first <+> ppHsForAll maybe_tvs ctxt) </> + do_args False ty + do_args first (HsTyFun (HsTyDoc ty doc) r) + = (declBox (leader first <+> ppHsBType ty) <-> + rdocBox (markup htmlMarkup doc)) </> + do_args False r + do_args first (HsTyFun ty r) + = (declBox (leader first <+> ppHsBType ty) <-> + rdocBox noHtml) </> + do_args False r + do_args first (HsTyDoc ty doc) + = (declBox (leader first <+> ppHsBType ty) <-> + rdocBox (markup htmlMarkup doc)) + do_args first _ = declBox (leader first <+> ppHsBType ty) + + leader True = toHtml "::" + leader False = toHtml "->" -- ----------------------------------------------------------------------------- -- Types and contexts @@ -671,15 +693,19 @@ ppHsContext [] = empty ppHsContext context = parenList (map (\ (a,b) -> ppHsQName a <+> hsep (map ppHsAType b)) context) +ppHsForAll Nothing context = + hsep [ ppHsContext context, toHtml "=>" ] +ppHsForAll (Just tvs) [] = + hsep (keyword "forall" : map ppHsName tvs ++ [toHtml "."]) +ppHsForAll (Just tvs) context = + hsep (keyword "forall" : map ppHsName tvs ++ + [toHtml ".", ppHsContext context, toHtml "=>"]) + ppHsType :: HsType -> Html -ppHsType (HsForAllType Nothing context htype) = - hsep [ ppHsContext context, toHtml "=>", ppHsType htype] -ppHsType (HsForAllType (Just tvs) [] htype) = - hsep (keyword "forall" : map ppHsName tvs ++ toHtml "." : [ppHsType htype]) -ppHsType (HsForAllType (Just tvs) context htype) = - hsep (keyword "forall" : map ppHsName tvs ++ toHtml "." : - ppHsContext context : toHtml "=>" : [ppHsType htype]) +ppHsType (HsForAllType maybe_tvs context htype) = + ppHsForAll maybe_tvs context <+> ppHsType htype ppHsType (HsTyFun a b) = hsep [ppHsBType a, toHtml "->", ppHsType b] +ppHsType (HsTyDoc ty doc) = ppHsBType ty ppHsType t = ppHsBType t ppHsBType (HsTyApp (HsTyCon (Qual (Module "Prelude") (HsTyClsName (HsSpecial "[]")))) b ) @@ -751,7 +777,7 @@ htmlMarkup = Markup { markupEmpty = toHtml "", markupString = toHtml, markupAppend = (+++), - markupIdentifier = ppHsQName, + markupIdentifier = ppHsQName . head, markupModule = ppHsModule, markupEmphasis = emphasize . toHtml, markupMonospaced = tt . toHtml, @@ -800,10 +826,26 @@ ubxparens p = toHtml "(#" +++ p +++ toHtml "#)" text = strAttr "TEXT" +-- a box for displaying code declBox :: Html -> HtmlTable declBox html = tda [theclass "decl"] << html +-- a box for displaying documentation, +-- indented and with a little padding at the top docBox :: Html -> HtmlTable docBox html = tda [theclass "doc"] << html +-- a box for displaying documentation, not indented. +ndocBox :: Html -> HtmlTable +ndocBox html = tda [theclass "ndoc"] << html + +-- a box for displaying documentation, padded on the left a little +rdocBox :: Html -> HtmlTable +rdocBox html = tda [theclass "rdoc"] << html + +-- a box for the buttons at the top of the page +topButBox html = tda [theclass "topbut"] << html + vanillaTable = table ! [width "100%", cellpadding 0, cellspacing 0, border 0] + +narrowTable = table ! [cellpadding 0, cellspacing 0, border 0] diff --git a/src/HaddockParse.y b/src/HaddockParse.y index 789f0d94..37ceff4f 100644 --- a/src/HaddockParse.y +++ b/src/HaddockParse.y @@ -2,7 +2,9 @@ module HaddockParse (parseParas, parseString) where import HaddockLex -import HaddockTypes +import HsSyn +import HsLexer hiding (Token) +import HsParseMonad } %tokentype { Token } @@ -26,48 +28,48 @@ import HaddockTypes %% -doc :: { ParsedDoc } +doc :: { Doc } : apara PARA doc { docAppend $1 $3 } | PARA doc { $2 } | apara { $1 } | {- empty -} { DocEmpty } -apara :: { ParsedDoc } +apara :: { Doc } : ulpara { DocUnorderedList [$1] } | olpara { DocOrderedList [$1] } | para { $1 } -ulpara :: { ParsedDoc } +ulpara :: { Doc } : '*' para { $2 } -olpara :: { ParsedDoc } +olpara :: { Doc } : '(n)' para { $2 } -para :: { ParsedDoc } +para :: { Doc } : seq { docParagraph $1 } | codepara { DocCodeBlock $1 } -codepara :: { ParsedDoc } +codepara :: { Doc } : '>' seq codepara { docAppend $2 $3 } | '>' seq { $2 } -seq :: { ParsedDoc } +seq :: { Doc } : elem seq { docAppend $1 $2 } | elem { $1 } -elem :: { ParsedDoc } +elem :: { Doc } : elem1 { $1 } | '@' seq1 '@' { DocMonospaced $2 } -seq1 :: { ParsedDoc } +seq1 :: { Doc } : elem1 seq1 { docAppend $1 $2 } | elem1 { $1 } -elem1 :: { ParsedDoc } +elem1 :: { Doc } : STRING { DocString $1 } | '/' STRING '/' { DocEmphasis (DocString $2) } | URL { DocURL $1 } - | squo STRING squo { DocIdentifier $2 } + | squo STRING squo { DocIdentifier (strToHsQNames $2) } | DQUO STRING DQUO { DocModule $2 } squo :: { () } @@ -86,4 +88,29 @@ instance Monad (Either String) where Left l >>= _ = Left l Right r >>= k = k r fail msg = Left msg + +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 -> [] } diff --git a/src/HaddockRename.hs b/src/HaddockRename.hs index 59d71bd5..02085e2e 100644 --- a/src/HaddockRename.hs +++ b/src/HaddockRename.hs @@ -10,7 +10,7 @@ module HaddockRename ( renameExportList, renameDecl, renameExportItems, - renameDoc, resolveDoc, + renameDoc, ) where import HaddockTypes @@ -64,37 +64,47 @@ renameExportList spec = mapM renameExport spec renameExport (HsEVar x) = lookupRn HsEVar x renameExport (HsEAbs x) = lookupRn HsEAbs x renameExport (HsEThingAll x) = lookupRn HsEThingAll x - renameExport (HsEThingWith x cs) - = do cs' <- mapM (lookupRn id) cs - lookupRn (\x' -> HsEThingWith x' cs') x + renameExport (HsEThingWith x cs) = do + cs' <- mapM (lookupRn id) cs + lookupRn (\x' -> HsEThingWith x' cs') x renameExport (HsEModuleContents m) = return (HsEModuleContents m) - renameExport (HsEGroup lev str) = return (HsEGroup lev str) - renameExport (HsEDoc str) = return (HsEDoc str) + renameExport (HsEGroup lev doc) = do + doc <- renameDoc doc + return (HsEGroup lev doc) + renameExport (HsEDoc doc) = do + doc <- renameDoc doc + return (HsEDoc doc) renameExport (HsEDocNamed str) = return (HsEDocNamed str) renameDecl :: HsDecl -> RnM HsDecl renameDecl decl = case decl of - HsTypeDecl loc t args ty -> do + HsTypeDecl loc t args ty doc -> do ty <- renameType ty - return (HsTypeDecl loc t args ty) - HsDataDecl loc ctx t args cons drv -> do + doc <- renameMaybeDoc doc + return (HsTypeDecl loc t args ty doc) + HsDataDecl loc ctx t args cons drv doc -> do cons <- mapM renameConDecl cons - return (HsDataDecl loc ctx t args cons drv) - HsNewTypeDecl loc ctx t args con drv -> do + doc <- renameMaybeDoc doc + return (HsDataDecl loc ctx t args cons drv doc) + HsNewTypeDecl loc ctx t args con drv doc -> do con <- renameConDecl con - return (HsNewTypeDecl loc ctx t args con drv) - HsClassDecl loc qt fds decls -> do + doc <- renameMaybeDoc doc + return (HsNewTypeDecl loc ctx t args con drv doc) + HsClassDecl loc qt fds decls doc -> do qt <- renameClassHead qt decls <- mapM renameDecl decls - return (HsClassDecl loc qt fds decls) - HsTypeSig loc fs qt -> do + doc <- renameMaybeDoc doc + return (HsClassDecl loc qt fds decls doc) + HsTypeSig loc fs qt doc -> do qt <- renameType qt - return (HsTypeSig loc fs qt) - HsForeignImport loc cc safe ent n ty -> do + doc <- renameMaybeDoc doc + return (HsTypeSig loc fs qt doc) + HsForeignImport loc cc safe ent n ty doc -> do ty <- renameType ty - return (HsForeignImport loc cc safe ent n ty) + doc <- renameMaybeDoc doc + return (HsForeignImport loc cc safe ent n ty doc) _ -> return decl @@ -104,15 +114,18 @@ renameClassHead (HsForAllType tvs ctx ty) = do renameClassHead ty = do return ty -renameConDecl (HsConDecl loc nm tvs ctxt tys maybe_doc) = do +renameConDecl (HsConDecl loc nm tvs ctxt tys doc) = do tys <- mapM renameBangTy tys - return (HsConDecl loc nm tvs ctxt tys maybe_doc) -renameConDecl (HsRecDecl loc nm tvs ctxt fields maybe_doc) = do + doc <- renameMaybeDoc doc + return (HsConDecl loc nm tvs ctxt tys doc) +renameConDecl (HsRecDecl loc nm tvs ctxt fields doc) = do fields <- mapM renameField fields - return (HsRecDecl loc nm tvs ctxt fields maybe_doc) + doc <- renameMaybeDoc doc + return (HsRecDecl loc nm tvs ctxt fields doc) renameField (HsFieldDecl ns ty doc) = do ty <- renameBangTy ty + doc <- renameMaybeDoc doc return (HsFieldDecl ns ty doc) renameBangTy (HsBangedTy ty) = HsBangedTy `liftM` renameType ty @@ -141,19 +154,23 @@ renameType (HsTyVar nm) = return (HsTyVar nm) renameType (HsTyCon nm) = lookupRn HsTyCon nm +renameType (HsTyDoc ty doc) = do + ty <- renameType ty + doc <- renameDoc doc + return (HsTyDoc ty doc) -- ----------------------------------------------------------------------------- -- Renaming documentation -- Renaming documentation is done by "marking it up" from ordinary Doc -- into (Rn Doc), which can then be renamed with runRn. -markupRename :: DocMarkup HsQName (RnM Doc) +markupRename :: DocMarkup [HsQName] (RnM Doc) markupRename = Markup { markupEmpty = return DocEmpty, markupString = return . DocString, markupParagraph = liftM DocParagraph, markupAppend = liftM2 DocAppend, - markupIdentifier = lookupRn DocIdentifier, + markupIdentifier = lookupForDoc, markupModule = return . DocModule, markupEmphasis = liftM DocEmphasis, markupMonospaced = liftM DocMonospaced, @@ -165,31 +182,32 @@ markupRename = Markup { renameDoc = markup markupRename -markupResolveDoc :: DocMarkup String (GenRnM String Doc) -markupResolveDoc = Markup { - markupEmpty = return DocEmpty, - markupString = return . DocString, - markupParagraph = liftM DocParagraph, - markupAppend = liftM2 DocAppend, - markupIdentifier = lookupIdString, - markupModule = return . DocModule, - markupEmphasis = liftM DocEmphasis, - markupMonospaced = liftM DocMonospaced, - markupUnorderedList = liftM DocUnorderedList . sequence, - markupOrderedList = liftM DocOrderedList . sequence, - markupCodeBlock = liftM DocCodeBlock, - markupURL = return . DocURL - } - -resolveDoc = markup markupResolveDoc +renameMaybeDoc Nothing = return Nothing +renameMaybeDoc (Just doc) = Just `liftM` renameDoc doc -lookupIdString :: String -> GenRnM String Doc -lookupIdString str = do - fn <- getLookupRn - case fn str of - Nothing -> return (DocString str) - Just n -> return (DocIdentifier n) +-- --------------------------------------------------------------------------- +-- Looking up names in documentation +lookupForDoc :: [HsQName] -> RnM Doc +lookupForDoc qns = do + lkp <- getLookupRn + case [ n | Just n <- map lkp qns ] of + ns@(_:_) -> return (DocIdentifier ns) + [] -> -- if we were given a qualified name, but there's nothing + -- matching that name in scope, then just assume its existence + -- (this means you can use qualified names in doc strings wihout + -- worrying about whether the entity is in scope). + let quals = filter isQualified qns in + if (not (null quals)) then + return (DocIdentifier quals) + else + -- no qualified names: just replace this name with its + -- string representation. + return (DocString (show (head qns))) + where + isQualified (Qual m i) = True + isQualified _ = False + -- ----------------------------------------------------------------------------- renameExportItems items = mapM rn items diff --git a/src/HaddockTypes.hs b/src/HaddockTypes.hs index 5af102d4..9c957dd5 100644 --- a/src/HaddockTypes.hs +++ b/src/HaddockTypes.hs @@ -6,20 +6,14 @@ module HaddockTypes ( -- * Module interfaces - NameEnv, Interface(..), ModuleInfo(..), ExportItem(..), ModuleMap, + NameEnv, Interface(..), ExportItem(..), ModuleMap, DocOption(..), - -- * User documentation strings - DocString, GenDoc(..), Doc, ParsedDoc, DocMarkup(..), - markup, mapIdent, - docAppend, docParagraph, ) where import FiniteMap import HsSyn -import Char (isSpace) - -- --------------------------------------------------------------------------- -- Describing a module interface @@ -45,11 +39,6 @@ data Interface -- restricted to only those bits exported. -- the map key is the "main name" of the decl. - iface_name_docs :: FiniteMap HsName Doc, - -- ^ maps names exported by this module to documentation. - -- Includes not just "main names" but names of constructors, - -- record fields, etc. - iface_info :: Maybe ModuleInfo, -- ^ information from the module header @@ -60,11 +49,6 @@ data Interface -- ^ module-wide doc options } -data ModuleInfo = ModuleInfo - { portability :: String, - stability :: String, - maintainer :: String } - data DocOption = OptHide | OptPrune | OptIgnoreExports deriving (Eq) @@ -72,7 +56,7 @@ type DocString = String data ExportItem = ExportDecl - HsDecl -- a declaration + HsDecl -- a declaration (with doc annotations) | ExportGroup -- a section heading Int -- section level (1, 2, 3, ... ) @@ -87,104 +71,3 @@ data ExportItem type ModuleMap = FiniteMap Module Interface --- ----------------------------------------------------------------------------- --- Doc strings and formatting - -data GenDoc id - = DocEmpty - | DocAppend (GenDoc id) (GenDoc id) - | DocString String - | DocParagraph (GenDoc id) - | DocIdentifier id - | DocModule String - | DocEmphasis (GenDoc id) - | DocMonospaced (GenDoc id) - | DocUnorderedList [GenDoc id] - | DocOrderedList [GenDoc id] - | DocCodeBlock (GenDoc id) - | DocURL String - -type Doc = GenDoc HsQName -type ParsedDoc = GenDoc String - --- | DocMarkup is a set of instructions for marking up documentation. --- In fact, it's really just a mapping from 'GenDoc' to some other --- type [a], where [a] is usually the type of the output (HTML, say). - -data DocMarkup id a = Markup { - markupEmpty :: a, - markupString :: String -> a, - markupParagraph :: a -> a, - markupAppend :: a -> a -> a, - markupIdentifier :: id -> a, - markupModule :: String -> a, - markupEmphasis :: a -> a, - markupMonospaced :: a -> a, - markupUnorderedList :: [a] -> a, - markupOrderedList :: [a] -> a, - markupCodeBlock :: a -> a, - markupURL :: String -> a - } - -markup :: DocMarkup id a -> GenDoc id -> a -markup m DocEmpty = markupEmpty m -markup m (DocAppend d1 d2) = markupAppend m (markup m d1) (markup m d2) -markup m (DocString s) = markupString m s -markup m (DocParagraph d) = markupParagraph m (markup m d) -markup m (DocIdentifier i) = markupIdentifier m i -markup m (DocModule mod) = markupModule m mod -markup m (DocEmphasis d) = markupEmphasis m (markup m d) -markup m (DocMonospaced d) = markupMonospaced m (markup m d) -markup m (DocUnorderedList ds) = markupUnorderedList m (map (markup m) ds) -markup m (DocOrderedList ds) = markupOrderedList m (map (markup m) ds) -markup m (DocCodeBlock d) = markupCodeBlock m (markup m d) -markup m (DocURL url) = markupURL m url - --- | Since marking up is just a matter of mapping 'Doc' into some --- other type, we can \'rename\' documentation by marking up 'Doc' into --- the same thing, modifying only the identifiers embedded in it. -mapIdent f = Markup { - markupEmpty = DocEmpty, - markupString = DocString, - markupParagraph = DocParagraph, - markupAppend = DocAppend, - markupIdentifier = f, - markupModule = DocModule, - markupEmphasis = DocEmphasis, - markupMonospaced = DocMonospaced, - markupUnorderedList = DocUnorderedList, - markupOrderedList = DocOrderedList, - markupCodeBlock = DocCodeBlock, - markupURL = DocURL - } - --- ----------------------------------------------------------------------------- --- ** Smart constructors - --- used to make parsing easier; we group the list items later -docAppend (DocUnorderedList ds1) (DocUnorderedList ds2) - = DocUnorderedList (ds1++ds2) -docAppend (DocUnorderedList ds1) (DocAppend (DocUnorderedList ds2) d) - = DocAppend (DocUnorderedList (ds1++ds2)) d -docAppend (DocOrderedList ds1) (DocOrderedList ds2) - = DocOrderedList (ds1++ds2) -docAppend (DocOrderedList ds1) (DocAppend (DocOrderedList ds2) d) - = DocAppend (DocOrderedList (ds1++ds2)) d -docAppend DocEmpty d = d -docAppend d DocEmpty = d -docAppend d1 d2 - = DocAppend d1 d2 - --- again to make parsing easier - we spot a paragraph whose only item --- is a DocMonospaced and make it into a DocCodeBlock -docParagraph (DocMonospaced p) - = DocCodeBlock p -docParagraph (DocAppend (DocString s1) (DocMonospaced p)) - | all isSpace s1 - = DocCodeBlock p -docParagraph (DocAppend (DocString s1) - (DocAppend (DocMonospaced p) (DocString s2))) - | all isSpace s1 && all isSpace s2 - = DocCodeBlock p -docParagraph p - = DocParagraph p diff --git a/src/HaddockUtil.hs b/src/HaddockUtil.hs index ef209f98..58033edc 100644 --- a/src/HaddockUtil.hs +++ b/src/HaddockUtil.hs @@ -9,7 +9,7 @@ module HaddockUtil ( -- * Misc utilities nameOfQName, collectNames, declBinders, declMainBinder, splitTyConApp, - restrictTo, + restrictTo, declDoc, parseModuleHeader, -- * Filename utilities basename, dirname, splitFilename3, @@ -25,6 +25,7 @@ import HsSyn import List ( intersect ) import IO ( hPutStr, stderr ) import System +import RegexString -- ----------------------------------------------------------------------------- -- Some Utilities @@ -38,25 +39,25 @@ collectNames ds = concat (map declBinders ds) declMainBinder :: HsDecl -> Maybe HsName declMainBinder d = case d of - HsTypeDecl _ n _ _ -> Just n - HsDataDecl _ _ n _ cons _ -> Just n - HsNewTypeDecl _ _ n _ _ _ -> Just n - HsClassDecl _ qt _ decls -> Just (exQtNm qt) - HsTypeSig _ [n] _ -> Just n - HsTypeSig _ ns _ -> error "declMainBinder" - HsForeignImport _ _ _ _ n _ -> Just n - _ -> Nothing + HsTypeDecl _ n _ _ _ -> Just n + HsDataDecl _ _ n _ cons _ _ -> Just n + HsNewTypeDecl _ _ n _ _ _ _ -> Just n + HsClassDecl _ qt _ decls _ -> Just (exQtNm qt) + HsTypeSig _ [n] _ _ -> Just n + HsTypeSig _ ns _ _ -> error "declMainBinder" + HsForeignImport _ _ _ _ n _ _ -> Just n + _ -> Nothing declBinders :: HsDecl -> [HsName] declBinders d = case d of - HsTypeDecl _ n _ _ -> [n] - HsDataDecl _ _ n _ cons _ -> n : concat (map conDeclBinders cons) - HsNewTypeDecl _ _ n _ con _ -> n : conDeclBinders con - HsClassDecl _ qt _ decls -> exQtNm qt : collectNames decls - HsTypeSig _ ns _ -> ns - HsForeignImport _ _ _ _ n _ -> [n] - _ -> [] + HsTypeDecl _ n _ _ _ -> [n] + HsDataDecl _ _ n _ cons _ _ -> n : concat (map conDeclBinders cons) + HsNewTypeDecl _ _ n _ con _ _ -> n : conDeclBinders con + HsClassDecl _ qt _ decls _ -> exQtNm qt : collectNames decls + HsTypeSig _ ns _ _ -> ns + HsForeignImport _ _ _ _ n _ _ -> [n] + _ -> [] conDeclBinders (HsConDecl _ n _ _ _ _) = [n] conDeclBinders (HsRecDecl _ n _ _ fields _) = @@ -67,7 +68,7 @@ fieldDeclBinders (HsFieldDecl ns _ _) = ns exQtNm (HsForAllType _ _ t) = nameOfQName (fst (splitTyConApp t)) exQtNm t = nameOfQName (fst (splitTyConApp t)) -splitTyConApp :: HsType -> (HsQName,[HsType]) +splitTyConApp :: HsType -> (HsQName, [HsType]) splitTyConApp t = split t [] where split :: HsType -> [HsType] -> (HsQName,[HsType]) @@ -80,12 +81,12 @@ splitTyConApp t = split t [] restrictTo :: [HsName] -> HsDecl -> HsDecl restrictTo names decl = case decl of - HsDataDecl loc ctxt n xs cons drv -> - HsDataDecl loc ctxt n xs (restrictCons names cons) drv - HsNewTypeDecl loc ctxt n xs con drv -> - HsDataDecl loc ctxt n xs (restrictCons names [con]) drv - HsClassDecl loc qt fds decls -> - HsClassDecl loc qt fds (restrictDecls names decls) + HsDataDecl loc ctxt n xs cons drv doc -> + HsDataDecl loc ctxt n xs (restrictCons names cons) drv doc + HsNewTypeDecl loc ctxt n xs con drv doc -> + HsDataDecl loc ctxt n xs (restrictCons names [con]) drv doc + HsClassDecl loc qt fds decls doc -> + HsClassDecl loc qt fds (restrictDecls names decls) doc _ -> decl restrictCons :: [HsName] -> [HsConDecl] -> [HsConDecl] @@ -100,6 +101,52 @@ restrictDecls names decls = filter keep decls -- ToDo: not really correct -- ----------------------------------------------------------------------------- +-- Extract documentation from a declaration + +declDoc (HsTypeDecl _ _ _ _ d) = d +declDoc (HsDataDecl _ _ _ _ _ _ d) = d +declDoc (HsNewTypeDecl _ _ _ _ _ _ d) = d +declDoc (HsClassDecl _ _ _ _ d) = d +declDoc (HsTypeSig _ _ _ d) = d +declDoc (HsForeignImport _ _ _ _ _ _ d) = d +declDoc _ = Nothing + +-- ----------------------------------------------------------------------------- +-- 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 + +-- ----------------------------------------------------------------------------- -- Filename mangling functions stolen from GHC's main/DriverUtil.lhs. type Suffix = String @@ -159,3 +206,4 @@ mapSnd f ((x,y):xs) = (x,f y) : mapSnd f xs mapMaybeM :: Monad m => (a -> m b) -> Maybe a -> m (Maybe b) mapMaybeM f Nothing = return Nothing mapMaybeM f (Just a) = f a >>= return . Just + diff --git a/src/HsLexer.lhs b/src/HsLexer.lhs index 505e07f8..c6026b67 100644 --- a/src/HsLexer.lhs +++ b/src/HsLexer.lhs @@ -1,5 +1,5 @@ ----------------------------------------------------------------------------- --- $Id: HsLexer.lhs,v 1.8 2002/05/09 12:45:19 simonmar Exp $ +-- $Id: HsLexer.lhs,v 1.9 2002/05/15 13:03:02 simonmar Exp $ -- -- (c) The GHC Team, 1997-2000 -- @@ -17,7 +17,7 @@ module HsLexer (Token(..), lexer, parseError,isSymbol) where import HsParseMonad import HsParseUtils -import HsSyn(SrcLoc(..)) +import HsSyn import Numeric ( readHex, readOct ) import Char @@ -64,11 +64,11 @@ data Token -- Documentation annotations - | DocCommentNext String -- something beginning '-- |' - | DocCommentPrev String -- something beginning '-- ^' + | DocCommentNext String -- something beginning '-- |' + | DocCommentPrev String -- something beginning '-- ^' | DocCommentNamed String -- something beginning '-- $' - | DocSection Int String -- a section heading - | DocOptions String + | DocSection Int String -- a section heading + | DocOptions String -- attributes '-- #' -- Reserved operators @@ -280,10 +280,9 @@ lexToken cont s loc y x = -- trace ("lexer: y="++show y++" x="++show x++"\n") $ case s of -- First the doc comments - '-':'-':' ':s -> do_doc s docComment - - '{':'-':' ':s -> do_doc s nestedDocComment - '{':'-':s -> do_doc s nestedDocComment + '-':'-':' ':s -> do_doc s False + '{':'-':' ':s -> do_doc s True + '{':'-':s -> do_doc s True -- Next the special symbols '(':'#':s -> forward 2 LeftUT s @@ -346,16 +345,21 @@ lexToken cont s loc y x = where forward n t s = cont t s loc y (x+n) - do_doc ('|':s) f = f DocCommentNext cont s loc y x - do_doc ('/':s) f = f DocCommentNext cont s loc y x - do_doc ('^':s) f = f DocCommentPrev cont s loc y x - do_doc ('$':s) f = f DocCommentNamed cont s loc y x - do_doc ('#':s) f = f DocOptions cont s loc y x - do_doc ('*':s) f = section 1 s + -- this is all terribly ugly, sorry :( + do_doc ('|':s) nested = multi nested DocCommentNext cont s loc y x + do_doc ('/':s) nested = multi nested DocCommentNext cont s loc y x + do_doc ('^':s) nested = multi nested DocCommentPrev cont s loc y x + do_doc ('$':s) nested = multi nested DocCommentNamed cont s loc y x + do_doc ('#':s) nested = multi nested DocOptions cont s loc y x + do_doc ('*':s) nested = section 1 s where section n ('*':s) = section (n+1) s - section n s = f (DocSection n) cont s loc y x + section n s + | nested = nestedDocComment (DocSection n) cont s loc y x + | otherwise = oneLineDocComment (DocSection n) cont s loc y x do_doc _ _ = error "Internal error: HsLexer.do_doc" +multi True = nestedDocComment +multi False = multiLineDocComment afterNum cont i ('#':s) loc y x = cont (PrimInt i) s loc y (x+1) afterNum cont i s loc y x = cont (IntTok i) s loc y x @@ -593,10 +597,13 @@ nestedDocComment f cont s loc y x = go f cont "" y x s c:s -> go f cont (c:acc) y (x+1) s [] -> error "Internal error: nestedComment" +oneLineDocComment f cont s loc y x + = cont (f line) rest loc y x -- continue with the newline char + where (line, rest) = break (== '\n') s -docComment f cont s loc y x - = let (s', comment, y') = slurpExtraCommentLines s [] y in - cont (f comment) s' loc y' x -- continue with the newline char +multiLineDocComment f cont s loc y x + = cont (f comment) s' loc y' x -- continue with the newline char + where (s', comment, y') = slurpExtraCommentLines s [] y slurpExtraCommentLines s lines y = case rest of diff --git a/src/HsParser.ly b/src/HsParser.ly index b2d4eea6..9b47f117 100644 --- a/src/HsParser.ly +++ b/src/HsParser.ly @@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -$Id: HsParser.ly,v 1.10 2002/05/09 12:43:06 simonmar Exp $ +$Id: HsParser.ly,v 1.11 2002/05/15 13:03:02 simonmar Exp $ -(c) Simon Marlow, Sven Panne 1997-2000 +(c) Simon Marlow, Sven Panne 1997-2002 Haskell grammar. ----------------------------------------------------------------------------- @@ -21,14 +21,10 @@ ToDo: Differentiate between record updates and labeled construction. > import HsParseMonad > import HsLexer > import HsParseUtils -> -> #ifdef __HUGS__ -> {- -> #endif -> import GlaExts -> #ifdef __HUGS__ -> -} -> #endif +> import HaddockLex hiding (Token) +> import HaddockParse +> import HaddockUtil ( parseModuleHeader ) +> import Char ( isSpace ) > } ----------------------------------------------------------------------------- @@ -71,7 +67,7 @@ Docs > DOCNEXT { DocCommentNext $$ } > DOCPREV { DocCommentPrev $$ } > DOCNAMED { DocCommentNamed $$ } -> DOCGROUP { DocSection _ _ } +> DOCSECTION { DocSection _ _ } > DOCOPTIONS { DocOptions $$ } Symbols @@ -153,18 +149,19 @@ Module Header > module :: { HsModule } > : optdoc 'module' modid maybeexports 'where' body -> { HsModule $3 $4 (reverse (fst $6)) (reverse (snd $6)) -> (fst $1) (snd $1) } +> { case $1 of { (opts,info,doc) -> +> HsModule $3 $4 (reverse (fst $6)) (reverse (snd $6)) +> opts info doc } } > | body > { HsModule main_mod Nothing (reverse (fst $1)) (reverse (snd $1)) -> Nothing Nothing } +> Nothing 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) } +> optdoc :: { (Maybe String, Maybe ModuleInfo, Maybe Doc) } +> : moduleheader { (Nothing, fst $1, snd $1) } +> | DOCOPTIONS { (Just $1, Nothing, Nothing) } +> | DOCOPTIONS moduleheader { (Just $1, fst $2, snd $2) } +> | moduleheader DOCOPTIONS { (Just $2, fst $1, snd $1) } +> | {- empty -} { (Nothing, Nothing, Nothing) } > body :: { ([HsImportDecl],[HsDecl]) } > : '{' bodyaux '}' { $2 } @@ -193,14 +190,14 @@ The Export List > exportlist :: { [HsExportSpec] } > : export ',' exportlist { $1 : $3 } > | docgroup exportlist { $1 : $2 } -> | DOCNAMED exportlist { HsEDocNamed $1 : $2 } -> | DOCNEXT exportlist { HsEDoc $1 : $2 } +> | docnamed exportlist { HsEDocNamed (fst $1) : $2 } +> | docnext exportlist { HsEDoc $1 : $2 } > | ',' exportlist { $2 } > | export { [$1] } > | {- empty -} { [] } > docgroup :: { HsExportSpec } -> : DOCGROUP { case $1 of { DocSection i s -> HsEGroup i s } } +> : docsection { case $1 of { (i,s) -> HsEGroup i s } } > export :: { HsExportSpec } > : qvar { HsEVar $1 } @@ -299,19 +296,19 @@ shift/reduce-conflict, so we don't handle this case here, but in bodyaux. > topdecl :: { HsDecl } > : 'type' simpletype srcloc '=' ctype -> { HsTypeDecl $3 (fst $2) (snd $2) $5 } +> { HsTypeDecl $3 (fst $2) (snd $2) $5 Nothing } > | 'data' ctype srcloc constrs deriving -> {% checkDataHeader $2 `thenP` \(cs,c,t) -> -> returnP (HsDataDecl $3 cs c t (reverse $4) $5) } +> {% checkDataHeader $2 `thenP` \(cs,c,t) -> +> returnP (HsDataDecl $3 cs c t (reverse $4) $5 Nothing) } > | 'newtype' ctype srcloc '=' constr deriving -> {% checkDataHeader $2 `thenP` \(cs,c,t) -> -> returnP (HsNewTypeDecl $3 cs c t $5 $6) } +> {% checkDataHeader $2 `thenP` \(cs,c,t) -> +> returnP (HsNewTypeDecl $3 cs c t $5 $6 Nothing) } > | 'class' srcloc ctype fds optcbody -> { HsClassDecl $2 $3 $4 $5} +> { HsClassDecl $2 $3 $4 $5 Nothing} > | 'instance' srcloc ctype optvaldefs -> { HsInstDecl $2 $3 $4 } +> { HsInstDecl $2 $3 $4 } > | 'default' srcloc '(' typelist ')' -> { HsDefaultDecl $2 $4 } +> { HsDefaultDecl $2 $4 } > | 'foreign' fdecl { $2 } > | decl { $1 } @@ -329,21 +326,21 @@ shift/reduce-conflict, so we don't handle this case here, but in bodyaux. > | decl { [$1] } > decl :: { HsDecl } -> : signdecl { $1 } -> | fixdecl { $1 } -> | valdef { $1 } -> | DOCNEXT { HsDocCommentNext $1 } -> | DOCPREV { HsDocCommentPrev $1 } -> | DOCNAMED { HsDocCommentNamed $1 } -> | DOCGROUP { case $1 of { DocSection i s -> -> HsDocGroup i s } } +> : signdecl { $1 } +> | fixdecl { $1 } +> | valdef { $1 } +> | srcloc docnext { HsDocCommentNext $1 $2 } +> | srcloc docprev { HsDocCommentPrev $1 $2 } +> | srcloc docnamed { case $2 of { (n,s) -> +> HsDocCommentNamed $1 n s } } +> | srcloc docsection { case $2 of { (i,s) -> HsDocGroup $1 i s } } > decllist :: { [HsDecl] } > : '{' decls '}' { $2 } > | layout_on decls close { $2 } > signdecl :: { HsDecl } -> : vars srcloc '::' ctype { HsTypeSig $2 (reverse $1) $4 } +> : vars srcloc '::' ctypedoc { HsTypeSig $2 (reverse $1) $4 Nothing } ATTENTION: Dirty Hackery Ahead! If the second alternative of vars is var instead of qvar, we get another shift/reduce-conflict. Consider the @@ -366,9 +363,9 @@ Foreign Declarations > fdecl :: { HsDecl } > fdecl : srcloc 'import' callconv safety fspec -> { case $5 of (spec,nm,ty) -> HsForeignImport $1 $3 $4 spec nm ty } +> { case $5 of (spec,nm,ty) -> HsForeignImport $1 $3 $4 spec nm ty Nothing } > | srcloc 'import' callconv fspec -> { case $4 of (spec,nm,ty) -> HsForeignImport $1 $3 HsFISafe spec nm ty } +> { case $4 of (spec,nm,ty) -> HsForeignImport $1 $3 HsFISafe spec nm ty Nothing } > | srcloc 'export' callconv fspec > { case $4 of (spec,nm,ty) -> HsForeignExport $1 $3 spec nm ty } @@ -383,14 +380,22 @@ Foreign Declarations > | 'threadsafe' { HsFIThreadSafe } > fspec :: { (String, HsName, HsType) } -> : STRING varid '::' ctype { ($1, $2, $4) } -> | varid '::' ctype { ("", $1, $3) } +> : STRING varid '::' ctypedoc { ($1, $2, $4) } +> | varid '::' ctypedoc { ("", $1, $3) } ----------------------------------------------------------------------------- Types +> doctype :: { HsType } +> : tydoc '->' doctype { HsTyFun $1 $3 } +> | tydoc { $1 } + +> tydoc :: { HsType } +> : btype { $1 } +> | btype docprev { HsTyDoc $1 $2 } + > type :: { HsType } -> : btype '->' type { HsTyFun $1 $3 } +> : btype '->' type { HsTyFun $1 $3 } > | btype { $1 } > btype :: { HsType } @@ -429,6 +434,11 @@ C a, or (C1 a, C2 b, ... Cn z) and convert it into a context. Blaach! > | context '=>' type { mkHsForAllType Nothing $1 $3 } > | type { $1 } +> ctypedoc :: { HsType } +> : 'forall' tyvars '.' ctypedoc { mkHsForAllType (Just $2) [] $4 } +> | context '=>' doctype { mkHsForAllType Nothing $1 $3 } +> | doctype { $1 } + > context :: { HsContext } > : btype {% checkContext $1 } @@ -472,14 +482,6 @@ Datatype declarations > : scontype { $1 } > | sbtype conop sbtype { ($2, [$1,$3]) } -> maybe_docprev :: { Maybe String } -> : DOCPREV { Just $1 } -> | {- empty -} { Nothing } - -> maybe_docnext :: { Maybe String } -> : DOCNEXT { Just $1 } -> | {- empty -} { Nothing } - > scontype :: { (HsName, [HsBangType]) } > : btype {% splitTyConApp $1 `thenP` \(c,ts) -> > returnP (toVarHsName c, @@ -927,6 +929,45 @@ Miscellaneous (mostly renamings) > : varid_no_forall { $1 } ----------------------------------------------------------------------------- +Documentation comments + +> docnext :: { Doc } +> : DOCNEXT {% case parseParas (tokenise $1) of { +> Left err -> parseError err; +> Right doc -> returnP doc } } + +> docprev :: { Doc } +> : DOCPREV {% case parseParas (tokenise $1) of { +> Left err -> parseError err; +> Right doc -> returnP doc } } + +> docnamed :: { (String,Doc) } +> : DOCNAMED {% let (name,rest) = break isSpace $1 in +> case parseParas (tokenise rest) of { +> Left err -> parseError err; +> Right doc -> returnP (name,doc) } } + +> docsection :: { (Int,Doc) } +> : DOCSECTION {% case $1 of { DocSection n s -> +> case parseString (tokenise s) of { +> Left err -> parseError err; +> Right doc -> returnP (n, doc) } } } + +> maybe_docprev :: { Maybe Doc } +> : docprev { Just $1 } +> | {- empty -} { Nothing } + +> maybe_docnext :: { Maybe Doc } +> : docnext { Just $1 } +> | {- empty -} { Nothing } + +> moduleheader :: { (Maybe ModuleInfo, Maybe Doc) } +> : DOCNEXT {% let (str, info) = parseModuleHeader $1 in +> case parseParas (tokenise str) of { +> Left err -> parseError err; +> Right doc -> returnP (info, Just doc); } } + +----------------------------------------------------------------------------- > { > happyError = parseError "Parse error" diff --git a/src/HsSyn.lhs b/src/HsSyn.lhs index 069143f9..ecd2b0ce 100644 --- a/src/HsSyn.lhs +++ b/src/HsSyn.lhs @@ -1,5 +1,5 @@ % ----------------------------------------------------------------------------- -% $Id: HsSyn.lhs,v 1.8 2002/05/09 10:35:00 simonmar Exp $ +% $Id: HsSyn.lhs,v 1.9 2002/05/15 13:03:02 simonmar Exp $ % % (c) The GHC Team, 1997-2002 % @@ -10,7 +10,7 @@ \begin{code} module HsSyn ( SrcLoc(..), Module(..), HsQName(..), HsName(..), HsIdentifier(..), - HsModule(..), HsExportSpec(..), + HsModule(..), HsExportSpec(..), ModuleInfo(..), HsImportDecl(..), HsImportSpec(..), HsAssoc(..), HsDecl(..), HsMatch(..), HsConDecl(..), HsFieldDecl(..), HsBangType(..), HsRhs(..), @@ -28,8 +28,13 @@ module HsSyn ( stdcall_name, ccall_name, dotnet_name, unit_tycon_name, fun_tycon_name, list_tycon_name, tuple_tycon_name, unit_tycon, fun_tycon, list_tycon, tuple_tycon, + + GenDoc(..), Doc, DocMarkup(..), + markup, mapIdent, + docAppend, docParagraph, ) where +import Char (isSpace) data SrcLoc = SrcLoc Int Int -- (Line, Indentation) deriving (Eq,Ord,Show) @@ -72,8 +77,15 @@ instance Show HsIdentifier where data HsModule = HsModule Module (Maybe [HsExportSpec]) [HsImportDecl] [HsDecl] - (Maybe String) -- the doc options - (Maybe String) -- the module doc + (Maybe String) -- the doc options + (Maybe ModuleInfo) -- the info (portability etc.) + (Maybe Doc) -- the module doc + deriving Show + +data ModuleInfo = ModuleInfo + { portability :: String, + stability :: String, + maintainer :: String } deriving Show -- Export/Import Specifications @@ -84,8 +96,8 @@ data HsExportSpec | HsEThingAll HsQName -- T(..) | HsEThingWith HsQName [HsQName] -- T(C_1,...,C_n) | HsEModuleContents Module -- module M (not for imports) - | HsEGroup Int String -- a doc section heading - | HsEDoc String -- some documentation + | HsEGroup Int Doc -- a doc section heading + | HsEDoc Doc -- some documentation | HsEDocNamed String -- a reference to named doc deriving (Eq,Show) @@ -120,22 +132,37 @@ data HsCallConv deriving (Eq,Show) data HsDecl - = HsTypeDecl SrcLoc HsName [HsName] HsType - | HsDataDecl SrcLoc HsContext HsName [HsName] [HsConDecl] [HsQName] - | HsInfixDecl SrcLoc HsAssoc Int [HsName] - | HsNewTypeDecl SrcLoc HsContext HsName [HsName] HsConDecl [HsQName] - | HsClassDecl SrcLoc HsType [HsFunDep] [HsDecl] - | HsInstDecl SrcLoc HsType [HsDecl] - | HsDefaultDecl SrcLoc [HsType] - | HsTypeSig SrcLoc [HsName] HsType - | HsFunBind [HsMatch] - | HsPatBind SrcLoc HsPat HsRhs {-where-} [HsDecl] - | HsForeignImport SrcLoc HsCallConv HsFISafety String HsName HsType - | HsForeignExport SrcLoc HsCallConv String HsName HsType - | HsDocCommentNext String -- a documentation annotation - | HsDocCommentPrev String -- a documentation annotation - | HsDocCommentNamed String -- a documentation annotation - | HsDocGroup Int String -- a documentation group + = HsTypeDecl SrcLoc HsName [HsName] HsType (Maybe Doc) + + | HsDataDecl SrcLoc HsContext HsName [HsName] [HsConDecl] [HsQName] + (Maybe Doc) + + | HsInfixDecl SrcLoc HsAssoc Int [HsName] + + | HsNewTypeDecl SrcLoc HsContext HsName [HsName] HsConDecl [HsQName] + (Maybe Doc) + + | HsClassDecl SrcLoc HsType [HsFunDep] [HsDecl] (Maybe Doc) + + | HsInstDecl SrcLoc HsType [HsDecl] + + | HsDefaultDecl SrcLoc [HsType] + + | HsTypeSig SrcLoc [HsName] HsType (Maybe Doc) + + | HsFunBind [HsMatch] + + | HsPatBind SrcLoc HsPat HsRhs {-where-} [HsDecl] + + | HsForeignImport SrcLoc HsCallConv HsFISafety String HsName HsType + (Maybe Doc) + + | HsForeignExport SrcLoc HsCallConv String HsName HsType + + | HsDocCommentNext SrcLoc Doc -- a documentation annotation + | HsDocCommentPrev SrcLoc Doc -- a documentation annotation + | HsDocCommentNamed SrcLoc String Doc -- a documentation annotation + | HsDocGroup SrcLoc Int Doc -- a documentation group deriving (Eq,Show) data HsMatch @@ -143,12 +170,12 @@ data HsMatch deriving (Eq,Show) data HsConDecl - = HsConDecl SrcLoc HsName [HsName] HsContext [HsBangType] (Maybe String) - | HsRecDecl SrcLoc HsName [HsName] HsContext [HsFieldDecl] (Maybe String) + = HsConDecl SrcLoc HsName [HsName] HsContext [HsBangType] (Maybe Doc) + | HsRecDecl SrcLoc HsName [HsName] HsContext [HsFieldDecl] (Maybe Doc) deriving (Eq,Show) data HsFieldDecl - = HsFieldDecl [HsName] HsBangType (Maybe String) + = HsFieldDecl [HsName] HsBangType (Maybe Doc) deriving (Eq,Show) data HsBangType @@ -172,6 +199,7 @@ data HsType | HsTyApp HsType HsType | HsTyVar HsName | HsTyCon HsQName + | HsTyDoc HsType Doc deriving (Eq,Show) type HsFunDep = ([HsName], [HsName]) @@ -317,4 +345,106 @@ unit_tycon = HsTyCon unit_tycon_name fun_tycon = HsTyCon fun_tycon_name list_tycon = HsTyCon list_tycon_name tuple_tycon i = HsTyCon (tuple_tycon_name i) + +-- ----------------------------------------------------------------------------- +-- Doc strings and formatting + +data GenDoc id + = DocEmpty + | DocAppend (GenDoc id) (GenDoc id) + | DocString String + | DocParagraph (GenDoc id) + | DocIdentifier id + | DocModule String + | DocEmphasis (GenDoc id) + | DocMonospaced (GenDoc id) + | DocUnorderedList [GenDoc id] + | DocOrderedList [GenDoc id] + | DocCodeBlock (GenDoc id) + | DocURL String + deriving (Eq, Show) + +type Doc = GenDoc [HsQName] + +-- | DocMarkup is a set of instructions for marking up documentation. +-- In fact, it's really just a mapping from 'GenDoc' to some other +-- type [a], where [a] is usually the type of the output (HTML, say). + +data DocMarkup id a = Markup { + markupEmpty :: a, + markupString :: String -> a, + markupParagraph :: a -> a, + markupAppend :: a -> a -> a, + markupIdentifier :: id -> a, + markupModule :: String -> a, + markupEmphasis :: a -> a, + markupMonospaced :: a -> a, + markupUnorderedList :: [a] -> a, + markupOrderedList :: [a] -> a, + markupCodeBlock :: a -> a, + markupURL :: String -> a + } + +markup :: DocMarkup id a -> GenDoc id -> a +markup m DocEmpty = markupEmpty m +markup m (DocAppend d1 d2) = markupAppend m (markup m d1) (markup m d2) +markup m (DocString s) = markupString m s +markup m (DocParagraph d) = markupParagraph m (markup m d) +markup m (DocIdentifier i) = markupIdentifier m i +markup m (DocModule mod) = markupModule m mod +markup m (DocEmphasis d) = markupEmphasis m (markup m d) +markup m (DocMonospaced d) = markupMonospaced m (markup m d) +markup m (DocUnorderedList ds) = markupUnorderedList m (map (markup m) ds) +markup m (DocOrderedList ds) = markupOrderedList m (map (markup m) ds) +markup m (DocCodeBlock d) = markupCodeBlock m (markup m d) +markup m (DocURL url) = markupURL m url + +-- | Since marking up is just a matter of mapping 'Doc' into some +-- other type, we can \'rename\' documentation by marking up 'Doc' into +-- the same thing, modifying only the identifiers embedded in it. +mapIdent f = Markup { + markupEmpty = DocEmpty, + markupString = DocString, + markupParagraph = DocParagraph, + markupAppend = DocAppend, + markupIdentifier = f, + markupModule = DocModule, + markupEmphasis = DocEmphasis, + markupMonospaced = DocMonospaced, + markupUnorderedList = DocUnorderedList, + markupOrderedList = DocOrderedList, + markupCodeBlock = DocCodeBlock, + markupURL = DocURL + } + +-- ----------------------------------------------------------------------------- +-- ** Smart constructors + +-- used to make parsing easier; we group the list items later +docAppend (DocUnorderedList ds1) (DocUnorderedList ds2) + = DocUnorderedList (ds1++ds2) +docAppend (DocUnorderedList ds1) (DocAppend (DocUnorderedList ds2) d) + = DocAppend (DocUnorderedList (ds1++ds2)) d +docAppend (DocOrderedList ds1) (DocOrderedList ds2) + = DocOrderedList (ds1++ds2) +docAppend (DocOrderedList ds1) (DocAppend (DocOrderedList ds2) d) + = DocAppend (DocOrderedList (ds1++ds2)) d +docAppend DocEmpty d = d +docAppend d DocEmpty = d +docAppend d1 d2 + = DocAppend d1 d2 + +-- again to make parsing easier - we spot a paragraph whose only item +-- is a DocMonospaced and make it into a DocCodeBlock +docParagraph (DocMonospaced p) + = DocCodeBlock p +docParagraph (DocAppend (DocString s1) (DocMonospaced p)) + | all isSpace s1 + = DocCodeBlock p +docParagraph (DocAppend (DocString s1) + (DocAppend (DocMonospaced p) (DocString s2))) + | all isSpace s1 && all isSpace s2 + = DocCodeBlock p +docParagraph p + = DocParagraph p \end{code} 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 ])) -- ----------------------------------------------------------------------------- |