1{-# OPTIONS_GHC -Wno-unused-do-bind #-}
2{-# LANGUAGE BangPatterns, GADTs, OverloadedStrings #-}
18import Control.Concurrent (forkIO)
19import Control.Concurrent.MVar
20import Control.Monad (filterM, mapM_, sequence_)
21import qualified Data.ByteString as B
22import qualified Data.Char as Char
23import qualified Data.Either as Either
24import qualified Data.Graph as Graph
25import qualified Data.List as List
26import qualified Data.Map.Utils as Map
27import qualified Data.Map.Strict as Map
28import Data.Map.Strict ((!))
29import qualified Data.Maybe as Maybe
30import qualified Data.Name as Name
31import qualified Data.NonEmptyList as NE
32import qualified Data.OneOrMore as OneOrMore
33import qualified Data.Set as Set
34import qualified System.Directory as Dir
35import qualified System.FilePath as FP
36import System.FilePath ((</>), (<.>))
38import qualified AST.Canonical as Can
39import qualified AST.Source as Src
40import qualified AST.Optimized as Opt
41import qualified Compile
42import qualified Elm.Details as Details
43import qualified Elm.Docs as Docs
44import qualified Elm.Interface as I
45import qualified Elm.ModuleName as ModuleName
46import qualified Elm.Package as Pkg
48import qualified Json.Encode as E
49import qualified Parse.Module as Parse
50import qualified Reporting
51import qualified Reporting.Annotation as A
52import qualified Reporting.Error as Error
53import qualified Reporting.Error.Syntax as Syntax
54import qualified Reporting.Error.Import as Import
55import qualified Reporting.Exit as Exit
56import qualified Reporting.Render.Type.Localizer as L
66 { _key :: Reporting.BKey
69 , _srcDirs :: [FilePath]
70 , _locals :: Map.Map ModuleName.Raw Details.Local
71 , _foreigns :: Map.Map ModuleName.Raw Details.Foreign
75makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> Env
76makeEnv key root (Details.Details _ validOutline locals foreigns _) =
78 Details.ValidApp srcDirs ->
79 Env key root Pkg.dummyName (NE.toList srcDirs) locals foreigns
81 Details.ValidPkg pkg _ ->
82 Env key root pkg ["src"] locals foreigns
89fork :: IO a -> IO (MVar a)
91 do mvar <- newEmptyMVar
92 _ <- forkIO $ putMVar mvar =<< work
96{-# INLINE forkWithKey #-}
97forkWithKey :: (k -> a -> IO b) -> Map.Map k a -> IO (Map.Map k (MVar b))
98forkWithKey func dict =
99 Map.traverseWithKey (\k v -> fork (func k v)) dict
106fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
107fromExposed style root details docsGoal exposed@(NE.List e es) =
108 Reporting.trackBuild style $ \key ->
109 do let env = makeEnv key root details
110 dmvar <- Details.loadInterfaces root details
114 let docsNeed = toDocsNeed docsGoal
115 roots <- Map.fromKeysA (fork . crawlModule env mvar docsNeed) (e:es)
118 statuses <- traverse readMVar =<< readMVar mvar
121 midpoint <- checkMidpoint dmvar statuses
124 return (Left (Exit.BuildProjectProblem problem))
127 do rmvar <- newEmptyMVar
128 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
129 putMVar rmvar resultMVars
130 results <- traverse readMVar resultMVars
131 writeDetails root details results
132 finalizeExposed docsGoal exposed results
142 , _deps :: Dependencies
143 , _mains :: NE.List Main
144 , _modules :: [Module]
149 = Fresh ModuleName.Raw I.Interface Opt.LocalGraph
150 | Cached ModuleName.Raw Bool (MVar CachedInterface)
154 Map.Map ModuleName.Canonical I.DependencyInterface
157fromMains :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
158fromMains style root details paths =
159 Reporting.trackBuild style $ \key ->
160 do let env = makeEnv key root details
162 elmains <- findMains env paths
165 return (Left (Exit.BuildProjectProblem problem))
169 dmvar <- Details.loadInterfaces root details
170 smvar <- newMVar Map.empty
171 smainMVars <- traverse (fork . crawlMain env smvar) lmains
172 smains <- traverse readMVar smainMVars
173 statuses <- traverse readMVar =<< readMVar smvar
175 midpoint <- checkMainsMidpoint dmvar statuses smains
178 return (Left (Exit.BuildProjectProblem problem))
182 rmvar <- newEmptyMVar
183 resultsMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
184 putMVar rmvar resultsMVars
185 rmainMVars <- traverse (fork . checkMain env resultsMVars) smains
186 results <- traverse readMVar resultsMVars
187 writeDetails root details results
188 toArtifacts env foreigns results <$> traverse readMVar rmainMVars
195getMainNames :: Artifacts -> NE.List ModuleName.Raw
196getMainNames (Artifacts _ _ mains _) =
197 fmap getMainName mains
200getMainName :: Main -> ModuleName.Raw
204 Outside name _ _ -> name
212 Map.Map ModuleName.Raw (MVar Status)
216 = SCached Details.Local
217 | SChanged Details.Local B.ByteString Src.Module DocsNeed
218 | SBadImport Import.Problem
219 | SBadSyntax FilePath File.Time B.ByteString Syntax.Error
224crawlDeps :: Env -> MVar StatusDict -> [ModuleName.Raw] -> a -> IO a
225crawlDeps env mvar deps blockedValue =
226 do statusDict <- takeMVar mvar
227 let depsDict = Map.fromKeys (\_ -> ()) deps
228 let newsDict = Map.difference depsDict statusDict
229 statuses <- Map.traverseWithKey crawlNew newsDict
230 putMVar mvar (Map.union statuses statusDict)
231 mapM_ readMVar statuses
234 crawlNew name () = fork (crawlModule env mvar (DocsNeed False) name)
237crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
238crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
239 do let fileName = ModuleName.toFilePath name <.> "elm"
240 let inRoot path = File.exists (root </> path)
242 paths <- filterM inRoot (map (</> fileName) srcDirs)
246 case Map.lookup name foreigns of
247 Just (Details.Foreign dep deps) ->
248 return $ SBadImport $ Import.Ambiguous path [] dep deps
251 case Map.lookup name locals of
253 crawlFile env mvar docsNeed name path
255 Just local@(Details.Local oldPath oldTime deps _) ->
257 then crawlFile env mvar docsNeed name path
259 do newTime <- File.getTime path
260 if oldTime < newTime || needsDocs docsNeed
261 then crawlFile env mvar docsNeed name path
262 else crawlDeps env mvar deps (SCached local)
265 return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
268 case Map.lookup name foreigns of
269 Just (Details.Foreign dep deps) ->
272 return $ SForeign dep
275 return $ SBadImport $ Import.AmbiguousForeign dep d ds
278 if Name.isKernel name && Pkg.isKernel pkg then
279 do exists <- File.exists ("src" </> ModuleName.toFilePath name <.> "js")
280 return $ if exists then SKernel else SBadImport Import.NotFound
282 return $ SBadImport Import.NotFound
285crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> IO Status
286crawlFile env@(Env _ root pkg _ _ _) mvar docsNeed expectedName path =
287 do time <- File.getTime path
288 source <- File.readUtf8 (root </> path)
290 case Parse.fromByteString pkg source of
292 return $ SBadSyntax path time source err
294 Right modul@(Src.Module maybeActualName _ _ imports values _ _ _ _) ->
295 case maybeActualName of
297 return $ SBadSyntax path time source (Syntax.ModuleNameUnspecified expectedName)
299 Just name@(A.At _ actualName) ->
300 if expectedName == actualName then
302 deps = map Src.getImportName imports
303 local = Details.Local path time deps (any isMain values)
305 crawlDeps env mvar deps (SChanged local source modul docsNeed)
307 return $ SBadSyntax path time source (Syntax.ModuleNameMismatch expectedName name)
310isMain :: A.Located Src.Value -> Bool
311isMain (A.At _ (Src.Value (A.At _ name) _ _ _)) =
320 Map.Map ModuleName.Raw (MVar Result)
324 = RNew !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
325 | RSame !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
326 | RCached Bool (MVar CachedInterface)
327 | RNotFound Import.Problem
328 | RProblem Error.Module
330 | RForeign I.Interface
340checkModule :: Env -> Dependencies -> MVar ResultDict -> ModuleName.Raw -> Status -> IO Result
341checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
343 SCached local@(Details.Local path time deps hasMain) ->
344 do results <- readMVar resultsMVar
345 depsStatus <- checkDeps root results deps
348 do source <- File.readUtf8 path
349 case Parse.fromByteString pkg source of
350 Right modul -> compile env (DocsNeed False) local source ifaces modul
353 Error.Module name path time source (Error.BadSyntax err)
356 do mvar <- newMVar Unneeded
357 return (RCached hasMain mvar)
362 DepsNotFound problems ->
363 do source <- File.readUtf8 path
364 return $ RProblem $ Error.Module name path time source $
365 case Parse.fromByteString pkg source of
366 Right (Src.Module _ _ _ imports _ _ _ _ _) ->
367 Error.BadImports (toImportErrors env results imports problems)
372 SChanged local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
373 do results <- readMVar resultsMVar
374 depsStatus <- checkDeps root results deps
377 compile env docsNeed local source ifaces modul
379 DepsSame same cached ->
380 do maybeLoaded <- loadInterfaces root same cached
382 Nothing -> return RBlocked
383 Just ifaces -> compile env docsNeed local source ifaces modul
388 DepsNotFound problems ->
389 return $ RProblem $ Error.Module name path time source $
390 Error.BadImports (toImportErrors env results imports problems)
392 SBadImport importProblem ->
393 return (RNotFound importProblem)
395 SBadSyntax path time source err ->
396 return $ RProblem $ Error.Module name path time source $
400 case foreigns ! ModuleName.Canonical home name of
401 I.Public iface -> return (RForeign iface)
402 I.Private _ _ _ -> error "loading private interface in Build"
413 = DepsChange (Map.Map ModuleName.Raw I.Interface)
414 | DepsSame [Dep] [CDep]
416 | DepsNotFound (NE.List (ModuleName.Raw, Import.Problem))
419checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> IO DepsStatus
420checkDeps root results deps =
421 checkDepsHelp root results deps [] [] [] [] False
424type Dep = (ModuleName.Raw, I.Interface)
425type CDep = (ModuleName.Raw, MVar CachedInterface)
428checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> IO DepsStatus
429checkDepsHelp root results deps new same cached importProblems isBlocked =
432 do result <- readMVar (results ! dep)
434 RNew _ iface _ _ -> checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked
435 RSame _ iface _ _ -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
436 RCached _ mvar -> checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked
437 RNotFound prob -> checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True
438 RProblem _ -> checkDepsHelp root results otherDeps new same cached importProblems True
439 RBlocked -> checkDepsHelp root results otherDeps new same cached importProblems True
440 RForeign iface -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
441 RKernel -> checkDepsHelp root results otherDeps new same cached importProblems isBlocked
444 case importProblems of
446 return $ DepsNotFound (NE.List p ps)
452 else if null new then
453 return $ DepsSame same cached
456 do maybeLoaded <- loadInterfaces root same cached
458 Nothing -> return DepsBlock
459 Just ifaces -> return $ DepsChange $ Map.union (Map.fromList new) ifaces
466toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
467toImportErrors (Env _ _ _ _ locals foreigns) results imports problems =
471 [ Map.keysSet foreigns
473 , Map.keysSet results
477 Set.difference knownModules (Set.fromList (map Src.getImportName imports))
480 Map.fromList (map (\(Src.Import (A.At region name) _ _) -> (name, region)) imports)
482 toError (name, problem) =
483 Import.Error (regionDict ! name) name unimportedModules problem
485 fmap toError problems
489-- LOAD CACHED INTERFACES
492loadInterfaces :: FilePath -> [Dep] -> [CDep] -> IO (Maybe (Map.Map ModuleName.Raw I.Interface))
493loadInterfaces root same cached =
494 do loading <- traverse (fork . loadInterface root) cached
495 maybeLoaded <- traverse readMVar loading
496 case sequence maybeLoaded of
501 return $ Just $ Map.union (Map.fromList loaded) (Map.fromList same)
504loadInterface :: FilePath -> CDep -> IO (Maybe Dep)
505loadInterface root (name, ciMvar) =
506 do cachedInterface <- takeMVar ciMvar
507 case cachedInterface of
509 do putMVar ciMvar cachedInterface
513 do putMVar ciMvar cachedInterface
514 return (Just (name, iface))
517 do maybeIface <- File.readBinary (Stuff.elmi root name)
520 do putMVar ciMvar Corrupted
524 do putMVar ciMvar (Loaded iface)
525 return (Just (name, iface))
532checkMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> IO (Either Exit.BuildProjectProblem Dependencies)
533checkMidpoint dmvar statuses =
534 case checkForCycles statuses of
536 do maybeForeigns <- readMVar dmvar
537 case maybeForeigns of
538 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
539 Just fs -> return (Right fs)
541 Just (NE.List name names) ->
542 do _ <- readMVar dmvar
543 return (Left (Exit.BP_Cycle name names))
546checkMainsMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> NE.List MainStatus -> IO (Either Exit.BuildProjectProblem Dependencies)
547checkMainsMidpoint dmvar statuses smains =
548 case checkForCycles statuses of
550 case checkUniqueMains statuses smains of
552 do maybeForeigns <- readMVar dmvar
553 case maybeForeigns of
554 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
555 Just fs -> return (Right fs)
558 do _ <- readMVar dmvar
559 return (Left problem)
561 Just (NE.List name names) ->
562 do _ <- readMVar dmvar
563 return (Left (Exit.BP_Cycle name names))
570checkForCycles :: Map.Map ModuleName.Raw Status -> Maybe (NE.List ModuleName.Raw)
571checkForCycles modules =
573 !graph = Map.foldrWithKey addToGraph [] modules
574 !sccs = Graph.stronglyConnComp graph
576 checkForCyclesHelp sccs
579checkForCyclesHelp :: [Graph.SCC ModuleName.Raw] -> Maybe (NE.List ModuleName.Raw)
580checkForCyclesHelp sccs =
587 Graph.AcyclicSCC _ -> checkForCyclesHelp otherSccs
588 Graph.CyclicSCC [] -> checkForCyclesHelp otherSccs
589 Graph.CyclicSCC (m:ms) -> Just (NE.List m ms)
593 ( ModuleName.Raw, ModuleName.Raw, [ModuleName.Raw] )
596addToGraph :: ModuleName.Raw -> Status -> [Node] -> [Node]
597addToGraph name status graph =
601 SCached (Details.Local _ _ deps _) -> deps
602 SChanged (Details.Local _ _ deps _) _ _ _ -> deps
604 SBadSyntax _ _ _ _ -> []
608 (name, name, dependencies) : graph
615checkUniqueMains :: Map.Map ModuleName.Raw Status -> NE.List MainStatus -> Maybe Exit.BuildProjectProblem
616checkUniqueMains insides smains =
619 Map.fromListWith OneOrMore.more (Maybe.mapMaybe mainStatusToNamePathPair (NE.toList smains))
621 case Map.traverseWithKey checkOutside outsidesDict of
626 case sequence_ (Map.intersectionWithKey checkInside outsides insides) of
628 Left problem -> Just problem
631mainStatusToNamePathPair :: MainStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
632mainStatusToNamePathPair smain =
635 SOutsideOk (Details.Local path _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
636 SOutsideErr _ -> Nothing
639checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
640checkOutside name paths =
641 case OneOrMore.destruct NE.List paths of
642 NE.List p [] -> Right p
643 NE.List p1 (p2:_) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
646checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
647checkInside name p1 status =
649 SCached (Details.Local p2 _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
650 SChanged (Details.Local p2 _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
651 SBadImport _ -> Right ()
652 SBadSyntax _ _ _ _ -> Right ()
653 SForeign _ -> Right ()
661compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
662compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) source ifaces modul =
663 case Compile.compile pkg ifaces modul of
664 Right (Compile.Artifacts canonical annotations objects) ->
665 do let name = Src.getName modul
666 let iface = I.fromModule pkg canonical annotations
667 let docs = makeDocs docsNeed canonical
668 let path = Stuff.elmi root name
669 File.writeBinary (Stuff.elmo root name) objects
670 maybeOldi <- File.readBinary path
672 Just oldi | oldi == iface ->
673 do -- iface should be fully forced by equality check
674 Reporting.report key Reporting.BDone
675 return (RSame local iface objects docs)
678 do -- iface may be lazy still
679 File.writeBinary path iface
680 Reporting.report key Reporting.BDone
681 return (RNew local iface objects docs)
684 do Reporting.report key Reporting.BDone
686 Error.Module (Src.getName modul) path time source err
693writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
694writeDetails root (Details.Details time outline locals foreigns extras) results =
695 File.writeBinary (Stuff.details root) $
696 Details.Details time outline (Map.foldrWithKey addNewLocal locals results) foreigns extras
699addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
700addNewLocal name result locals =
702 RNew local _ _ _ -> Map.insert name local locals
703 RSame local _ _ _ -> Map.insert name local locals
704 RCached _ _ -> locals
705 RNotFound _ -> locals
716finalizeExposed :: DocsGoal docs -> NE.List ModuleName.Raw -> Map.Map ModuleName.Raw Result -> IO (Either Exit.BuildProblem docs)
717finalizeExposed docsGoal exposed results =
718 case foldr (addImportProblems results) [] (NE.toList exposed) of
720 return $ Left $ Exit.BuildProjectProblem (Exit.BP_MissingExposed (NE.List p ps))
723 case Map.foldr addErrors [] results of
724 [] -> Right <$> finalizeDocs docsGoal results
725 e:es -> return $ Left $ Exit.BuildBadModules e es
728addErrors :: Result -> [Error.Module] -> [Error.Module]
729addErrors result errors =
731 RNew _ _ _ _ -> errors
732 RSame _ _ _ _ -> errors
733 RCached _ _ -> errors
734 RNotFound _ -> errors
735 RProblem e -> e:errors
741addImportProblems :: Map.Map ModuleName.Raw Result -> ModuleName.Raw -> [(ModuleName.Raw, Import.Problem)] -> [(ModuleName.Raw, Import.Problem)]
742addImportProblems results name problems =
743 case results ! name of
744 RNew _ _ _ _ -> problems
745 RSame _ _ _ _ -> problems
746 RCached _ _ -> problems
747 RNotFound p -> (name, p) : problems
748 RProblem _ -> problems
750 RForeign _ -> problems
759 KeepDocs :: DocsGoal Docs.Documentation
760 WriteDocs :: FilePath -> DocsGoal ()
761 IgnoreDocs :: DocsGoal ()
765 DocsNeed { needsDocs :: Bool }
768toDocsNeed :: DocsGoal a -> DocsNeed
771 IgnoreDocs -> DocsNeed False
772 WriteDocs _ -> DocsNeed True
773 KeepDocs -> DocsNeed True
776makeDocs :: DocsNeed -> Can.Module -> Maybe Docs.Module
777makeDocs (DocsNeed isNeeded) modul =
779 case Docs.fromModule modul of
780 Right docs -> Just docs
786finalizeDocs :: DocsGoal docs -> Map.Map ModuleName.Raw Result -> IO docs
787finalizeDocs goal results =
790 return $ Map.mapMaybe toDocs results
793 E.writeUgly path $ Docs.encode $ Map.mapMaybe toDocs results
799toDocs :: Result -> Maybe Docs.Module
804 RCached _ _ -> Nothing
805 RNotFound _ -> Nothing
806 RProblem _ -> Nothing
808 RForeign _ -> Nothing
813--------------------------------------------------------------------------------
814------ NOW FOR SOME REPL STUFF -------------------------------------------------
815--------------------------------------------------------------------------------
823 { _repl_home :: ModuleName.Canonical
824 , _repl_modules :: [Module]
825 , _repl_localizer :: L.Localizer
826 , _repl_annotations :: Map.Map Name.Name Can.Annotation
830fromRepl :: FilePath -> Details.Details -> B.ByteString -> IO (Either Exit.Repl ReplArtifacts)
831fromRepl root details source =
833 env@(Env _ _ pkg _ _ _) = makeEnv Reporting.ignorer root details
835 case Parse.fromByteString pkg source of
837 return $ Left $ Exit.ReplBadInput source $ Error.BadSyntax syntaxError
839 Right modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
840 do dmvar <- Details.loadInterfaces root details
842 let deps = map Src.getImportName imports
843 mvar <- newMVar Map.empty
844 crawlDeps env mvar deps ()
846 statuses <- traverse readMVar =<< readMVar mvar
847 midpoint <- checkMidpoint dmvar statuses
851 return $ Left $ Exit.ReplProjectProblem problem
854 do rmvar <- newEmptyMVar
855 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
856 putMVar rmvar resultMVars
857 results <- traverse readMVar resultMVars
858 writeDetails root details results
859 depsStatus <- checkDeps root resultMVars deps
860 finalizeReplArtifacts env source modul depsStatus resultMVars results
863finalizeReplArtifacts :: Env -> B.ByteString -> Src.Module -> DepsStatus -> ResultDict -> Map.Map ModuleName.Raw Result -> IO (Either Exit.Repl ReplArtifacts)
864finalizeReplArtifacts env@(Env _ root pkg _ _ _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) depsStatus resultMVars results =
866 compileInput ifaces =
867 case Compile.compile pkg ifaces modul of
868 Right (Compile.Artifacts canonical annotations objects) ->
870 h = Can._name canonical
871 m = Fresh (Src.getName modul) (I.fromModule pkg canonical annotations) objects
872 ms = Map.foldrWithKey addInside [] results
874 return $ Right $ ReplArtifacts h (m:ms) (L.fromModule modul) annotations
877 return $ Left $ Exit.ReplBadInput source errors
883 DepsSame same cached ->
884 do maybeLoaded <- loadInterfaces root same cached
886 Just ifaces -> compileInput ifaces
887 Nothing -> return $ Left $ Exit.ReplBadCache
890 case Map.foldr addErrors [] results of
891 [] -> return $ Left $ Exit.ReplBlocked
892 e:es -> return $ Left $ Exit.ReplBadLocalDeps e es
894 DepsNotFound problems ->
895 return $ Left $ Exit.ReplBadInput source $ Error.BadImports $
896 toImportErrors env resultMVars imports problems
900--------------------------------------------------------------------------------
901--------------------------------------------------------------------------------
902------ AFTER THIS, EVERYTHING IS ABOUT HANDLING MODULES GIVEN BY FILEPATH ------
903--------------------------------------------------------------------------------
904--------------------------------------------------------------------------------
912 = LInside ModuleName.Raw
916findMains :: Env -> NE.List FilePath -> IO (Either Exit.BuildProjectProblem (NE.List MainLocation))
918 do mvars <- traverse (fork . findLocation env) paths
919 elocs <- traverse readMVar mvars
920 return $ checkLocations =<< sequence elocs
923checkLocations :: NE.List Location -> Either Exit.BuildProjectProblem (NE.List MainLocation)
924checkLocations locations =
926 toOneOrMore loc@(Location absolute _ _) =
927 (absolute, OneOrMore.one loc)
929 fromOneOrMore loc locs =
932 loc2:_ -> Left (Exit.BP_MainPathDuplicate (_relative loc) (_relative loc2))
934 fmap (\_ -> fmap _location locations) $
935 traverse (OneOrMore.destruct fromOneOrMore) $
936 Map.fromListWith OneOrMore.more $ map toOneOrMore (NE.toList locations)
945 { _absolute :: FilePath
946 , _relative :: FilePath
947 , _location :: MainLocation
951findLocation :: Env -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
952findLocation env path =
953 do exists <- File.exists path
955 then isInsideSrcDirs env path <$> Dir.canonicalizePath path
956 else return (Left (Exit.BP_PathUnknown path))
959isInsideSrcDirs :: Env -> FilePath -> FilePath -> Either Exit.BuildProjectProblem Location
960isInsideSrcDirs (Env _ root _ srcDirs _ _) path absolutePath =
962 (dirs, file) = FP.splitFileName absolutePath
963 (final, ext) = break (=='.') file
966 then Left (Exit.BP_WithBadExtension path)
969 roots = FP.splitDirectories root
970 segments = FP.splitDirectories dirs ++ [final]
972 case dropPrefix roots segments of
974 Right (Location absolutePath path (LOutside path))
976 Just relativeSegments ->
979 Either.partitionEithers (map (isInsideSrcDirsHelp relativeSegments) srcDirs)
981 -- TODO make sure this is all correct
982 case (exits, Maybe.catMaybes maybes) of
983 (_, [(_,name)]) -> Right (Location absolutePath path (LInside name))
984 ([], []) -> Right (Location absolutePath path (LOutside path))
985 (_, (s1,_):(s2,_):_) -> Left (Exit.BP_WithAmbiguousSrcDir path s1 s2)
986 (exit:_, _) -> Left exit
989isInsideSrcDirsHelp :: [String] -> FilePath -> Either Exit.BuildProjectProblem (Maybe (FilePath, ModuleName.Raw))
990isInsideSrcDirsHelp segments srcDir =
991 case dropPrefix (FP.splitDirectories srcDir) segments of
996 if all isGoodName names
997 then Right (Just (srcDir, Name.fromChars (List.intercalate "." names)))
998 else Left (error "Exit.MakeWithInvalidModuleName" srcDir segments)
1001isGoodName :: [Char] -> Bool
1008 Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
1011dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
1012dropPrefix roots paths =
1020 p:ps -> if r == p then dropPrefix rs ps else Nothing
1028 = SInside ModuleName.Raw
1029 | SOutsideOk Details.Local B.ByteString Src.Module
1030 | SOutsideErr Error.Module
1033crawlMain :: Env -> MVar StatusDict -> MainLocation -> IO MainStatus
1034crawlMain env@(Env _ _ pkg _ _ _) mvar given =
1037 do statusMVar <- newEmptyMVar
1038 statusDict <- takeMVar mvar
1039 putMVar mvar (Map.insert name statusMVar statusDict)
1040 putMVar statusMVar =<< crawlModule env mvar (DocsNeed False) name
1041 return (SInside name)
1044 do time <- File.getTime path
1045 source <- File.readUtf8 path
1046 case Parse.fromByteString pkg source of
1047 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
1048 do let deps = map Src.getImportName imports
1049 let local = Details.Local path time deps (any isMain values)
1050 crawlDeps env mvar deps (SOutsideOk local source modul)
1053 return $ SOutsideErr $
1054 Error.Module "???" path time source (Error.BadSyntax syntaxError)
1062 = RInside ModuleName.Raw
1063 | ROutsideOk ModuleName.Raw I.Interface Opt.LocalGraph
1064 | ROutsideErr Error.Module
1068checkMain :: Env -> ResultDict -> MainStatus -> IO MainResult
1069checkMain env@(Env _ root _ _ _ _) results pendingMain =
1072 return (RInside name)
1075 return (ROutsideErr err)
1077 SOutsideOk local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
1078 do depsStatus <- checkDeps root results deps
1080 DepsChange ifaces ->
1081 return $ compileOutside env local source ifaces modul
1083 DepsSame same cached ->
1084 do maybeLoaded <- loadInterfaces root same cached
1086 Nothing -> return ROutsideBlocked
1087 Just ifaces -> return $ compileOutside env local source ifaces modul
1090 return ROutsideBlocked
1092 DepsNotFound problems ->
1093 return $ ROutsideErr $ Error.Module (Src.getName modul) path time source $
1094 Error.BadImports (toImportErrors env results imports problems)
1097compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> MainResult
1098compileOutside (Env _ _ pkg _ _ _) (Details.Local path time _ _) source ifaces modul =
1100 name = Src.getName modul
1102 case Compile.compile pkg ifaces modul of
1103 Right (Compile.Artifacts canonical annotations objects) ->
1104 ROutsideOk name (I.fromModule pkg canonical annotations) objects
1108 Error.Module name path time source errors
1116 = Inside ModuleName.Raw
1117 | Outside ModuleName.Raw I.Interface Opt.LocalGraph
1120toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either Exit.BuildProblem Artifacts
1121toArtifacts (Env _ _ pkg _ _ _) foreigns results mainResults =
1122 case gatherProblemsOrMains results mainResults of
1123 Left (NE.List e es) ->
1124 Left (Exit.BuildBadModules e es)
1127 Right $ Artifacts pkg foreigns mains $
1128 Map.foldrWithKey addInside (foldr addOutside [] mainResults) results
1131gatherProblemsOrMains :: Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either (NE.List Error.Module) (NE.List Main)
1132gatherProblemsOrMains results (NE.List mainResult mainResults) =
1134 sortMain result (es, mains) =
1136 RInside n -> ( es, Inside n : mains)
1137 ROutsideOk n i o -> ( es, Outside n i o : mains)
1138 ROutsideErr e -> (e:es, mains)
1139 ROutsideBlocked -> ( es, mains)
1141 errors = Map.foldr addErrors [] results
1143 case (mainResult, foldr sortMain (errors, []) mainResults) of
1144 (RInside n , ( [], ms)) -> Right (NE.List (Inside n) ms)
1145 (RInside _ , (e:es, _ )) -> Left (NE.List e es)
1146 (ROutsideOk n i o, ( [], ms)) -> Right (NE.List (Outside n i o) ms)
1147 (ROutsideOk _ _ _, (e:es, _ )) -> Left (NE.List e es)
1148 (ROutsideErr e , ( es, _ )) -> Left (NE.List e es)
1149 (ROutsideBlocked , ( [], _ )) -> error "seems like elm-stuff/ is corrupted"
1150 (ROutsideBlocked , (e:es, _ )) -> Left (NE.List e es)
1153addInside :: ModuleName.Raw -> Result -> [Module] -> [Module]
1154addInside name result modules =
1156 RNew _ iface objs _ -> Fresh name iface objs : modules
1157 RSame _ iface objs _ -> Fresh name iface objs : modules
1158 RCached main mvar -> Cached name main mvar : modules
1159 RNotFound _ -> error (badInside name)
1160 RProblem _ -> error (badInside name)
1161 RBlocked -> error (badInside name)
1162 RForeign _ -> modules
1166badInside :: ModuleName.Raw -> [Char]
1168 "Error from `" ++ Name.toChars name ++ "` should have been reported already."
1171addOutside :: MainResult -> [Module] -> [Module]
1172addOutside main modules =
1174 RInside _ -> modules
1175 ROutsideOk name iface objs -> Fresh name iface objs : modules
1176 ROutsideErr _ -> modules
1177 ROutsideBlocked -> modules
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