aboutsummaryrefslogtreecommitdiff
path: root/src/Haddock/Interface.hs
blob: 41a73480f5f391170ae9ed65b963b30c303e9c99 (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
90
91
92
-------------------------------------------------------------------------------
-- Haddock.Interface
--
-- 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.
--
-- The Interface structure holds the interface data as well as 
-- intermediate information needed during its creation.
-------------------------------------------------------------------------------


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 (hmod_mod 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` 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