diff options
Diffstat (limited to 'src/HaddockTypes.hs')
-rw-r--r-- | src/HaddockTypes.hs | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/src/HaddockTypes.hs b/src/HaddockTypes.hs new file mode 100644 index 00000000..8def4b34 --- /dev/null +++ b/src/HaddockTypes.hs @@ -0,0 +1,229 @@ +-- +-- Haddock - A Haskell Documentation Tool +-- +-- (c) Simon Marlow 2002 +-- + +module HaddockTypes ( + -- * Module interfaces + NameEnv, Interface(..), ExportItem(..), ModuleMap, + + -- * User documentation strings + DocString, GenDoc(..), Doc, ParsedDoc, DocMarkup(..), + markup, mapIdent, + docAppend, docParagraph, + + -- * Misc utilities + nameOfQName, collectNames, declBinders, declMainBinder, splitTyConApp, + restrictTo, + ) where + +import FiniteMap +import HsSyn + +import List (intersect) +import Char (isSpace) + +-- --------------------------------------------------------------------------- +-- Describing a module interface + +type NameEnv = FiniteMap HsName HsQName + +data Interface + = Interface { + iface_filename :: FilePath, + -- ^ the filename that contains the source code for this module + + iface_env :: NameEnv, + -- ^ environment mapping names to *original* names + + iface_exports :: [ExportItem], + -- ^ the exports used to construct the documentation + + iface_decls :: FiniteMap HsName HsDecl, + -- ^ decls from this module (only) + -- 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_portability :: String, + iface_stability :: String, + iface_maintainer :: String, + -- ^ information from the module header + + iface_doc :: Maybe Doc + -- ^ documentation from the module header + } + +type DocString = String + +data ExportItem + = ExportDecl HsDecl -- a declaration + | ExportGroup Int Doc -- a section heading + +type ModuleMap = FiniteMap Module Interface + +-- ----------------------------------------------------------------------------- +-- Some Utilities + +nameOfQName (Qual _ n) = n +nameOfQName (UnQual n) = n + +collectNames :: [HsDecl] -> [HsName] +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 + +declBinders :: HsDecl -> [HsName] +declBinders d = + case d of + HsTypeDecl _ n _ _ -> [n] + HsDataDecl _ _ n _ cons _ -> n : concat (map conDeclBinders cons) + HsNewTypeDecl _ _ n _ _ _ -> [n] + HsClassDecl _ qt decls -> exQtNm qt : collectNames decls + HsTypeSig _ ns _ -> ns + HsForeignImport _ _ _ _ n _ -> [n] + _ -> [] + +conDeclBinders (HsConDecl _ n _ _) = [n] +conDeclBinders (HsRecDecl _ n fields _) = n : concat (map fieldDeclBinders fields) + +fieldDeclBinders (HsFieldDecl ns _ _) = ns + +exQtNm (HsForAllType _ _ t) = nameOfQName (fst (splitTyConApp t)) +exQtNm t = nameOfQName (fst (splitTyConApp t)) + +splitTyConApp :: HsType -> (HsQName,[HsType]) +splitTyConApp t = split t [] + where + split :: HsType -> [HsType] -> (HsQName,[HsType]) + split (HsTyApp t u) ts = split t (u:ts) + split (HsTyCon t) ts = (t,ts) + split _ _ = error "splitTyConApp" + +-- --------------------------------------------------------------------------- +-- Making abstract declarations + +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 decls -> + HsClassDecl loc qt (restrictDecls names decls) + _ -> decl + +restrictCons :: [HsName] -> [HsConDecl] -> [HsConDecl] +restrictCons names decls = filter keep decls + where keep (HsConDecl _ n _ _) = n `elem` names + keep (HsRecDecl _ n _ _) = n `elem` names + -- ToDo: records not right + +restrictDecls :: [HsName] -> [HsDecl] -> [HsDecl] +restrictDecls names decls = filter keep decls + where keep d = not (null (declBinders d `intersect` names)) + -- ToDo: not really correct + +-- ----------------------------------------------------------------------------- +-- 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) + +type Doc = GenDoc HsQName +type ParsedDoc = GenDoc String + +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 + } + +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 + } + +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) + +-- ----------------------------------------------------------------------------- +-- ** 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 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 |