aboutsummaryrefslogtreecommitdiff
path: root/src/Haddock/Interface.hs
blob: e548f500ce8251a4c2be7fd8d0c364c5cb620046 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
--
-- Haddock - A Haskell Documentation Tool
--
-- (c) Simon Marlow 2003
--

-- Here we build the actual module interfaces. By interface we mean the 
-- information that is used to render a Haddock page for a module. Parts of 
-- this information is also stored in the interface files.


module Haddock.Interface (
  createInterfaces
) where


import Haddock.Interface.Create
import Haddock.Interface.AttachInstances
import Haddock.Interface.Rename
import Haddock.Types
import Haddock.Options
import Haddock.GHC.Utils

import qualified Data.Map as Map
import Data.Map (Map)
import Data.List
import Control.Monad.Writer
import Control.Monad

import Name


-- | Turn a topologically sorted list of GhcModules into interfaces. Also
-- return the home link environment created in the process, and any error
-- messages.
createInterfaces :: [GhcModule] -> LinkEnv -> [Flag] -> ([Interface], LinkEnv, [ErrMsg])
createInterfaces modules extLinks flags = (interfaces, homeLinks, messages)
  where 
    ((interfaces, homeLinks), messages) = runWriter $ do
      -- part 1, create the interfaces
      interfaces <- createInterfaces' modules flags
      -- part 2, attach the instances
      let interfaces' = attachInstances interfaces
      -- part 3, rename the interfaces
      renameInterfaces interfaces' extLinks


createInterfaces' :: [GhcModule] -> [Flag] -> ErrMsgM [Interface]
createInterfaces' modules flags = do
  resultMap <- foldM addInterface Map.empty modules
  return (Map.elems resultMap)
  where
    addInterface :: ModuleMap -> GhcModule -> ErrMsgM ModuleMap
    addInterface map mod = do
      interface <- createInterface mod flags map
      return $ Map.insert (ifaceMod interface) interface map

 
renameInterfaces :: [Interface] -> LinkEnv -> ErrMsgM ([Interface], LinkEnv)
renameInterfaces interfaces externalLinks = do
  let homeLinks = buildHomeLinks interfaces
  let links = homeLinks `Map.union` externalLinks
  interfaces' <- mapM (renameInterface links) interfaces
  return (interfaces', homeLinks)


-- | 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.
buildHomeLinks :: [Interface] -> LinkEnv
buildHomeLinks modules = foldl upd Map.empty (reverse modules)
  where
    upd old_env mod
      | OptHide    `elem` ifaceOptions mod = old_env
      | OptNotHome `elem` ifaceOptions mod =
        foldl' keep_old old_env exported_names
      | otherwise = foldl' keep_new old_env exported_names
      where
        exported_names = ifaceVisibleExports mod
        modName = ifaceMod 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