2-- Provides the ability to sort modules based on module dependencies
4module Language.PureScript.ModuleDependencies
11import Control.Monad.Error.Class (MonadError(..))
15import Data.Maybe (fromMaybe)
17import Language.PureScript.AST
18import Language.PureScript.Crash
19import Language.PureScript.Errors
20import Language.PureScript.Names
21import Language.PureScript.Types
23-- | A list of modules with their transitive dependencies
24type ModuleGraph = [(ModuleName, [ModuleName])]
26-- | Sort a collection of modules based on module dependencies.
28-- Reports an error if the module graph contains a cycle.
30sortModules :: (MonadError MultipleErrors m) => [Module] -> m ([Module], ModuleGraph)
32 let verts = map goModule ms
33 ms' <- mapM toModule $ stronglyConnComp verts
34 let (graph, fromVertex, toVertex) = graphFromEdges verts
35 moduleGraph = do (_, mn, _) <- verts
36 let v = fromMaybe (internalError "sortModules: vertex not found") (toVertex mn)
37 deps = reachable graph v
38 toKey i = case fromVertex i of (_, key, _) -> key
39 return (mn, filter (/= mn) (map toKey deps))
40 return (ms', moduleGraph)
42 goModule :: Module -> (Module, ModuleName, [ModuleName])
43 goModule m@(Module _ _ _ ds _) =
44 let ams = concatMap extractQualAs ds
45 in (m, getModuleName m, nub (concatMap (usedModules ams) ds))
47 -- Extract module names that have been brought into scope by an `as` import.
48 extractQualAs :: Declaration -> [ModuleName]
49 extractQualAs (PositionedDeclaration _ _ d) = extractQualAs d
50 extractQualAs (ImportDeclaration _ _ (Just am)) = [am]
54-- Calculate a list of used modules based on explicit imports and qualified
55-- names. `ams` is a list of `ModuleNames` that refer to names brought into
56-- scope by importing with `as` - this ensures that when building the list we
57-- don't inadvertantly assume a dependency on an actual module, if there is a
58-- module that has the same name as the qualified import.
60usedModules :: [ModuleName] -> Declaration -> [ModuleName]
62 let (f, _, _, _, _) = everythingOnValues (++) forDecls forValues (const []) (const []) (const [])
63 (g, _, _, _, _) = accumTypes (everythingOnTypes (++) forTypes)
67 forDecls :: Declaration -> [ModuleName]
68 forDecls (ImportDeclaration mn _ _) =
69 -- Regardless of whether an imported module is qualified we still need to
70 -- take into account its import to build an accurate list of dependencies.
72 forDecls (FixityDeclaration fd)
73 | Just mn <- extractQualFixity fd, mn `notElem` ams = [mn]
74 forDecls (TypeInstanceDeclaration _ _ (Qualified (Just mn) _) _ _)
75 | mn `notElem` ams = [mn]
78 forValues :: Expr -> [ModuleName]
79 forValues (Var (Qualified (Just mn) _))
80 | mn `notElem` ams = [mn]
81 forValues (Constructor (Qualified (Just mn) _))
82 | mn `notElem` ams = [mn]
85 forTypes :: Type -> [ModuleName]
86 forTypes (TypeConstructor (Qualified (Just mn) _))
87 | mn `notElem` ams = [mn]
90 extractQualFixity :: Either ValueFixity TypeFixity -> Maybe ModuleName
91 extractQualFixity (Left (ValueFixity _ (Qualified mn _) _)) = mn
92 extractQualFixity (Right (TypeFixity _ (Qualified mn _) _)) = mn
95-- Convert a strongly connected component of the module graph to a module
97toModule :: (MonadError MultipleErrors m) => SCC Module -> m Module
98toModule (AcyclicSCC m) = return m
99toModule (CyclicSCC [m]) = return m
100toModule (CyclicSCC ms) = throwError . errorMessage $ CycleInModules (map getModuleName ms)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list