@@ -1,297 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings #-}
11−import Control.Concurrent.Chan (Chan, newChan, readChan)
12−import Control.Monad (foldM)
13−import Control.Monad.Except (liftIO)
14−import qualified Data.ByteString as BS
15−import qualified Data.Graph as Graph
16−import qualified Data.Map as Map
17−import qualified Data.Set as Set
19−import qualified Elm.Compiler.Objects as Obj
20−import qualified Elm.Kernel as Kernel
21−import qualified Elm.ModuleName as ModuleName
22−import qualified Elm.Package as Pkg
24−import qualified Elm.Project.Json as Project
25−import Elm.Project.Summary (Summary(..))
26−import qualified File.Args as Args
27−import qualified File.Find as Find
28−import qualified File.Header as Header
29−import qualified File.IO as IO
30−import qualified Reporting.Exit as Exit
31−import qualified Reporting.Exit.Crawl as E
32−import qualified Reporting.Task as Task
39−data Graph kernel problems =
41− { _args :: Args.Args ModuleName.Raw
42− , _locals :: Map.Map ModuleName.Raw Header.Info
43− , _kernels :: Map.Map ModuleName.Raw kernel
44− , _foreigns :: Map.Map ModuleName.Raw Pkg.Canonical
45− , _problems :: problems
54− Graph (FilePath, Maybe FilePath) [E.Problem]
57−initWorkGraph :: Args.Args ModuleName.Raw -> Map.Map ModuleName.Raw Header.Info -> WorkGraph
58−initWorkGraph args locals =
59− Graph args locals Map.empty Map.empty []
66−crawl :: Summary -> Args.Args FilePath -> Task.Task Result
70− do let roots = map (Unvisited E.ElmJson) names
71− let graph = initWorkGraph (Args.Pkg names) Map.empty
72− depthFirstSearch summary roots graph
74− Args.Roots path [] ->
75− crawlHelp summary =<< Header.readOneFile summary path
78− do (h,hs) <- Header.readManyFiles summary p ps
79− let unvisited = concatMap toUnvisited (h:hs)
80− let graph = initWorkGraph (Args.Roots (fst h) (map fst hs)) (Map.fromList (h:hs))
81− depthFirstSearch summary unvisited graph
83− toUnvisited (name, Header.Info path _ _ deps) =
84− map (Unvisited (E.Module path name)) deps
87−crawlFromSource :: Summary -> BS.ByteString -> Task.Task Result
88−crawlFromSource summary@(Summary _ project _ _ _) source =
89− crawlHelp summary =<<
90− Header.readSource project source
93−crawlHelp :: Summary -> ( Maybe ModuleName.Raw, Header.Info ) -> Task.Task Result
94−crawlHelp summary ( maybeName, info@(Header.Info path _ _ deps) ) =
95− do let name = maybe "Main" id maybeName
96− let toUnvisited dep = Unvisited (maybe (E.File path) (E.Module path) maybeName) dep
97− let roots = map toUnvisited deps
98− let graph = initWorkGraph (Args.Roots name []) (Map.singleton name info)
99− depthFirstSearch summary roots graph
103−-- DEPTH FIRST SEARCH
106−depthFirstSearch :: Summary -> [Unvisited] -> WorkGraph -> Task.Task Result
107−depthFirstSearch summary unvisited startGraph =
108− do chan <- liftIO newChan
110− (Graph args locals kernelPaths foreigns problems) <-
111− dfs summary chan 0 Set.empty unvisited startGraph
115− do checkForCycles locals
116− kernels <- visitKernels summary locals kernelPaths
117− return $ Graph args locals kernels foreigns ()
119− problem : otherProblems ->
120− Task.throw (Exit.Crawl (E.DependencyProblems problem otherProblems))
127−checkForCycles :: Map.Map ModuleName.Raw Header.Info -> Task.Task ()
128−checkForCycles locals =
130− toNode (name, Header.Info _ _ _ imports) =
131− (name, name, imports)
134− Graph.stronglyConnComp (map toNode (Map.toList locals))
136− mapM_ checkComponent components
139−checkComponent :: Graph.SCC ModuleName.Raw -> Task.Task ()
142− Graph.AcyclicSCC _ ->
145− Graph.CyclicSCC names ->
146− Task.throw (Exit.Cycle names)
150−-- CONCURRENT DEPTH FIRST SEARCH
155− -> Chan (Either E.Problem Asset)
157− -> Set.Set ModuleName.Raw
160− -> Task.Task WorkGraph
161−dfs summary chan oldPending oldSeen unvisited graph =
162− do (seen, pending) <-
163− foldM (spawnVisitor summary chan) (oldSeen, oldPending) unvisited
168− do asset <- liftIO $ readChan chan
170− Right (Local name info@(Header.Info path _ _ imports)) ->
171− do let newGraph = graph { _locals = Map.insert name info (_locals graph) }
172− let deps = map (Unvisited (E.Module path name)) imports
173− dfs summary chan (pending - 1) seen deps newGraph
175− Right (Kernel name info) ->
176− do let kernels = Map.insert name info (_kernels graph)
177− let newGraph = graph { _kernels = kernels }
178− dfs summary chan (pending - 1) seen [] newGraph
180− Right (Foreign name pkg) ->
181− do let foreigns = Map.insert name pkg (_foreigns graph)
182− let newGraph = graph { _foreigns = foreigns }
183− dfs summary chan (pending - 1) seen [] newGraph
185− Right ForeignKernel ->
186− dfs summary chan (pending - 1) seen [] graph
189− do let problems = problem : _problems graph
190− let newGraph = graph { _problems = problems }
191− dfs summary chan (pending - 1) seen [] newGraph
196− -> Chan (Either E.Problem Asset)
197− -> (Set.Set ModuleName.Raw, Int)
199− -> Task.Task (Set.Set ModuleName.Raw, Int)
200−spawnVisitor summary chan (seen, n) unvisited@(Unvisited _ name) =
201− if Set.member name seen then
204− do Task.workerChan chan (toVisitor summary unvisited)
205− return (Set.insert name seen, n + 1)
214− { _origin :: E.Origin
215− , _name :: ModuleName.Raw
220− = Local ModuleName.Raw Header.Info
221− | Kernel ModuleName.Raw (FilePath, Maybe FilePath)
222− | Foreign ModuleName.Raw Pkg.Canonical
226−toVisitor :: Summary -> Unvisited -> Task.Task_ E.Problem Asset
227−toVisitor summary (Unvisited origin name) =
228− do asset <- Find.find summary origin name
231− uncurry Local <$> Header.readModule summary name path
234− return $ Foreign name pkg
236− Find.Kernel clientPath maybeServerPath ->
237− return $ Kernel name (clientPath, maybeServerPath)
239− Find.ForeignKernel ->
240− return ForeignKernel
249− -> Map.Map ModuleName.Raw Header.Info
250− -> Map.Map ModuleName.Raw (FilePath, Maybe FilePath)
251− -> Task.Task (Map.Map ModuleName.Raw Obj.Kernel)
252−visitKernels summary locals kernelPaths =
253− if Map.null kernelPaths then
256− -- TODO do this concurrently?
257− -- Need better concurrency primitives in Task
258− traverse (readKernel (toImportDict summary locals)) kernelPaths
261−readKernel :: ImportDict -> (FilePath, Maybe FilePath) -> Task.Task Obj.Kernel
262−readKernel importDict (clientPath, maybeServerPath) =
264− <$> readKContent importDict clientPath
265− <*> traverse (readKContent importDict) maybeServerPath
268−readKContent :: ImportDict -> FilePath -> Task.Task Kernel.KContent
269−readKContent importDict path =
270− do source <- liftIO $ IO.readUtf8 path
271− case Kernel.parse importDict source of
276− Task.throw (Exit.Crawl (E.BadKernelHeader path))
284− Map.Map ModuleName.Raw [Pkg.Name]
287−toImportDict :: Summary -> Map.Map ModuleName.Raw info -> ImportDict
288−toImportDict (Summary _ project exposed _ _) locals =
291− [Project.getName project]
293− addLocal name _ dict =
294− Map.insertWith (++) name localPkg dict
296− Map.foldrWithKey addLocal (Map.map (map Pkg._name) exposed) locals