aboutsummaryrefslogtreecommitdiff
path: root/src/Main.hs
diff options
context:
space:
mode:
authorDavid Waern <unknown>2007-08-29 22:40:23 +0000
committerDavid Waern <unknown>2007-08-29 22:40:23 +0000
commit658e79eddf0ac941d2719ec0a3aea58f42ef1277 (patch)
tree649135576118781ddc77896f81289df5b5699cec /src/Main.hs
parentc9746ad9a53e84c3a46ff8fd77f0fb3656ca7697 (diff)
Major refactoring
Diffstat (limited to 'src/Main.hs')
-rw-r--r--src/Main.hs922
1 files changed, 57 insertions, 865 deletions
diff --git a/src/Main.hs b/src/Main.hs
index 8f3eda4e..c127f773 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -10,73 +10,35 @@
module Main (main) where
-import Haddock.Html
-import Haddock.Hoogle
-import Haddock.Rename
+import Haddock.Packages
+import Haddock.Backends.Html
+import Haddock.Backends.Hoogle
+import Haddock.Interface
import Haddock.Types hiding (NoLink)
-import Haddock.Utils
import Haddock.Version
import Haddock.InterfaceFile
import Haddock.Exception
import Haddock.Options
-import Haddock.Typecheck
-import Haddock.Packages
-import Haddock.Utils.GHC
+import Haddock.GHC
+import Haddock.Utils
import Paths_haddock
-
-import Prelude hiding (catch)
-import Control.Exception
import Control.Monad
-import Control.Monad.Writer
-import Control.Arrow
-import Data.Char
-import Data.IORef
-import Data.Ord
-import Data.List
-import Data.Maybe
-import Data.Typeable
-import Data.Graph hiding (flattenSCC)
+import Control.Exception
+import Control.Exception
import Data.Dynamic
-import Data.Foldable (foldlM)
-import System.Console.GetOpt
-import System.Environment
-import System.Directory
-import System.FilePath
-import System.Cmd
-import System.Exit
-import System.IO
-
+import Data.Maybe
+import Data.IORef
import qualified Data.Map as Map
-import Data.Map (Map)
-
-import Distribution.InstalledPackageInfo
-import Distribution.Simple.Utils
-
+import System.IO
+import System.Exit
+import System.Environment
import GHC
-import Outputable
-import SrcLoc
-import Name
-import Module
-import InstEnv
-import Class
-import TypeRep
-import Var hiding (varName)
-import TyCon
-import PrelNames
+import DynFlags
import Bag
-import HscTypes
import Util (handleDyn)
-import ErrUtils (printBagOfErrors)
-import UniqFM
-
-import FastString
-#define FSLIT(x) (mkFastString# (x#))
-
-import DynFlags hiding (Option)
-import Packages hiding (package)
-import StaticFlags
+import ErrUtils
--------------------------------------------------------------------------------
@@ -140,50 +102,48 @@ main = handleTopExceptions $ do
-- parse command-line flags and handle some of them initially
args <- getArgs
(flags, fileArgs) <- parseHaddockOpts args
- libDir <- handleFlags flags fileArgs
+ libDir <- handleEasyFlags flags fileArgs
-- initialize GHC
restGhcFlags <- tryParseStaticFlags flags
- (session, _) <- startGHC libDir
+ (session, _) <- startGhc libDir
- -- parse and set the ghc flags
+ -- parse and set the GHC flags
dynflags <- parseGhcFlags session restGhcFlags
setSessionDynFlags session dynflags
- -- get the -use-package packages, expose them to GHC,
- -- and try to load their installed HaddockPackages
+ -- get the -use-package packages, load them in GHC,
+ -- and try to get the corresponding installed HaddockPackages
let usePackages = [ pkg | Flag_UsePackage pkg <- flags ]
- packages <- initAndReadPackages session usePackages
+ pkgInfos <- loadPackages session usePackages
+ packages <- getHaddockPackages pkgInfos
-- typecheck argument modules using GHC
modules <- typecheckFiles session fileArgs
- -- update the html references for rendering phase (global variable)
+ -- combine the link envs of the external packages into one
+ let extLinks = combineLinkEnvs packages
+
+ -- create the interfaces -- this is the core part of Haddock
+ let (interfaces, homeLinks, messages) = createInterfaces modules extLinks flags
+ mapM_ putStrLn messages
+
+ -- render the interfaces
updateHTMLXRefs packages
+ render flags interfaces
- -- combine the doc envs of the read packages into one
- let env = combineDocEnvs packages
+ -- last but not least, dump the interface file!
+ dumpInterfaceFile homeLinks flags
- -- TODO: continue to break up the run function into parts
- run flags modules env
+-------------------------------------------------------------------------------
+-- Rendering
+-------------------------------------------------------------------------------
-startGHC :: String -> IO (Session, DynFlags)
-startGHC libDir = do
- session <- newSession (Just libDir)
- flags <- getSessionDynFlags session
- let flags' = dopt_set flags Opt_Haddock
- let flags'' = flags' {
- hscTarget = HscNothing,
- ghcMode = CompManager,
- ghcLink = NoLink
- }
- setSessionDynFlags session flags''
- return (session, flags'')
-
-run :: [Flag] -> [GhcModule] -> Map Name Name -> IO ()
-run flags modules extEnv = do
+-- | Render the interfaces with whatever backend is specified in the flags
+render :: [Flag] -> [HaddockModule] -> IO ()
+render flags interfaces = do
let
title = case [str | Flag_Heading str <- flags] of
[] -> ""
@@ -229,23 +189,9 @@ run flags modules extEnv = do
prologue <- getPrologue flags
- let
- -- run pass 1 on this data
- (modMap, messages) = runWriter (pass1 modules flags)
-
- haddockMods = catMaybes [ Map.lookup (ghcModule m) modMap | m <- modules ]
- homeEnv = buildGlobalDocEnv haddockMods
- env = homeEnv `Map.union` extEnv
- haddockMods' = attachInstances haddockMods
- (haddockMods'', messages') = runWriter $ mapM (renameModule env) haddockMods'
-
- mapM_ putStrLn messages
- mapM_ putStrLn messages'
-
let
- visibleMods = [ m | m <- haddockMods'', OptHide `notElem` (hmod_options m) ]
- packageName = (Just . packageIdString . modulePackageId .
- hmod_mod . head) visibleMods
+ visibleMods = [ m | m <- interfaces, OptHide `notElem` (hmod_options m) ]
+ packageName = (Just . modulePkgStr . hmod_mod . head) visibleMods
when (Flag_GenIndex `elem` flags) $ do
ppHtmlIndex odir title packageName maybe_html_help_format
@@ -269,23 +215,24 @@ run flags modules extEnv = do
maybe_contents_url maybe_index_url
copyHtmlBits odir libdir css_file
- let iface = InterfaceFile {
- ifDocEnv = homeEnv
--- ifModules = map hmod2interface visibleMods
- }
-
- case [str | Flag_DumpInterface str <- flags] of
- [] -> return ()
- fs -> let filename = (last fs) in
- writeInterfaceFile filename iface
-
-------------------------------------------------------------------------------
--- Flags
+-- Misc
-------------------------------------------------------------------------------
-handleFlags flags fileArgs = do
+dumpInterfaceFile :: LinkEnv -> [Flag] -> IO ()
+dumpInterfaceFile homeLinks flags =
+ case [str | Flag_DumpInterface str <- flags] of
+ [] -> return ()
+ fs -> let filename = last fs in writeInterfaceFile filename ifaceFile
+ where
+ ifaceFile = InterfaceFile {
+ ifLinkEnv = homeLinks
+ }
+
+
+handleEasyFlags flags fileArgs = do
usage <- getUsage
when (Flag_Help `elem` flags) (bye usage)
@@ -301,318 +248,12 @@ handleFlags flags fileArgs = do
throwE ("-h cannot be used with --gen-index or --gen-contents")
return ghcLibDir
-
-
--- | Filter out the GHC specific flags and try to parse and set them as static
--- flags. Return a list of flags that couldn't be parsed.
-tryParseStaticFlags flags = do
- let ghcFlags = [ str | Flag_GhcFlag str <- flags ]
- parseStaticFlags ghcFlags
-
-
--- | Try to parse dynamic GHC flags
-parseGhcFlags session ghcFlags = do
- dflags <- getSessionDynFlags session
- foldlM parseFlag dflags (map words ghcFlags)
- where
- -- try to parse a flag as either a dynamic or static GHC flag
- parseFlag dynflags ghcFlag = do
- (dynflags', rest) <- parseDynamicFlags dynflags ghcFlag
- when (rest == ghcFlag) $
- throwE ("Couldn't parse GHC flag: " ++ (unwords ghcFlag))
- return dynflags'
-
-
-byeVersion =
- bye ("Haddock version " ++ projectVersion ++
- ", (c) Simon Marlow 2003; ported to the GHC-API by David Waern 2006\n")
-
-
--------------------------------------------------------------------------------
--- Phase 1
--------------------------------------------------------------------------------
-
-
--- | Produce a map of HaddockModules with information that is close to
--- renderable. What is lacking after this pass are the renamed export items.
-pass1 :: [GhcModule] -> [Flag] -> ErrMsgM ModuleMap
-pass1 modules flags = foldM produceAndInsert Map.empty modules
- where
- produceAndInsert modMap modData = do
- resultMod <- pass1data modData flags modMap
- let key = ghcModule modData
- return (Map.insert key resultMod modMap)
-
-
--- | Massage the data in GhcModule to produce something closer to what
--- we want to render. To do this, we need access to modules before this one
--- in the topological sort, to which we have already done this conversion.
--- That's what's in the ModuleMap.
-pass1data :: GhcModule -> [Flag] -> ModuleMap -> ErrMsgM HaddockModule
-pass1data modData flags modMap = do
-
- let mod = ghcModule modData
-
- opts <- mkDocOpts (ghcMbDocOpts modData) mod
-
- let group = ghcGroup modData
- entities = (nubBy sameName . collectEntities) group
- exports = fmap (reverse . map unLoc) (ghcMbExports modData)
- entityNames_ = entityNames entities
- subNames = allSubNames group
- localNames = entityNames_ ++ subNames
- subMap = mkSubMap group
- expDeclMap = mkDeclMap (ghcExportedNames modData) group
- localDeclMap = mkDeclMap entityNames_ group
- docMap = mkDocMap group
- ignoreExps = Flag_IgnoreAllExports `elem` flags
-
- visibleNames <- mkVisibleNames mod modMap localNames (ghcNamesInScope modData)
- subMap exports opts localDeclMap
-
- exportItems <- mkExportItems modMap mod (ghcExportedNames modData)
- expDeclMap localDeclMap subMap entities
- opts exports ignoreExps docMap
-
- -- prune the export list to just those declarations that have
- -- documentation, if the 'prune' option is on.
- let
- prunedExportItems
- | OptPrune `elem` opts = pruneExportItems exportItems
- | otherwise = exportItems
-
- return HM {
- hmod_mod = mod,
- hmod_orig_filename = ghcFilename modData,
- hmod_info = ghcHaddockModInfo modData,
- hmod_doc = ghcMbDoc modData,
- hmod_rn_doc = Nothing,
- hmod_options = opts,
- hmod_locals = localNames,
- hmod_doc_map = docMap,
- hmod_rn_doc_map = Map.empty,
- hmod_sub_map = subMap,
- hmod_export_items = prunedExportItems,
- hmod_rn_export_items = [],
- hmod_exports = ghcExportedNames modData,
- hmod_visible_exports = visibleNames,
- hmod_exported_decl_map = expDeclMap,
- hmod_instances = ghcInstances modData
- }
- where
- mkDocOpts mbOpts mod = do
- opts <- case mbOpts of
- Just opts -> processOptions opts
- Nothing -> return []
- let opts' = if Flag_HideModule (moduleString mod) `elem` flags
- then OptHide : opts
- else opts
- return opts'
-
-
-sameName (DocEntity _) _ = False
-sameName (DeclEntity _) (DocEntity _) = False
-sameName (DeclEntity a) (DeclEntity b) = a == b
-
-
--- This map includes everything that can be exported separately,
--- that means: top declarations, class methods and record selectors
--- TODO: merge this with mkDeclMap and the extractXXX functions
-mkDocMap :: HsGroup Name -> Map Name (HsDoc Name)
-mkDocMap group = Map.fromList (topDeclDocs ++ classMethDocs ++ recordFieldDocs)
- where
- tyclds = map unLoc (hs_tyclds group)
- classes = filter isClassDecl tyclds
- datadecls = filter isDataDecl tyclds
- constrs = [ con | d <- datadecls, L _ con <- tcdCons d ]
- fields = concat [ fields | RecCon fields <- map con_details constrs]
-
- topDeclDocs = collectDocs (collectEntities group)
- classMethDocs = concatMap (collectDocs . collectClassEntities) classes
-
- recordFieldDocs = [ (unLoc lname, doc) |
- ConDeclField lname _ (Just (L _ doc)) <- fields ]
-
-
---------------------------------------------------------------------------------
--- Source code entities
---------------------------------------------------------------------------------
-
-
-data Entity = DocEntity (DocDecl Name) | DeclEntity Name
-data LEntity = Located Entity
-
-
-sortByLoc = map unLoc . sortBy (comparing getLoc)
-
-
--- | Collect all the entities in a class that can be documented.
--- The entities are sorted by their SrcLoc.
-collectClassEntities tcd = sortByLoc (docs ++ meths ++ sigs)
- where
- docs = [ L l (DocEntity d) | L l d <- tcdDocs tcd ]
- meths =
- let bindings = bagToList (tcdMeths tcd)
- bindingName = unLoc . fun_id
- in [ L l (DeclEntity (bindingName b)) | L l b <- bindings ]
- sigs =
- let sigName = fromJust . sigNameNoLoc
- in [ L l (DeclEntity (sigName sig)) | L l sig <- tcdSigs tcd ]
-
-
--- | Collect all the entities in the source file that can be documented.
--- The entities are sorted by their SrcLoc.
-collectEntities :: HsGroup Name -> [Entity]
-collectEntities group = sortByLoc (docs ++ declarations)
where
- docs = [ L l (DocEntity d) | L l d <- hs_docs group ]
-
- declarations = [ L l (DeclEntity n) | (l, n) <- valds ++ tyclds ++ fords ]
- where
- valds = let ValBindsOut _ sigs = hs_valds group
- -- we just use the sigs here for now.
- -- TODO: collect from the bindings as well
- -- (needed for docs to work for inferred entities)
- in [ (l, fromJust (sigNameNoLoc s)) | L l s <- sigs ]
- tyclds = [ (l, tcdName t) | L l t <- hs_tyclds group ]
- fords = [ (l, forName f) | L l f <- hs_fords group ]
- where
- forName (ForeignImport name _ _) = unLoc name
- forName (ForeignExport name _ _) = unLoc name
-
-
---------------------------------------------------------------------------------
--- Collect docs
---------------------------------------------------------------------------------
-
-
--- | Collect the docs and attach them to the right name
-collectDocs :: [Entity] -> [(Name, HsDoc Name)]
-collectDocs entities = collect Nothing DocEmpty entities
-
-
-collect :: Maybe Entity -> HsDoc Name -> [Entity] -> [(Name, HsDoc Name)]
-collect d doc_so_far [] =
- case d of
- Nothing -> []
- Just d0 -> finishedDoc d0 doc_so_far []
-
-collect d doc_so_far (e:es) =
- case e of
- DocEntity (DocCommentNext str) ->
- case d of
- Nothing -> collect d (docAppend doc_so_far str) es
- Just d0 -> finishedDoc d0 doc_so_far (collect Nothing str es)
-
- DocEntity (DocCommentPrev str) -> collect d (docAppend doc_so_far str) es
-
- _ -> case d of
- Nothing -> collect (Just e) doc_so_far es
- Just d0
- | sameName d0 e -> collect d doc_so_far es
- | otherwise -> finishedDoc d0 doc_so_far (collect (Just e) DocEmpty es)
-
-
-finishedDoc :: Entity -> HsDoc Name -> [(Name, HsDoc Name)] ->
- [(Name, HsDoc Name)]
-finishedDoc d DocEmpty rest = rest
-finishedDoc (DeclEntity name) doc rest = (name, doc) : rest
-finishedDoc _ _ rest = rest
-
-
--------------------------------------------------------------------------------
---
--------------------------------------------------------------------------------
-
-
-allSubNames :: HsGroup Name -> [Name]
-allSubNames group =
- concat [ tail (map unLoc (tyClDeclNames tycld)) | L _ tycld <- hs_tyclds group ]
-
-
-mkSubMap :: HsGroup Name -> Map Name [Name]
-mkSubMap group = Map.fromList [ (name, subs) | L _ tycld <- hs_tyclds group,
- let name:subs = map unLoc (tyClDeclNames tycld) ]
-
-
-mkDeclMap :: [Name] -> HsGroup Name -> Map Name (LHsDecl Name)
-mkDeclMap names group = Map.fromList [ (n,d) | (n,Just d) <- maybeDecls ]
- where
- maybeDecls = [ (name, getDeclFromGroup group name) | name <- names ]
+ byeVersion = bye $
+ "Haddock version " ++ projectVersion ++
+ ", (c) Simon Marlow 2003; ported to the GHC-API by David Waern 2006\n"
-entityNames :: [Entity] -> [Name]
-entityNames entities = [ name | DeclEntity name <- entities ]
-{-
-getValSig :: Name -> HsValBinds Name -> TypeEnv -> Maybe (LSig Name)
-getValSig name (ValBindsOut recsAndBinds _) typEnv = case matchingBinds of
- [bind] -> -- OK we have found a binding that matches. Now look up the
- -- type, even though it may be present in the ValBindsOut
- let tything = lookupTypeEnv typeEnv name
- _ -> Nothing
- where
- binds = snd $ unzip recsAndBinds
- matchingBinds = Bag.filter matchesName binds
- matchesName (L _ bind) = fun_id bind == name
-getValSig _ _ _ = error "getValSig"
--}
-
-
-getDeclFromGroup :: HsGroup Name -> Name -> Maybe (LHsDecl Name)
-getDeclFromGroup group name =
- case catMaybes [ getDeclFromVals (hs_valds group),
- getDeclFromTyCls (hs_tyclds group),
- getDeclFromFors (hs_fords group) ] of
- [decl] -> Just decl
- _ -> Nothing
- where
- getDeclFromVals (ValBindsOut _ lsigs) = case matching of
- [lsig] -> Just (L (getLoc lsig) (SigD (unLoc lsig)))
- _ -> Nothing
- where
- matching = [ lsig | lsig <- lsigs, let Just n = sigName lsig, n == name,
- isNormal (unLoc lsig) ]
- isNormal (TypeSig _ _) = True
- isNormal _ = False
-
- getDeclFromVals _ = error "getDeclFromVals: illegal input"
-
-{- getDeclFromVals (ValBindsOut recsAndbinds _) =
- let binds = snd $ unzip recsAndBinds
- matchingBinds = Bag.filter matchesName binds
- matchesName (L _ bind) = fun_id bind == name
- in case matchingBinds of
- [bind] -> -- OK we have found a binding that matches. Now look up the
- -- type, even though it may be present in the ValBindsOut
-
- _ -> Nothing
- where
- matching = [ lsig | lsig <- lsigs, let Just n = sigName lsig, n == name ]
- getDeclFromVals _ = error "getDeclFromVals: illegal input"
- -}
- getDeclFromTyCls ltycls = case matching of
- [ltycl] -> Just (L (getLoc ltycl) (TyClD (unLoc ltycl)))
- _ -> Nothing
- where
- matching = [ ltycl | ltycl <- ltycls,
- name `elem` map unLoc (tyClDeclNames (unLoc ltycl))]
-
- getDeclFromFors lfors = case matching of
- [for] -> Just (L (getLoc for) (ForD (unLoc for)))
- _ -> Nothing
- where
- matching = [ for | for <- lfors, forName (unLoc for) == name ]
- forName (ForeignExport n _ _) = unLoc n
- forName (ForeignImport n _ _) = unLoc n
-
-
-parseIfaceOption :: String -> (FilePath,FilePath)
-parseIfaceOption s =
- case break (==',') s of
- (fpath,',':file) -> (fpath,file)
- (file, _) -> ("", file)
-
-
updateHTMLXRefs :: [HaddockPackage] -> IO ()
updateHTMLXRefs packages = do
writeIORef html_xrefs_ref (Map.fromList mapping)
@@ -631,452 +272,3 @@ getPrologue flags
Left err -> throwE err
Right doc -> return (Just doc)
_otherwise -> throwE "multiple -p/--prologue options"
-
-
--------------------------------------------------------------------------------
--- Phase 2
--------------------------------------------------------------------------------
-
-
-renameModule :: Map Name Name -> HaddockModule -> ErrMsgM HaddockModule
-renameModule renamingEnv mod =
-
- -- first create the local env, where every name exported by this module
- -- is mapped to itself, and everything else comes from the global renaming
- -- env
- let localEnv = foldl fn renamingEnv (hmod_visible_exports mod)
- where fn env name = Map.insert name (nameSetMod name (hmod_mod mod)) env
-
- docs = Map.toList (hmod_doc_map mod)
- renameMapElem (k,d) = do d' <- renameDoc d; return (k, d')
-
- -- rename names in the exported declarations to point to things that
- -- are closer to, or maybe even exported by, the current module.
- (renamedExportItems, missingNames1)
- = runRnFM localEnv (renameExportItems (hmod_export_items mod))
-
- (rnDocMap, missingNames2)
- = runRnFM localEnv (liftM Map.fromList (mapM renameMapElem docs))
-
- (finalModuleDoc, missingNames3)
- = runRnFM localEnv (renameMaybeDoc (hmod_doc mod))
-
- -- combine the missing names and filter out the built-ins, which would
- -- otherwise allways be missing.
- missingNames = nub $ filter isExternalName
- (missingNames1 ++ missingNames2 ++ missingNames3)
-
- -- filter out certain built in type constructors using their string
- -- representation. TODO: use the Name constants from the GHC API.
- strings = filter (`notElem` ["()", "[]", "(->)"])
- (map (showSDoc . ppr) missingNames)
-
- in do
- -- report things that we couldn't link to. Only do this for non-hidden
- -- modules.
- when (OptHide `notElem` hmod_options mod && not (null strings)) $
- tell ["Warning: " ++ show (ppr (hmod_mod mod) defaultUserStyle) ++
- ": could not find link destinations for:\n"++
- " " ++ concat (map (' ':) strings) ]
-
- return $ mod { hmod_rn_doc = finalModuleDoc,
- hmod_rn_doc_map = rnDocMap,
- hmod_rn_export_items = renamedExportItems }
-
-
--- | Build the list of items that will become the documentation, from the
--- export list. At this point, the list of ExportItems is in terms of
--- original names.
-mkExportItems
- :: ModuleMap
- -> Module -- this module
- -> [Name] -- exported names (orig)
- -> Map Name (LHsDecl Name) -- maps exported names to declarations
- -> Map Name (LHsDecl Name) -- maps local names to declarations
- -> Map Name [Name] -- sub-map for this module
- -> [Entity] -- entities in the current module
- -> [DocOption]
- -> Maybe [IE Name]
- -> Bool -- --ignore-all-exports flag
- -> Map Name (HsDoc Name)
- -> ErrMsgM [ExportItem Name]
-
-mkExportItems mod_map this_mod exported_names exportedDeclMap localDeclMap sub_map entities
- opts maybe_exps ignore_all_exports docMap
- | isNothing maybe_exps || ignore_all_exports || OptIgnoreExports `elem` opts
- = everything_local_exported
- | Just specs <- maybe_exps = do
- exps <- mapM lookupExport specs
- return (concat exps)
- where
- everything_local_exported = -- everything exported
- return (fullContentsOfThisModule this_mod entities localDeclMap docMap)
-
- packageId = modulePackageId this_mod
-
- lookupExport (IEVar x) = declWith x
- lookupExport (IEThingAbs t) = declWith t
- lookupExport (IEThingAll t) = declWith t
- lookupExport (IEThingWith t cs) = declWith t
- lookupExport (IEModuleContents m) = fullContentsOf (mkModule packageId m)
- lookupExport (IEGroup lev doc) = return [ ExportGroup lev "" doc ]
- lookupExport (IEDoc doc) = return [ ExportDoc doc ]
- lookupExport (IEDocNamed str)
- = do r <- findNamedDoc str entities
- case r of
- Nothing -> return []
- Just found -> return [ ExportDoc found ]
-
- declWith :: Name -> ErrMsgM [ ExportItem Name ]
- declWith t
- | (Just decl, maybeDoc) <- findDecl t
- = return [ ExportDecl t (restrictTo subs (extractDecl t mdl decl)) maybeDoc [] ]
- | otherwise
- = return []
- where
- mdl = nameModule t
- subs = filter (`elem` exported_names) all_subs
- all_subs | mdl == this_mod = Map.findWithDefault [] t sub_map
- | otherwise = allSubsOfName mod_map t
-
- fullContentsOf m
- | m == this_mod = return (fullContentsOfThisModule this_mod entities localDeclMap docMap)
- | otherwise =
- case Map.lookup m mod_map of
- Just hmod
- | OptHide `elem` hmod_options hmod
- -> return (hmod_export_items hmod)
- | otherwise -> return [ ExportModule m ]
- Nothing -> return [] -- already emitted a warning in visibleNames
-
- findDecl :: Name -> (Maybe (LHsDecl Name), Maybe (HsDoc Name))
- findDecl n | not (isExternalName n) = error "This shouldn't happen"
- findDecl n
- | m == this_mod = (Map.lookup n exportedDeclMap, Map.lookup n docMap)
- | otherwise =
- case Map.lookup m mod_map of
- Just hmod -> (Map.lookup n (hmod_exported_decl_map hmod),
- Map.lookup n (hmod_doc_map hmod))
- Nothing -> (Nothing, Nothing)
- where
- m = nameModule n
-
-
-fullContentsOfThisModule :: Module -> [Entity] -> Map Name (LHsDecl Name) ->
- Map Name (HsDoc Name) -> [ExportItem Name]
-fullContentsOfThisModule module_ entities declMap docMap
- = catMaybes (map mkExportItem entities)
- where
- mkExportItem (DocEntity (DocGroup lev doc)) = Just (ExportGroup lev "" doc)
- mkExportItem (DeclEntity name) = fmap mkExport (Map.lookup name declMap)
- where mkExport decl = ExportDecl name decl (Map.lookup name docMap) []
- mkExportItem _ = Nothing
-
-
--- | Sometimes the declaration we want to export is not the "main" declaration:
--- it might be an individual record selector or a class method. In these
--- cases we have to extract the required declaration (and somehow cobble
--- together a type signature for it...)
-extractDecl :: Name -> Module -> LHsDecl Name -> LHsDecl Name
-extractDecl name mdl decl
- | Just n <- getMainDeclBinder (unLoc decl), n == name = decl
- | otherwise =
- case unLoc decl of
- TyClD d | isClassDecl d ->
- let matches = [ sig | sig <- tcdSigs d, sigName sig == Just name ]
- in case matches of
- [s0] -> let (n, tyvar_names) = name_and_tyvars d
- L pos sig = extractClassDecl n mdl tyvar_names s0
- in L pos (SigD sig)
- _ -> error "internal: extractDecl"
- TyClD d | isDataDecl d ->
- let (n, tyvar_names) = name_and_tyvars d
- L pos sig = extractRecSel name mdl n tyvar_names (tcdCons d)
- in L pos (SigD sig)
- _ -> error "internal: extractDecl"
- where
- name_and_tyvars d = (unLoc (tcdLName d), hsLTyVarLocNames (tcdTyVars d))
-
-
-toTypeNoLoc :: Located Name -> LHsType Name
-toTypeNoLoc lname = noLoc (HsTyVar (unLoc lname))
-
-
-rmLoc :: Located a -> Located a
-rmLoc a = noLoc (unLoc a)
-
-
-extractClassDecl :: Name -> Module -> [Located Name] -> LSig Name -> LSig Name
-extractClassDecl c mdl tvs0 (L pos (TypeSig lname ltype)) = case ltype of
- L _ (HsForAllTy exp tvs (L _ preds) ty) ->
- L pos (TypeSig lname (noLoc (HsForAllTy exp tvs (lctxt preds) ty)))
- _ -> L pos (TypeSig lname (noLoc (mkImplicitHsForAllTy (lctxt []) ltype)))
- where
- lctxt preds = noLoc (ctxt preds)
- ctxt preds = [noLoc (HsClassP c (map toTypeNoLoc tvs0))] ++ preds
-
-extractClassDecl _ _ _ d = error $ "extractClassDecl: unexpected decl"
-
-
-extractRecSel :: Name -> Module -> Name -> [Located Name] -> [LConDecl Name]
- -> LSig Name
-extractRecSel _ _ _ _ [] = error "extractRecSel: selector not found"
-
-extractRecSel nm mdl t tvs (L _ con : rest) =
- case con_details con of
- RecCon fields | (ConDeclField n ty _ : _) <- matching_fields fields ->
- L (getLoc n) (TypeSig (noLoc nm) (noLoc (HsFunTy data_ty (getBangType ty))))
- _ -> extractRecSel nm mdl t tvs rest
- where
- matching_fields flds = [ f | f@(ConDeclField n _ _) <- flds, (unLoc n) == nm ]
- data_ty = foldl (\x y -> noLoc (HsAppTy x y)) (noLoc (HsTyVar t)) (map toTypeNoLoc tvs)
-
-
--- Pruning
-pruneExportItems :: [ExportItem Name] -> [ExportItem Name]
-pruneExportItems items = filter hasDoc items
- where hasDoc (ExportDecl _ _ d _) = isJust d
- hasDoc _ = True
-
-
--- | Gather a list of original names exported from this module
-mkVisibleNames :: Module
- -> ModuleMap
- -> [Name]
- -> [Name]
- -> Map Name [Name]
- -> Maybe [IE Name]
- -> [DocOption]
- -> Map Name (LHsDecl Name)
- -> ErrMsgM [Name]
-
-mkVisibleNames mdl modMap localNames scope subMap maybeExps opts declMap
- -- if no export list, just return all local names
- | Nothing <- maybeExps = return (filter hasDecl localNames)
- | OptIgnoreExports `elem` opts = return localNames
- | Just expspecs <- maybeExps = do
- visibleNames <- mapM extract expspecs
- return $ filter isNotPackageName (concat visibleNames)
- where
- hasDecl name = isJust (Map.lookup name declMap)
- isNotPackageName name = nameMod == mdl || isJust (Map.lookup nameMod modMap)
- where nameMod = nameModule name
-
- extract e =
- case e of
- IEVar x -> return [x]
- IEThingAbs t -> return [t]
- IEThingAll t -> return (t : all_subs)
- where
- all_subs | nameModule t == mdl = Map.findWithDefault [] t subMap
- | otherwise = allSubsOfName modMap t
-
- IEThingWith t cs -> return (t : cs)
-
- IEModuleContents m
- | mkModule (modulePackageId mdl) m == mdl -> return localNames
- | otherwise -> let m' = mkModule (modulePackageId mdl) m in
- case Map.lookup m' modMap of
- Just mod
- | OptHide `elem` hmod_options mod ->
- return (filter (`elem` scope) (hmod_exports mod))
- | otherwise -> return []
- Nothing
- -> tell (exportModuleMissingErr mdl m') >> return []
-
- _ -> return []
-
-
-exportModuleMissingErr this mdl
- = ["Warning: in export list of " ++ show (moduleString this)
- ++ ": module not found: " ++ show (moduleString mdl)]
-
-
--- | For a given entity, find all the names it "owns" (ie. all the
--- constructors and field names of a tycon, or all the methods of a
--- class).
-allSubsOfName :: ModuleMap -> Name -> [Name]
-allSubsOfName mod_map name
- | isExternalName name =
- case Map.lookup (nameModule name) mod_map of
- Just hmod -> Map.findWithDefault [] name (hmod_sub_map hmod)
- Nothing -> []
- | otherwise = error $ "Main.allSubsOfName: unexpected unqual'd name"
-
-
--- | Build a mapping which for each original name, points to the "best"
--- place to link to in the documentation. For the definition of
--- "best", we use "the module nearest the bottom of the dependency
--- graph which exports this name", not including hidden modules. When
--- there are multiple choices, we pick a random one.
---
--- The interfaces are passed in in topologically sorted order, but we start
--- by reversing the list so we can do a foldl.
-buildGlobalDocEnv :: [HaddockModule] -> Map Name Name
-buildGlobalDocEnv modules
- = foldl upd Map.empty (reverse modules)
- where
- upd old_env mod
- | OptHide `elem` hmod_options mod
- = old_env
- | OptNotHome `elem` hmod_options mod
- = foldl' keep_old old_env exported_names
- | otherwise
- = foldl' keep_new old_env exported_names
- where
- exported_names = hmod_visible_exports mod
- modName = hmod_mod mod
-
- keep_old env n = Map.insertWith (\new old -> old)
- n (nameSetMod n modName) env
- keep_new env n = Map.insert n (nameSetMod n modName) env
-
-
--- Named documentation
-
-findNamedDoc :: String -> [Entity] -> ErrMsgM (Maybe (HsDoc Name))
-findNamedDoc name entities = search entities
- where search [] = do
- tell ["Cannot find documentation for: $" ++ name]
- return Nothing
- search ((DocEntity (DocCommentNamed name' doc)):rest)
- | name == name' = return (Just doc)
- | otherwise = search rest
- search (_other_decl : rest) = search rest
-
-
--- Haddock options embedded in the source file
-
-processOptions_ str = let (opts, msg) = runWriter (processOptions str)
- in print msg >> return opts
-
-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 "not-home" = return (Just OptNotHome)
-parseOption other = do tell ["Unrecognised option: " ++ other]; return Nothing
-
-
--- | Simplified type for sorting types, ignoring qualification (not visible
--- in Haddock output) and unifying special tycons with normal ones.
-data SimpleType = SimpleType Name [SimpleType] deriving (Eq,Ord)
-
-
-attachInstances :: [HaddockModule] -> [HaddockModule]
-attachInstances modules = map attach modules
- where
- instMap = fmap (map toHsInstHead . sortImage instHead) $ collectInstances modules
- attach mod = mod { hmod_export_items = newItems }
- where
- newItems = map attachExport (hmod_export_items mod)
-
- attachExport (ExportDecl n decl doc _) =
- ExportDecl n decl doc (case Map.lookup n instMap of
- Nothing -> []
- Just instheads -> instheads)
- attachExport otherExport = otherExport
-
-
-collectInstances
- :: [HaddockModule]
- -> Map Name [([TyVar], [PredType], Class, [Type])] -- maps class/type names to instances
-
-collectInstances modules
- = Map.fromListWith (flip (++)) tyInstPairs `Map.union`
- Map.fromListWith (flip (++)) classInstPairs
- where
- allInstances = concat (map hmod_instances modules)
- classInstPairs = [ (is_cls inst, [instanceHead inst]) |
- inst <- allInstances ]
- tyInstPairs = [ (tycon, [instanceHead inst]) | inst <- allInstances,
- Just tycon <- nub (is_tcs inst) ]
-
-
-instHead :: ([TyVar], [PredType], Class, [Type]) -> ([Int], Name, [SimpleType])
-instHead (_, _, cls, args)
- = (map argCount args, className cls, map simplify args)
- where
- argCount (AppTy t _) = argCount t + 1
- argCount (TyConApp _ ts) = length ts
- argCount (FunTy _ _ ) = 2
- argCount (ForAllTy _ t) = argCount t
- argCount (NoteTy _ t) = argCount t
- argCount _ = 0
-
- simplify (ForAllTy _ t) = simplify t
- simplify (FunTy t1 t2) =
- SimpleType funTyConName [simplify t1, simplify t2]
- simplify (AppTy t1 t2) = SimpleType s (args ++ [simplify t2])
- where (SimpleType s args) = simplify t1
- simplify (TyVarTy v) = SimpleType (tyVarName v) []
- simplify (TyConApp tc ts) = SimpleType (tyConName tc) (map simplify ts)
- simplify (NoteTy _ t) = simplify t
- simplify _ = error "simplify"
-
-
--- sortImage f = sortBy (\x y -> compare (f x) (f y))
-sortImage :: Ord b => (a -> b) -> [a] -> [a]
-sortImage f xs = map snd $ sortBy cmp_fst [(f x, x) | x <- xs]
- where cmp_fst (x,_) (y,_) = compare x y
-
-
-funTyConName = mkWiredInName gHC_PRIM
- (mkOccNameFS tcName FSLIT("(->)"))
- funTyConKey
- (ATyCon funTyCon) -- Relevant TyCon
- BuiltInSyntax
-
-
-toHsInstHead :: ([TyVar], [PredType], Class, [Type]) -> InstHead Name
-toHsInstHead (_, preds, cls, ts) = (map toHsPred preds, className cls, map toHsType ts)
-
-
---------------------------------------------------------------------------------
--- Type -> HsType conversion
---------------------------------------------------------------------------------
-
-
-toHsPred :: PredType -> HsPred Name
-toHsPred (ClassP cls ts) = HsClassP (className cls) (map toLHsType ts)
-toHsPred (IParam n t) = HsIParam n (toLHsType t)
-
-
-toLHsType = noLoc . toHsType
-
-
-toHsType :: Type -> HsType Name
-toHsType t = case t of
- TyVarTy v -> HsTyVar (tyVarName v)
- AppTy a b -> HsAppTy (toLHsType a) (toLHsType b)
- TyConApp tc ts -> case ts of
- [] -> HsTyVar (tyConName tc)
- _ -> app (tycon tc) ts
- FunTy a b -> HsFunTy (toLHsType a) (toLHsType b)
- ForAllTy v t -> cvForAll [v] t
- PredTy p -> HsPredTy (toHsPred p)
- NoteTy _ t -> toHsType t
- where
- tycon tc = HsTyVar (tyConName tc)
- app tc ts = foldl (\a b -> HsAppTy (noLoc a) (noLoc b)) tc (map toHsType ts)
- cvForAll vs (ForAllTy v t) = cvForAll (v:vs) t
- cvForAll vs t = mkExplicitHsForAllTy (tyvarbinders vs) (noLoc []) (toLHsType t)
- tyvarbinders vs = map (noLoc . UserTyVar . tyVarName) vs
-
-
--- A monad which collects error messages
-
-type ErrMsg = String
-type ErrMsgM a = Writer [ErrMsg] a