forked from purescript/purescript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathModuleDependencies.hs
More file actions
84 lines (73 loc) · 3.07 KB
/
ModuleDependencies.hs
File metadata and controls
84 lines (73 loc) · 3.07 KB
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
-----------------------------------------------------------------------------
--
-- Module : Language.PureScript.ModuleDependencies
-- Copyright : (c) 2013-15 Phil Freeman, (c) 2014-15 Gary Burgess
-- License : MIT (http://opensource.org/licenses/MIT)
--
-- Maintainer : Phil Freeman <paf31@cantab.net>
-- Stability : experimental
-- Portability :
--
-- | Provides the ability to sort modules based on module dependencies
--
-----------------------------------------------------------------------------
{-# LANGUAGE FlexibleContexts #-}
module Language.PureScript.ModuleDependencies (
sortModules,
ModuleGraph
) where
import Control.Monad.Error.Class (MonadError(..))
import Data.Graph
import Data.List (nub)
import Data.Maybe (fromMaybe)
import Language.PureScript.Crash
import Language.PureScript.AST
import Language.PureScript.Names
import Language.PureScript.Types
import Language.PureScript.Errors
-- | A list of modules with their transitive dependencies
type ModuleGraph = [(ModuleName, [ModuleName])]
-- | Sort a collection of modules based on module dependencies.
--
-- Reports an error if the module graph contains a cycle.
--
sortModules :: (MonadError MultipleErrors m) => [Module] -> m ([Module], ModuleGraph)
sortModules ms = do
let verts = map (\m@(Module _ _ _ ds _) -> (m, getModuleName m, nub (concatMap usedModules ds))) ms
ms' <- mapM toModule $ stronglyConnComp verts
let (graph, fromVertex, toVertex) = graphFromEdges verts
moduleGraph = do (_, mn, _) <- verts
let v = fromMaybe (internalError "sortModules: vertex not found") (toVertex mn)
deps = reachable graph v
toKey i = case fromVertex i of (_, key, _) -> key
return (mn, filter (/= mn) (map toKey deps))
return (ms', moduleGraph)
-- |
-- Calculate a list of used modules based on explicit imports and qualified names
--
usedModules :: Declaration -> [ModuleName]
usedModules d =
let (f, _, _, _, _) = everythingOnValues (++) forDecls forValues (const []) (const []) (const [])
(g, _, _, _, _) = accumTypes (everythingOnTypes (++) forTypes)
in nub (f d ++ g d)
where
forDecls :: Declaration -> [ModuleName]
forDecls (ImportDeclaration mn _ _ _) = [mn]
forDecls (FixityDeclaration _ _ (Just (Left (Qualified (Just mn) _)))) = [mn]
forDecls (FixityDeclaration _ _ (Just (Right (Qualified (Just mn) _)))) = [mn]
forDecls (TypeInstanceDeclaration _ _ (Qualified (Just mn) _) _ _) = [mn]
forDecls _ = []
forValues :: Expr -> [ModuleName]
forValues (Var (Qualified (Just mn) _)) = [mn]
forValues (Constructor (Qualified (Just mn) _)) = [mn]
forValues _ = []
forTypes :: Type -> [ModuleName]
forTypes (TypeConstructor (Qualified (Just mn) _)) = [mn]
forTypes _ = []
-- |
-- Convert a strongly connected component of the module graph to a module
--
toModule :: (MonadError MultipleErrors m) => SCC Module -> m Module
toModule (AcyclicSCC m) = return m
toModule (CyclicSCC [m]) = return m
toModule (CyclicSCC ms) = throwError . errorMessage $ CycleInModules (map getModuleName ms)