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.Graph as Graph
24import qualified Data.List as List
25import qualified Data.Map.Utils as Map
26import qualified Data.Map.Strict as Map
27import Data.Map.Strict ((!))
28import qualified Data.Maybe as Maybe
29import qualified Data.Name as Name
30import qualified Data.NonEmptyList as NE
31import qualified Data.OneOrMore as OneOrMore
32import qualified Data.Set as Set
33import qualified System.Directory as Dir
34import qualified System.FilePath as FP
35import System.FilePath ((</>), (<.>))
37import qualified AST.Canonical as Can
38import qualified AST.Source as Src
39import qualified AST.Optimized as Opt
40import qualified Compile
41import qualified Elm.Details as Details
42import qualified Elm.Docs as Docs
43import qualified Elm.Interface as I
44import qualified Elm.ModuleName as ModuleName
45import qualified Elm.Package as Pkg
47import qualified Json.Encode as E
48import qualified Parse.Module as Parse
49import qualified Reporting
50import qualified Reporting.Annotation as A
51import qualified Reporting.Error as Error
52import qualified Reporting.Error.Syntax as Syntax
53import qualified Reporting.Error.Import as Import
54import qualified Reporting.Exit as Exit
55import qualified Reporting.Render.Type.Localizer as L
65 { _key :: Reporting.BKey
68 , _srcDirs :: [FilePath]
69 , _locals :: Map.Map ModuleName.Raw Details.Local
70 , _foreigns :: Map.Map ModuleName.Raw Details.Foreign
74makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> Env
75makeEnv key root (Details.Details _ validOutline locals foreigns _) =
77 Details.ValidApp srcDirs ->
78 Env key root Pkg.dummyName (NE.toList srcDirs) locals foreigns
80 Details.ValidPkg pkg _ _ ->
81 Env key root pkg ["src"] locals foreigns
88-- PERF try using IORef semephore on file crawl phase?
89-- described in Chapter 13 of Parallel and Concurrent Programming in Haskell by Simon Marlow
90-- https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch13.html#sec_conc-par-overhead
92fork :: IO a -> IO (MVar a)
94 do mvar <- newEmptyMVar
95 _ <- forkIO $ putMVar mvar =<< work
99{-# INLINE forkWithKey #-}
100forkWithKey :: (k -> a -> IO b) -> Map.Map k a -> IO (Map.Map k (MVar b))
101forkWithKey func dict =
102 Map.traverseWithKey (\k v -> fork (func k v)) dict
109fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
110fromExposed style root details docsGoal exposed@(NE.List e es) =
111 Reporting.trackBuild style $ \key ->
112 do let env = makeEnv key root details
113 dmvar <- Details.loadInterfaces root details
117 let docsNeed = toDocsNeed docsGoal
118 roots <- Map.fromKeysA (fork . crawlModule env mvar docsNeed) (e:es)
121 statuses <- traverse readMVar =<< readMVar mvar
124 midpoint <- checkMidpoint dmvar statuses
127 return (Left (Exit.BuildProjectProblem problem))
130 do rmvar <- newEmptyMVar
131 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
132 putMVar rmvar resultMVars
133 results <- traverse readMVar resultMVars
134 writeDetails root details results
135 finalizeExposed docsGoal exposed results
145 , _deps :: Dependencies
146 , _mains :: NE.List Main
147 , _modules :: [Module]
152 = Fresh ModuleName.Raw I.Interface Opt.LocalGraph
153 | Cached ModuleName.Raw Bool (MVar CachedInterface)
157 Map.Map ModuleName.Canonical I.DependencyInterface
160fromMains :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
161fromMains style root details paths =
162 Reporting.trackBuild style $ \key ->
163 do let env = makeEnv key root details
165 elmains <- findMains env paths
168 return (Left (Exit.BuildProjectProblem problem))
172 dmvar <- Details.loadInterfaces root details
173 smvar <- newMVar Map.empty
174 smainMVars <- traverse (fork . crawlMain env smvar) lmains
175 smains <- traverse readMVar smainMVars
176 statuses <- traverse readMVar =<< readMVar smvar
178 midpoint <- checkMainsMidpoint dmvar statuses smains
181 return (Left (Exit.BuildProjectProblem problem))
185 rmvar <- newEmptyMVar
186 resultsMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
187 putMVar rmvar resultsMVars
188 rmainMVars <- traverse (fork . checkMain env resultsMVars) smains
189 results <- traverse readMVar resultsMVars
190 writeDetails root details results
191 toArtifacts env foreigns results <$> traverse readMVar rmainMVars
198getMainNames :: Artifacts -> NE.List ModuleName.Raw
199getMainNames (Artifacts _ _ mains _) =
200 fmap getMainName mains
203getMainName :: Main -> ModuleName.Raw
207 Outside name _ _ -> name
215 Map.Map ModuleName.Raw (MVar Status)
219 = SCached Details.Local
220 | SChanged Details.Local B.ByteString Src.Module DocsNeed
221 | SBadImport Import.Problem
222 | SBadSyntax FilePath File.Time B.ByteString Syntax.Error
227crawlDeps :: Env -> MVar StatusDict -> [ModuleName.Raw] -> a -> IO a
228crawlDeps env mvar deps blockedValue =
229 do statusDict <- takeMVar mvar
230 let depsDict = Map.fromKeys (\_ -> ()) deps
231 let newsDict = Map.difference depsDict statusDict
232 statuses <- Map.traverseWithKey crawlNew newsDict
233 putMVar mvar (Map.union statuses statusDict)
234 mapM_ readMVar statuses
237 crawlNew name () = fork (crawlModule env mvar (DocsNeed False) name)
240crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
241crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
242 do let fileName = ModuleName.toFilePath name <.> "elm"
243 let inRoot path = File.exists (root </> path)
245 paths <- filterM inRoot (map (</> fileName) srcDirs)
249 case Map.lookup name foreigns of
250 Just (Details.Foreign dep deps) ->
251 return $ SBadImport $ Import.Ambiguous path [] dep deps
254 case Map.lookup name locals of
256 crawlFile env mvar docsNeed name path
258 Just local@(Details.Local oldPath oldTime deps _) ->
260 then crawlFile env mvar docsNeed name path
262 do newTime <- File.getTime path
263 if oldTime < newTime || needsDocs docsNeed
264 then crawlFile env mvar docsNeed name path
265 else crawlDeps env mvar deps (SCached local)
268 return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
271 case Map.lookup name foreigns of
272 Just (Details.Foreign dep deps) ->
275 return $ SForeign dep
278 return $ SBadImport $ Import.AmbiguousForeign dep d ds
281 if Name.isKernel name && Pkg.isKernel pkg then
282 do exists <- File.exists ("src" </> ModuleName.toFilePath name <.> "js")
283 return $ if exists then SKernel else SBadImport Import.NotFound
285 return $ SBadImport Import.NotFound
288crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> IO Status
289crawlFile env@(Env _ root pkg _ _ _) mvar docsNeed expectedName path =
290 do time <- File.getTime path
291 source <- File.readUtf8 (root </> path)
293 case Parse.fromByteString pkg source of
295 return $ SBadSyntax path time source err
297 Right modul@(Src.Module maybeActualName _ _ imports values _ _ _ _) ->
298 case maybeActualName of
300 return $ SBadSyntax path time source (Syntax.ModuleNameUnspecified expectedName)
302 Just name@(A.At _ actualName) ->
303 if expectedName == actualName then
305 deps = map Src.getImportName imports
306 local = Details.Local path time deps (any isMain values)
308 crawlDeps env mvar deps (SChanged local source modul docsNeed)
310 return $ SBadSyntax path time source (Syntax.ModuleNameMismatch expectedName name)
313isMain :: A.Located Src.Value -> Bool
314isMain (A.At _ (Src.Value (A.At _ name) _ _ _)) =
323 Map.Map ModuleName.Raw (MVar Result)
327 = RNew !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
328 | RSame !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
329 | RCached Bool (MVar CachedInterface)
330 | RNotFound Import.Problem
331 | RProblem Error.Module
333 | RForeign I.Interface
343checkModule :: Env -> Dependencies -> MVar ResultDict -> ModuleName.Raw -> Status -> IO Result
344checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
346 SCached local@(Details.Local path time deps hasMain) ->
347 do results <- readMVar resultsMVar
348 depsStatus <- checkDeps root results deps
351 do source <- File.readUtf8 path
352 case Parse.fromByteString pkg source of
353 Right modul -> compile env (DocsNeed False) local source ifaces modul
356 Error.Module name path time source (Error.BadSyntax err)
359 do mvar <- newMVar Unneeded
360 return (RCached hasMain mvar)
365 DepsNotFound problems ->
366 do source <- File.readUtf8 path
367 return $ RProblem $ Error.Module name path time source $
368 case Parse.fromByteString pkg source of
369 Right (Src.Module _ _ _ imports _ _ _ _ _) ->
370 Error.BadImports (toImportErrors env results imports problems)
375 SChanged local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
376 do results <- readMVar resultsMVar
377 depsStatus <- checkDeps root results deps
380 compile env docsNeed local source ifaces modul
382 DepsSame same cached ->
383 do maybeLoaded <- loadInterfaces root same cached
385 Nothing -> return RBlocked
386 Just ifaces -> compile env docsNeed local source ifaces modul
391 DepsNotFound problems ->
392 return $ RProblem $ Error.Module name path time source $
393 Error.BadImports (toImportErrors env results imports problems)
395 SBadImport importProblem ->
396 return (RNotFound importProblem)
398 SBadSyntax path time source err ->
399 return $ RProblem $ Error.Module name path time source $
403 case foreigns ! ModuleName.Canonical home name of
404 I.Public iface -> return (RForeign iface)
405 I.Private _ _ _ -> error $ "mistakenly seeing private interface for " ++ Pkg.toChars home ++ " " ++ ModuleName.toChars name
416 = DepsChange (Map.Map ModuleName.Raw I.Interface)
417 | DepsSame [Dep] [CDep]
419 | DepsNotFound (NE.List (ModuleName.Raw, Import.Problem))
422checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> IO DepsStatus
423checkDeps root results deps =
424 checkDepsHelp root results deps [] [] [] [] False
427type Dep = (ModuleName.Raw, I.Interface)
428type CDep = (ModuleName.Raw, MVar CachedInterface)
431checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> IO DepsStatus
432checkDepsHelp root results deps new same cached importProblems isBlocked =
435 do result <- readMVar (results ! dep)
437 RNew _ iface _ _ -> checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked
438 RSame _ iface _ _ -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
439 RCached _ mvar -> checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked
440 RNotFound prob -> checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True
441 RProblem _ -> checkDepsHelp root results otherDeps new same cached importProblems True
442 RBlocked -> checkDepsHelp root results otherDeps new same cached importProblems True
443 RForeign iface -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
444 RKernel -> checkDepsHelp root results otherDeps new same cached importProblems isBlocked
447 case reverse importProblems of
449 return $ DepsNotFound (NE.List p ps)
455 else if null new then
456 return $ DepsSame same cached
459 do maybeLoaded <- loadInterfaces root same cached
461 Nothing -> return DepsBlock
462 Just ifaces -> return $ DepsChange $ Map.union (Map.fromList new) ifaces
469toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
470toImportErrors (Env _ _ _ _ locals foreigns) results imports problems =
474 [ Map.keysSet foreigns
476 , Map.keysSet results
480 Set.difference knownModules (Set.fromList (map Src.getImportName imports))
483 Map.fromList (map (\(Src.Import (A.At region name) _ _) -> (name, region)) imports)
485 toError (name, problem) =
486 Import.Error (regionDict ! name) name unimportedModules problem
488 fmap toError problems
492-- LOAD CACHED INTERFACES
495loadInterfaces :: FilePath -> [Dep] -> [CDep] -> IO (Maybe (Map.Map ModuleName.Raw I.Interface))
496loadInterfaces root same cached =
497 do loading <- traverse (fork . loadInterface root) cached
498 maybeLoaded <- traverse readMVar loading
499 case sequence maybeLoaded of
504 return $ Just $ Map.union (Map.fromList loaded) (Map.fromList same)
507loadInterface :: FilePath -> CDep -> IO (Maybe Dep)
508loadInterface root (name, ciMvar) =
509 do cachedInterface <- takeMVar ciMvar
510 case cachedInterface of
512 do putMVar ciMvar cachedInterface
516 do putMVar ciMvar cachedInterface
517 return (Just (name, iface))
520 do maybeIface <- File.readBinary (Stuff.elmi root name)
523 do putMVar ciMvar Corrupted
527 do putMVar ciMvar (Loaded iface)
528 return (Just (name, iface))
535checkMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> IO (Either Exit.BuildProjectProblem Dependencies)
536checkMidpoint dmvar statuses =
537 case checkForCycles statuses of
539 do maybeForeigns <- readMVar dmvar
540 case maybeForeigns of
541 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
542 Just fs -> return (Right fs)
544 Just (NE.List name names) ->
545 do _ <- readMVar dmvar
546 return (Left (Exit.BP_Cycle name names))
549checkMainsMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> NE.List MainStatus -> IO (Either Exit.BuildProjectProblem Dependencies)
550checkMainsMidpoint dmvar statuses smains =
551 case checkForCycles statuses of
553 case checkUniqueMains statuses smains of
555 do maybeForeigns <- readMVar dmvar
556 case maybeForeigns of
557 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
558 Just fs -> return (Right fs)
561 do _ <- readMVar dmvar
562 return (Left problem)
564 Just (NE.List name names) ->
565 do _ <- readMVar dmvar
566 return (Left (Exit.BP_Cycle name names))
573checkForCycles :: Map.Map ModuleName.Raw Status -> Maybe (NE.List ModuleName.Raw)
574checkForCycles modules =
576 !graph = Map.foldrWithKey addToGraph [] modules
577 !sccs = Graph.stronglyConnComp graph
579 checkForCyclesHelp sccs
582checkForCyclesHelp :: [Graph.SCC ModuleName.Raw] -> Maybe (NE.List ModuleName.Raw)
583checkForCyclesHelp sccs =
590 Graph.AcyclicSCC _ -> checkForCyclesHelp otherSccs
591 Graph.CyclicSCC [] -> checkForCyclesHelp otherSccs
592 Graph.CyclicSCC (m:ms) -> Just (NE.List m ms)
596 ( ModuleName.Raw, ModuleName.Raw, [ModuleName.Raw] )
599addToGraph :: ModuleName.Raw -> Status -> [Node] -> [Node]
600addToGraph name status graph =
604 SCached (Details.Local _ _ deps _) -> deps
605 SChanged (Details.Local _ _ deps _) _ _ _ -> deps
607 SBadSyntax _ _ _ _ -> []
611 (name, name, dependencies) : graph
618checkUniqueMains :: Map.Map ModuleName.Raw Status -> NE.List MainStatus -> Maybe Exit.BuildProjectProblem
619checkUniqueMains insides smains =
622 Map.fromListWith OneOrMore.more (Maybe.mapMaybe mainStatusToNamePathPair (NE.toList smains))
624 case Map.traverseWithKey checkOutside outsidesDict of
629 case sequence_ (Map.intersectionWithKey checkInside outsides insides) of
631 Left problem -> Just problem
634mainStatusToNamePathPair :: MainStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
635mainStatusToNamePathPair smain =
638 SOutsideOk (Details.Local path _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
639 SOutsideErr _ -> Nothing
642checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
643checkOutside name paths =
644 case OneOrMore.destruct NE.List paths of
645 NE.List p [] -> Right p
646 NE.List p1 (p2:_) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
649checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
650checkInside name p1 status =
652 SCached (Details.Local p2 _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
653 SChanged (Details.Local p2 _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
654 SBadImport _ -> Right ()
655 SBadSyntax _ _ _ _ -> Right ()
656 SForeign _ -> Right ()
664compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
665compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) source ifaces modul =
666 case Compile.compile pkg ifaces modul of
667 Right (Compile.Artifacts canonical annotations objects) ->
668 do let name = Src.getName modul
669 let iface = I.fromModule pkg canonical annotations
670 let docs = makeDocs docsNeed canonical
671 let elmi = Stuff.elmi root name
672 File.writeBinary (Stuff.elmo root name) objects
673 maybeOldi <- File.readBinary elmi
675 Just oldi | oldi == iface ->
676 do -- iface should be fully forced by equality check
677 Reporting.report key Reporting.BDone
678 return (RSame local iface objects docs)
681 do -- iface may be lazy still
682 File.writeBinary elmi iface
683 Reporting.report key Reporting.BDone
684 return (RNew local iface objects docs)
688 Error.Module (Src.getName modul) path time source err
695writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
696writeDetails root (Details.Details time outline locals foreigns extras) results =
697 File.writeBinary (Stuff.details root) $
698 Details.Details time outline (Map.foldrWithKey addNewLocal locals results) foreigns extras
701addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
702addNewLocal name result locals =
704 RNew local _ _ _ -> Map.insert name local locals
705 RSame local _ _ _ -> Map.insert name local locals
706 RCached _ _ -> locals
707 RNotFound _ -> locals
718finalizeExposed :: DocsGoal docs -> NE.List ModuleName.Raw -> Map.Map ModuleName.Raw Result -> IO (Either Exit.BuildProblem docs)
719finalizeExposed docsGoal exposed results =
720 case foldr (addImportProblems results) [] (NE.toList exposed) of
722 return $ Left $ Exit.BuildProjectProblem (Exit.BP_MissingExposed (NE.List p ps))
725 case Map.foldr addErrors [] results of
726 [] -> Right <$> finalizeDocs docsGoal results
727 e:es -> return $ Left $ Exit.BuildBadModules e es
730addErrors :: Result -> [Error.Module] -> [Error.Module]
731addErrors result errors =
733 RNew _ _ _ _ -> errors
734 RSame _ _ _ _ -> errors
735 RCached _ _ -> errors
736 RNotFound _ -> errors
737 RProblem e -> e:errors
743addImportProblems :: Map.Map ModuleName.Raw Result -> ModuleName.Raw -> [(ModuleName.Raw, Import.Problem)] -> [(ModuleName.Raw, Import.Problem)]
744addImportProblems results name problems =
745 case results ! name of
746 RNew _ _ _ _ -> problems
747 RSame _ _ _ _ -> problems
748 RCached _ _ -> problems
749 RNotFound p -> (name, p) : problems
750 RProblem _ -> problems
752 RForeign _ -> problems
761 KeepDocs :: DocsGoal Docs.Documentation
762 WriteDocs :: FilePath -> DocsGoal ()
763 IgnoreDocs :: DocsGoal ()
767 DocsNeed { needsDocs :: Bool }
770toDocsNeed :: DocsGoal a -> DocsNeed
773 IgnoreDocs -> DocsNeed False
774 WriteDocs _ -> DocsNeed True
775 KeepDocs -> DocsNeed True
778makeDocs :: DocsNeed -> Can.Module -> Maybe Docs.Module
779makeDocs (DocsNeed isNeeded) modul =
781 case Docs.fromModule modul of
782 Right docs -> Just docs
788finalizeDocs :: DocsGoal docs -> Map.Map ModuleName.Raw Result -> IO docs
789finalizeDocs goal results =
792 return $ Map.mapMaybe toDocs results
795 E.writeUgly path $ Docs.encode $ Map.mapMaybe toDocs results
801toDocs :: Result -> Maybe Docs.Module
806 RCached _ _ -> Nothing
807 RNotFound _ -> Nothing
808 RProblem _ -> Nothing
810 RForeign _ -> Nothing
815--------------------------------------------------------------------------------
816------ NOW FOR SOME REPL STUFF -------------------------------------------------
817--------------------------------------------------------------------------------
825 { _repl_home :: ModuleName.Canonical
826 , _repl_modules :: [Module]
827 , _repl_localizer :: L.Localizer
828 , _repl_annotations :: Map.Map Name.Name Can.Annotation
832fromRepl :: FilePath -> Details.Details -> B.ByteString -> IO (Either Exit.Repl ReplArtifacts)
833fromRepl root details source =
835 env@(Env _ _ pkg _ _ _) = makeEnv Reporting.ignorer root details
837 case Parse.fromByteString pkg source of
839 return $ Left $ Exit.ReplBadInput source $ Error.BadSyntax syntaxError
841 Right modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
842 do dmvar <- Details.loadInterfaces root details
844 let deps = map Src.getImportName imports
845 mvar <- newMVar Map.empty
846 crawlDeps env mvar deps ()
848 statuses <- traverse readMVar =<< readMVar mvar
849 midpoint <- checkMidpoint dmvar statuses
853 return $ Left $ Exit.ReplProjectProblem problem
856 do rmvar <- newEmptyMVar
857 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
858 putMVar rmvar resultMVars
859 results <- traverse readMVar resultMVars
860 writeDetails root details results
861 depsStatus <- checkDeps root resultMVars deps
862 finalizeReplArtifacts env source modul depsStatus resultMVars results
865finalizeReplArtifacts :: Env -> B.ByteString -> Src.Module -> DepsStatus -> ResultDict -> Map.Map ModuleName.Raw Result -> IO (Either Exit.Repl ReplArtifacts)
866finalizeReplArtifacts env@(Env _ root pkg _ _ _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) depsStatus resultMVars results =
868 compileInput ifaces =
869 case Compile.compile pkg ifaces modul of
870 Right (Compile.Artifacts canonical annotations objects) ->
872 h = Can._name canonical
873 m = Fresh (Src.getName modul) (I.fromModule pkg canonical annotations) objects
874 ms = Map.foldrWithKey addInside [] results
876 return $ Right $ ReplArtifacts h (m:ms) (L.fromModule modul) annotations
879 return $ Left $ Exit.ReplBadInput source errors
885 DepsSame same cached ->
886 do maybeLoaded <- loadInterfaces root same cached
888 Just ifaces -> compileInput ifaces
889 Nothing -> return $ Left $ Exit.ReplBadCache
892 case Map.foldr addErrors [] results of
893 [] -> return $ Left $ Exit.ReplBlocked
894 e:es -> return $ Left $ Exit.ReplBadLocalDeps e es
896 DepsNotFound problems ->
897 return $ Left $ Exit.ReplBadInput source $ Error.BadImports $
898 toImportErrors env resultMVars imports problems
902--------------------------------------------------------------------------------
903--------------------------------------------------------------------------------
904------ AFTER THIS, EVERYTHING IS ABOUT HANDLING MODULES GIVEN BY FILEPATH ------
905--------------------------------------------------------------------------------
906--------------------------------------------------------------------------------
914 = LInside ModuleName.Raw
918findMains :: Env -> NE.List FilePath -> IO (Either Exit.BuildProjectProblem (NE.List MainLocation))
920 do mvars <- traverse (fork . findLocation env) paths
921 elocs <- traverse readMVar mvars
922 return $ checkLocations =<< sequence elocs
925checkLocations :: NE.List Location -> Either Exit.BuildProjectProblem (NE.List MainLocation)
926checkLocations locations =
928 toOneOrMore loc@(Location absolute _ _) =
929 (absolute, OneOrMore.one loc)
931 fromOneOrMore loc locs =
934 loc2:_ -> Left (Exit.BP_MainPathDuplicate (_relative loc) (_relative loc2))
936 fmap (\_ -> fmap _location locations) $
937 traverse (OneOrMore.destruct fromOneOrMore) $
938 Map.fromListWith OneOrMore.more $ map toOneOrMore (NE.toList locations)
947 { _absolute :: FilePath
948 , _relative :: FilePath
949 , _location :: MainLocation
953findLocation :: Env -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
954findLocation env path =
955 do exists <- File.exists path
957 then findLoc env path =<< Dir.canonicalizePath path
958 else return (Left (Exit.BP_PathUnknown path))
961findLoc :: Env -> FilePath -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
962findLoc (Env _ root _ srcDirs _ _) path absolutePath =
964 (dirs, file) = FP.splitFileName absolutePath
965 (final, ext) = FP.splitExtension file
969 return $ Left $ Exit.BP_WithBadExtension path
972 roots = FP.splitDirectories root
973 segments = FP.splitDirectories dirs ++ [final]
975 case dropPrefix roots segments of
977 return $ Right $ Location absolutePath path (LOutside path)
979 Just relativeSegments ->
980 case Maybe.mapMaybe (isInsideSrcDirByPath relativeSegments) srcDirs of
982 return $ Right $ Location absolutePath path (LOutside path)
984 [(_, Right names)] ->
985 do let name = Name.fromChars (List.intercalate "." names)
986 dirs <- filterM (isInsideSrcDirByName root names) srcDirs
989 do let p1 = d1 </> FP.joinPath names <.> "elm"
990 let p2 = d2 </> FP.joinPath names <.> "elm"
991 return $ Left $ Exit.BP_MainNameDuplicate name p1 p2
994 return $ Right $ Location absolutePath path (LInside name)
997 return $ Left $ Exit.BP_MainNameInvalid path s names
1000 return $ Left $ Exit.BP_WithAmbiguousSrcDir path s1 s2
1004isInsideSrcDirByName :: FilePath -> [String] -> FilePath -> IO Bool
1005isInsideSrcDirByName root names srcDir =
1006 File.exists (root </> srcDir </> FP.joinPath names <.> "elm")
1009isInsideSrcDirByPath :: [String] -> FilePath -> Maybe (FilePath, Either [String] [String])
1010isInsideSrcDirByPath segments srcDir =
1011 case dropPrefix (FP.splitDirectories srcDir) segments of
1016 if all isGoodName names
1017 then Just (srcDir, Right names)
1018 else Just (srcDir, Left names)
1021isGoodName :: [Char] -> Bool
1028 Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
1031dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
1032dropPrefix roots paths =
1040 p:ps -> if r == p then dropPrefix rs ps else Nothing
1048 = SInside ModuleName.Raw
1049 | SOutsideOk Details.Local B.ByteString Src.Module
1050 | SOutsideErr Error.Module
1053crawlMain :: Env -> MVar StatusDict -> MainLocation -> IO MainStatus
1054crawlMain env@(Env _ _ pkg _ _ _) mvar given =
1057 do statusMVar <- newEmptyMVar
1058 statusDict <- takeMVar mvar
1059 putMVar mvar (Map.insert name statusMVar statusDict)
1060 putMVar statusMVar =<< crawlModule env mvar (DocsNeed False) name
1061 return (SInside name)
1064 do time <- File.getTime path
1065 source <- File.readUtf8 path
1066 case Parse.fromByteString pkg source of
1067 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
1068 do let deps = map Src.getImportName imports
1069 let local = Details.Local path time deps (any isMain values)
1070 crawlDeps env mvar deps (SOutsideOk local source modul)
1073 return $ SOutsideErr $
1074 Error.Module "???" path time source (Error.BadSyntax syntaxError)
1082 = RInside ModuleName.Raw
1083 | ROutsideOk ModuleName.Raw I.Interface Opt.LocalGraph
1084 | ROutsideErr Error.Module
1088checkMain :: Env -> ResultDict -> MainStatus -> IO MainResult
1089checkMain env@(Env _ root _ _ _ _) results pendingMain =
1092 return (RInside name)
1095 return (ROutsideErr err)
1097 SOutsideOk local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
1098 do depsStatus <- checkDeps root results deps
1100 DepsChange ifaces ->
1101 compileOutside env local source ifaces modul
1103 DepsSame same cached ->
1104 do maybeLoaded <- loadInterfaces root same cached
1106 Nothing -> return ROutsideBlocked
1107 Just ifaces -> compileOutside env local source ifaces modul
1110 return ROutsideBlocked
1112 DepsNotFound problems ->
1113 return $ ROutsideErr $ Error.Module (Src.getName modul) path time source $
1114 Error.BadImports (toImportErrors env results imports problems)
1117compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO MainResult
1118compileOutside (Env key _ pkg _ _ _) (Details.Local path time _ _) source ifaces modul =
1120 name = Src.getName modul
1122 case Compile.compile pkg ifaces modul of
1123 Right (Compile.Artifacts canonical annotations objects) ->
1124 do Reporting.report key Reporting.BDone
1125 return $ ROutsideOk name (I.fromModule pkg canonical annotations) objects
1128 return $ ROutsideErr $ Error.Module name path time source errors
1136 = Inside ModuleName.Raw
1137 | Outside ModuleName.Raw I.Interface Opt.LocalGraph
1140toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either Exit.BuildProblem Artifacts
1141toArtifacts (Env _ _ pkg _ _ _) foreigns results mainResults =
1142 case gatherProblemsOrMains results mainResults of
1143 Left (NE.List e es) ->
1144 Left (Exit.BuildBadModules e es)
1147 Right $ Artifacts pkg foreigns mains $
1148 Map.foldrWithKey addInside (foldr addOutside [] mainResults) results
1151gatherProblemsOrMains :: Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either (NE.List Error.Module) (NE.List Main)
1152gatherProblemsOrMains results (NE.List mainResult mainResults) =
1154 sortMain result (es, mains) =
1156 RInside n -> ( es, Inside n : mains)
1157 ROutsideOk n i o -> ( es, Outside n i o : mains)
1158 ROutsideErr e -> (e:es, mains)
1159 ROutsideBlocked -> ( es, mains)
1161 errors = Map.foldr addErrors [] results
1163 case (mainResult, foldr sortMain (errors, []) mainResults) of
1164 (RInside n , ( [], ms)) -> Right (NE.List (Inside n) ms)
1165 (RInside _ , (e:es, _ )) -> Left (NE.List e es)
1166 (ROutsideOk n i o, ( [], ms)) -> Right (NE.List (Outside n i o) ms)
1167 (ROutsideOk _ _ _, (e:es, _ )) -> Left (NE.List e es)
1168 (ROutsideErr e , ( es, _ )) -> Left (NE.List e es)
1169 (ROutsideBlocked , ( [], _ )) -> error "seems like elm-stuff/ is corrupted"
1170 (ROutsideBlocked , (e:es, _ )) -> Left (NE.List e es)
1173addInside :: ModuleName.Raw -> Result -> [Module] -> [Module]
1174addInside name result modules =
1176 RNew _ iface objs _ -> Fresh name iface objs : modules
1177 RSame _ iface objs _ -> Fresh name iface objs : modules
1178 RCached main mvar -> Cached name main mvar : modules
1179 RNotFound _ -> error (badInside name)
1180 RProblem _ -> error (badInside name)
1181 RBlocked -> error (badInside name)
1182 RForeign _ -> modules
1186badInside :: ModuleName.Raw -> [Char]
1188 "Error from `" ++ Name.toChars name ++ "` should have been reported already."
1191addOutside :: MainResult -> [Module] -> [Module]
1192addOutside main modules =
1194 RInside _ -> modules
1195 ROutsideOk name iface objs -> Fresh name iface objs : modules
1196 ROutsideErr _ -> modules
1197 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