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 , _buildID :: Details.BuildID
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 buildID locals foreigns _) =
78 Details.ValidApp srcDirs ->
79 Env key root Pkg.dummyName (NE.toList srcDirs) buildID locals foreigns
81 Details.ValidPkg pkg _ _ ->
82 Env key root pkg ["src"] buildID locals foreigns
89-- PERF try using IORef semephore on file crawl phase?
90-- described in Chapter 13 of Parallel and Concurrent Programming in Haskell by Simon Marlow
91-- https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch13.html#sec_conc-par-overhead
93fork :: IO a -> IO (MVar a)
95 do mvar <- newEmptyMVar
96 _ <- forkIO $ putMVar mvar =<< work
100{-# INLINE forkWithKey #-}
101forkWithKey :: (k -> a -> IO b) -> Map.Map k a -> IO (Map.Map k (MVar b))
102forkWithKey func dict =
103 Map.traverseWithKey (\k v -> fork (func k v)) dict
110fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
111fromExposed style root details docsGoal exposed@(NE.List e es) =
112 Reporting.trackBuild style $ \key ->
113 do let env = makeEnv key root details
114 dmvar <- Details.loadInterfaces root details
118 let docsNeed = toDocsNeed docsGoal
119 roots <- Map.fromKeysA (fork . crawlModule env mvar docsNeed) (e:es)
122 statuses <- traverse readMVar =<< readMVar mvar
125 midpoint <- checkMidpoint dmvar statuses
128 return (Left (Exit.BuildProjectProblem problem))
131 do rmvar <- newEmptyMVar
132 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
133 putMVar rmvar resultMVars
134 results <- traverse readMVar resultMVars
135 writeDetails root details results
136 finalizeExposed docsGoal exposed results
146 , _deps :: Dependencies
147 , _mains :: NE.List Main
148 , _modules :: [Module]
153 = Fresh ModuleName.Raw I.Interface Opt.LocalGraph
154 | Cached ModuleName.Raw Bool (MVar CachedInterface)
158 Map.Map ModuleName.Canonical I.DependencyInterface
161fromMains :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
162fromMains style root details paths =
163 Reporting.trackBuild style $ \key ->
164 do let env = makeEnv key root details
166 elmains <- findMains env paths
169 return (Left (Exit.BuildProjectProblem problem))
173 dmvar <- Details.loadInterfaces root details
174 smvar <- newMVar Map.empty
175 smainMVars <- traverse (fork . crawlMain env smvar) lmains
176 smains <- traverse readMVar smainMVars
177 statuses <- traverse readMVar =<< readMVar smvar
179 midpoint <- checkMainsMidpoint dmvar statuses smains
182 return (Left (Exit.BuildProjectProblem problem))
186 rmvar <- newEmptyMVar
187 resultsMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
188 putMVar rmvar resultsMVars
189 rmainMVars <- traverse (fork . checkMain env resultsMVars) smains
190 results <- traverse readMVar resultsMVars
191 writeDetails root details results
192 toArtifacts env foreigns results <$> traverse readMVar rmainMVars
199getMainNames :: Artifacts -> NE.List ModuleName.Raw
200getMainNames (Artifacts _ _ mains _) =
201 fmap getMainName mains
204getMainName :: Main -> ModuleName.Raw
208 Outside name _ _ -> name
216 Map.Map ModuleName.Raw (MVar Status)
220 = SCached Details.Local
221 | SChanged Details.Local B.ByteString Src.Module DocsNeed
222 | SBadImport Import.Problem
223 | SBadSyntax FilePath File.Time B.ByteString Syntax.Error
228crawlDeps :: Env -> MVar StatusDict -> [ModuleName.Raw] -> a -> IO a
229crawlDeps env mvar deps blockedValue =
230 do statusDict <- takeMVar mvar
231 let depsDict = Map.fromKeys (\_ -> ()) deps
232 let newsDict = Map.difference depsDict statusDict
233 statuses <- Map.traverseWithKey crawlNew newsDict
234 putMVar mvar (Map.union statuses statusDict)
235 mapM_ readMVar statuses
238 crawlNew name () = fork (crawlModule env mvar (DocsNeed False) name)
241crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
242crawlModule env@(Env _ root pkg srcDirs buildID locals foreigns) mvar docsNeed name =
243 do let fileName = ModuleName.toFilePath name <.> "elm"
244 let inRoot path = File.exists (root </> path)
246 paths <- filterM inRoot (map (</> fileName) srcDirs)
250 case Map.lookup name foreigns of
251 Just (Details.Foreign dep deps) ->
252 return $ SBadImport $ Import.Ambiguous path [] dep deps
255 do newTime <- File.getTime path
256 case Map.lookup name locals of
258 crawlFile env mvar docsNeed name path newTime buildID
260 Just local@(Details.Local oldPath oldTime deps _ lastChange _) ->
261 if path /= oldPath || oldTime /= newTime || needsDocs docsNeed
262 then crawlFile env mvar docsNeed name path newTime lastChange
263 else crawlDeps env mvar deps (SCached local)
266 return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
269 case Map.lookup name foreigns of
270 Just (Details.Foreign dep deps) ->
273 return $ SForeign dep
276 return $ SBadImport $ Import.AmbiguousForeign dep d ds
279 if Name.isKernel name && Pkg.isKernel pkg then
280 do exists <- File.exists ("src" </> ModuleName.toFilePath name <.> "js")
281 return $ if exists then SKernel else SBadImport Import.NotFound
283 return $ SBadImport Import.NotFound
286crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> File.Time -> Details.BuildID -> IO Status
287crawlFile env@(Env _ root pkg _ buildID _ _) mvar docsNeed expectedName path time lastChange =
288 do 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) lastChange buildID
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 Details.BuildID (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 lastChange lastCompile) ->
344 do results <- readMVar resultsMVar
345 depsStatus <- checkDeps root results deps lastCompile
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 lastChange 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 _ _ lastCompile) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
373 do results <- readMVar resultsMVar
374 depsStatus <- checkDeps root results deps lastCompile
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 $ "mistakenly seeing private interface for " ++ Pkg.toChars home ++ " " ++ ModuleName.toChars name
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] -> Details.BuildID -> IO DepsStatus
420checkDeps root results deps lastCompile =
421 checkDepsHelp root results deps [] [] [] [] False 0 lastCompile
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 -> Details.BuildID -> Details.BuildID -> IO DepsStatus
429checkDepsHelp root results deps new same cached importProblems isBlocked lastDepChange lastCompile =
432 do result <- readMVar (results ! dep)
434 RNew (Details.Local _ _ _ _ lastChange _) iface _ _ ->
435 checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked (max lastChange lastDepChange) lastCompile
437 RSame (Details.Local _ _ _ _ lastChange _) iface _ _ ->
438 checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked (max lastChange lastDepChange) lastCompile
440 RCached _ lastChange mvar ->
441 checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked (max lastChange lastDepChange) lastCompile
444 checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True lastDepChange lastCompile
447 checkDepsHelp root results otherDeps new same cached importProblems True lastDepChange lastCompile
450 checkDepsHelp root results otherDeps new same cached importProblems True lastDepChange lastCompile
453 checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked lastDepChange lastCompile
456 checkDepsHelp root results otherDeps new same cached importProblems isBlocked lastDepChange lastCompile
460 case reverse importProblems of
462 return $ DepsNotFound (NE.List p ps)
468 else if null new && lastDepChange <= lastCompile then
469 return $ DepsSame same cached
472 do maybeLoaded <- loadInterfaces root same cached
474 Nothing -> return DepsBlock
475 Just ifaces -> return $ DepsChange $ Map.union (Map.fromList new) ifaces
482toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
483toImportErrors (Env _ _ _ _ _ locals foreigns) results imports problems =
487 [ Map.keysSet foreigns
489 , Map.keysSet results
493 Set.difference knownModules (Set.fromList (map Src.getImportName imports))
496 Map.fromList (map (\(Src.Import (A.At region name) _ _) -> (name, region)) imports)
498 toError (name, problem) =
499 Import.Error (regionDict ! name) name unimportedModules problem
501 fmap toError problems
505-- LOAD CACHED INTERFACES
508loadInterfaces :: FilePath -> [Dep] -> [CDep] -> IO (Maybe (Map.Map ModuleName.Raw I.Interface))
509loadInterfaces root same cached =
510 do loading <- traverse (fork . loadInterface root) cached
511 maybeLoaded <- traverse readMVar loading
512 case sequence maybeLoaded of
517 return $ Just $ Map.union (Map.fromList loaded) (Map.fromList same)
520loadInterface :: FilePath -> CDep -> IO (Maybe Dep)
521loadInterface root (name, ciMvar) =
522 do cachedInterface <- takeMVar ciMvar
523 case cachedInterface of
525 do putMVar ciMvar cachedInterface
529 do putMVar ciMvar cachedInterface
530 return (Just (name, iface))
533 do maybeIface <- File.readBinary (Stuff.elmi root name)
536 do putMVar ciMvar Corrupted
540 do putMVar ciMvar (Loaded iface)
541 return (Just (name, iface))
548checkMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> IO (Either Exit.BuildProjectProblem Dependencies)
549checkMidpoint dmvar statuses =
550 case checkForCycles statuses of
552 do maybeForeigns <- readMVar dmvar
553 case maybeForeigns of
554 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
555 Just fs -> return (Right fs)
557 Just (NE.List name names) ->
558 do _ <- readMVar dmvar
559 return (Left (Exit.BP_Cycle name names))
562checkMainsMidpoint :: MVar (Maybe Dependencies) -> Map.Map ModuleName.Raw Status -> NE.List MainStatus -> IO (Either Exit.BuildProjectProblem Dependencies)
563checkMainsMidpoint dmvar statuses smains =
564 case checkForCycles statuses of
566 case checkUniqueMains statuses smains of
568 do maybeForeigns <- readMVar dmvar
569 case maybeForeigns of
570 Nothing -> return (Left Exit.BP_CannotLoadDependencies)
571 Just fs -> return (Right fs)
574 do _ <- readMVar dmvar
575 return (Left problem)
577 Just (NE.List name names) ->
578 do _ <- readMVar dmvar
579 return (Left (Exit.BP_Cycle name names))
586checkForCycles :: Map.Map ModuleName.Raw Status -> Maybe (NE.List ModuleName.Raw)
587checkForCycles modules =
589 !graph = Map.foldrWithKey addToGraph [] modules
590 !sccs = Graph.stronglyConnComp graph
592 checkForCyclesHelp sccs
595checkForCyclesHelp :: [Graph.SCC ModuleName.Raw] -> Maybe (NE.List ModuleName.Raw)
596checkForCyclesHelp sccs =
603 Graph.AcyclicSCC _ -> checkForCyclesHelp otherSccs
604 Graph.CyclicSCC [] -> checkForCyclesHelp otherSccs
605 Graph.CyclicSCC (m:ms) -> Just (NE.List m ms)
609 ( ModuleName.Raw, ModuleName.Raw, [ModuleName.Raw] )
612addToGraph :: ModuleName.Raw -> Status -> [Node] -> [Node]
613addToGraph name status graph =
617 SCached (Details.Local _ _ deps _ _ _) -> deps
618 SChanged (Details.Local _ _ deps _ _ _) _ _ _ -> deps
620 SBadSyntax _ _ _ _ -> []
624 (name, name, dependencies) : graph
631checkUniqueMains :: Map.Map ModuleName.Raw Status -> NE.List MainStatus -> Maybe Exit.BuildProjectProblem
632checkUniqueMains insides smains =
635 Map.fromListWith OneOrMore.more (Maybe.mapMaybe mainStatusToNamePathPair (NE.toList smains))
637 case Map.traverseWithKey checkOutside outsidesDict of
642 case sequence_ (Map.intersectionWithKey checkInside outsides insides) of
644 Left problem -> Just problem
647mainStatusToNamePathPair :: MainStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
648mainStatusToNamePathPair smain =
651 SOutsideOk (Details.Local path _ _ _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
652 SOutsideErr _ -> Nothing
655checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
656checkOutside name paths =
657 case OneOrMore.destruct NE.List paths of
658 NE.List p [] -> Right p
659 NE.List p1 (p2:_) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
662checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
663checkInside name p1 status =
665 SCached (Details.Local p2 _ _ _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
666 SChanged (Details.Local p2 _ _ _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
667 SBadImport _ -> Right ()
668 SBadSyntax _ _ _ _ -> Right ()
669 SForeign _ -> Right ()
677compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
678compile (Env key root pkg _ buildID _ _) docsNeed (Details.Local path time deps main lastChange _) source ifaces modul =
679 case Compile.compile pkg ifaces modul of
680 Right (Compile.Artifacts canonical annotations objects) ->
681 do let name = Src.getName modul
682 let iface = I.fromModule pkg canonical annotations
683 let docs = makeDocs docsNeed canonical
684 let elmi = Stuff.elmi root name
685 File.writeBinary (Stuff.elmo root name) objects
686 maybeOldi <- File.readBinary elmi
688 Just oldi | oldi == iface ->
689 do -- iface should be fully forced by equality check
690 Reporting.report key Reporting.BDone
691 let local = Details.Local path time deps main lastChange buildID
692 return (RSame local iface objects docs)
695 do -- iface may be lazy still
696 File.writeBinary elmi iface
697 Reporting.report key Reporting.BDone
698 let local = Details.Local path time deps main buildID buildID
699 return (RNew local iface objects docs)
703 Error.Module (Src.getName modul) path time source err
710writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
711writeDetails root (Details.Details time outline buildID locals foreigns extras) results =
712 File.writeBinary (Stuff.details root) $
713 Details.Details time outline buildID (Map.foldrWithKey addNewLocal locals results) foreigns extras
716addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
717addNewLocal name result locals =
719 RNew local _ _ _ -> Map.insert name local locals
720 RSame local _ _ _ -> Map.insert name local locals
721 RCached _ _ _ -> locals
722 RNotFound _ -> locals
733finalizeExposed :: DocsGoal docs -> NE.List ModuleName.Raw -> Map.Map ModuleName.Raw Result -> IO (Either Exit.BuildProblem docs)
734finalizeExposed docsGoal exposed results =
735 case foldr (addImportProblems results) [] (NE.toList exposed) of
737 return $ Left $ Exit.BuildProjectProblem (Exit.BP_MissingExposed (NE.List p ps))
740 case Map.foldr addErrors [] results of
741 [] -> Right <$> finalizeDocs docsGoal results
742 e:es -> return $ Left $ Exit.BuildBadModules e es
745addErrors :: Result -> [Error.Module] -> [Error.Module]
746addErrors result errors =
748 RNew _ _ _ _ -> errors
749 RSame _ _ _ _ -> errors
750 RCached _ _ _ -> errors
751 RNotFound _ -> errors
752 RProblem e -> e:errors
758addImportProblems :: Map.Map ModuleName.Raw Result -> ModuleName.Raw -> [(ModuleName.Raw, Import.Problem)] -> [(ModuleName.Raw, Import.Problem)]
759addImportProblems results name problems =
760 case results ! name of
761 RNew _ _ _ _ -> problems
762 RSame _ _ _ _ -> problems
763 RCached _ _ _ -> problems
764 RNotFound p -> (name, p) : problems
765 RProblem _ -> problems
767 RForeign _ -> problems
776 KeepDocs :: DocsGoal Docs.Documentation
777 WriteDocs :: FilePath -> DocsGoal ()
778 IgnoreDocs :: DocsGoal ()
782 DocsNeed { needsDocs :: Bool }
785toDocsNeed :: DocsGoal a -> DocsNeed
788 IgnoreDocs -> DocsNeed False
789 WriteDocs _ -> DocsNeed True
790 KeepDocs -> DocsNeed True
793makeDocs :: DocsNeed -> Can.Module -> Maybe Docs.Module
794makeDocs (DocsNeed isNeeded) modul =
796 case Docs.fromModule modul of
797 Right docs -> Just docs
803finalizeDocs :: DocsGoal docs -> Map.Map ModuleName.Raw Result -> IO docs
804finalizeDocs goal results =
807 return $ Map.mapMaybe toDocs results
810 E.writeUgly path $ Docs.encode $ Map.mapMaybe toDocs results
816toDocs :: Result -> Maybe Docs.Module
821 RCached _ _ _ -> Nothing
822 RNotFound _ -> Nothing
823 RProblem _ -> Nothing
825 RForeign _ -> Nothing
830--------------------------------------------------------------------------------
831------ NOW FOR SOME REPL STUFF -------------------------------------------------
832--------------------------------------------------------------------------------
840 { _repl_home :: ModuleName.Canonical
841 , _repl_modules :: [Module]
842 , _repl_localizer :: L.Localizer
843 , _repl_annotations :: Map.Map Name.Name Can.Annotation
847fromRepl :: FilePath -> Details.Details -> B.ByteString -> IO (Either Exit.Repl ReplArtifacts)
848fromRepl root details source =
850 env@(Env _ _ pkg _ _ _ _) = makeEnv Reporting.ignorer root details
852 case Parse.fromByteString pkg source of
854 return $ Left $ Exit.ReplBadInput source $ Error.BadSyntax syntaxError
856 Right modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
857 do dmvar <- Details.loadInterfaces root details
859 let deps = map Src.getImportName imports
860 mvar <- newMVar Map.empty
861 crawlDeps env mvar deps ()
863 statuses <- traverse readMVar =<< readMVar mvar
864 midpoint <- checkMidpoint dmvar statuses
868 return $ Left $ Exit.ReplProjectProblem problem
871 do rmvar <- newEmptyMVar
872 resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
873 putMVar rmvar resultMVars
874 results <- traverse readMVar resultMVars
875 writeDetails root details results
876 depsStatus <- checkDeps root resultMVars deps 0
877 finalizeReplArtifacts env source modul depsStatus resultMVars results
880finalizeReplArtifacts :: Env -> B.ByteString -> Src.Module -> DepsStatus -> ResultDict -> Map.Map ModuleName.Raw Result -> IO (Either Exit.Repl ReplArtifacts)
881finalizeReplArtifacts env@(Env _ root pkg _ _ _ _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) depsStatus resultMVars results =
883 compileInput ifaces =
884 case Compile.compile pkg ifaces modul of
885 Right (Compile.Artifacts canonical annotations objects) ->
887 h = Can._name canonical
888 m = Fresh (Src.getName modul) (I.fromModule pkg canonical annotations) objects
889 ms = Map.foldrWithKey addInside [] results
891 return $ Right $ ReplArtifacts h (m:ms) (L.fromModule modul) annotations
894 return $ Left $ Exit.ReplBadInput source errors
900 DepsSame same cached ->
901 do maybeLoaded <- loadInterfaces root same cached
903 Just ifaces -> compileInput ifaces
904 Nothing -> return $ Left $ Exit.ReplBadCache
907 case Map.foldr addErrors [] results of
908 [] -> return $ Left $ Exit.ReplBlocked
909 e:es -> return $ Left $ Exit.ReplBadLocalDeps e es
911 DepsNotFound problems ->
912 return $ Left $ Exit.ReplBadInput source $ Error.BadImports $
913 toImportErrors env resultMVars imports problems
917--------------------------------------------------------------------------------
918--------------------------------------------------------------------------------
919------ AFTER THIS, EVERYTHING IS ABOUT HANDLING MODULES GIVEN BY FILEPATH ------
920--------------------------------------------------------------------------------
921--------------------------------------------------------------------------------
929 = LInside ModuleName.Raw
933findMains :: Env -> NE.List FilePath -> IO (Either Exit.BuildProjectProblem (NE.List MainLocation))
935 do mvars <- traverse (fork . findLocation env) paths
936 elocs <- traverse readMVar mvars
937 return $ checkLocations =<< sequence elocs
940checkLocations :: NE.List Location -> Either Exit.BuildProjectProblem (NE.List MainLocation)
941checkLocations locations =
943 toOneOrMore loc@(Location absolute _ _) =
944 (absolute, OneOrMore.one loc)
946 fromOneOrMore loc locs =
949 loc2:_ -> Left (Exit.BP_MainPathDuplicate (_relative loc) (_relative loc2))
951 fmap (\_ -> fmap _location locations) $
952 traverse (OneOrMore.destruct fromOneOrMore) $
953 Map.fromListWith OneOrMore.more $ map toOneOrMore (NE.toList locations)
962 { _absolute :: FilePath
963 , _relative :: FilePath
964 , _location :: MainLocation
968findLocation :: Env -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
969findLocation env path =
970 do exists <- File.exists path
972 then findLoc env path =<< Dir.canonicalizePath path
973 else return (Left (Exit.BP_PathUnknown path))
976findLoc :: Env -> FilePath -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
977findLoc (Env _ root _ srcDirs _ _ _) path absolutePath =
979 (dirs, file) = FP.splitFileName absolutePath
980 (final, ext) = FP.splitExtension file
984 return $ Left $ Exit.BP_WithBadExtension path
987 roots = FP.splitDirectories root
988 segments = FP.splitDirectories dirs ++ [final]
990 case dropPrefix roots segments of
992 return $ Right $ Location absolutePath path (LOutside path)
994 Just relativeSegments ->
995 case Maybe.mapMaybe (isInsideSrcDirByPath relativeSegments) srcDirs of
997 return $ Right $ Location absolutePath path (LOutside path)
999 [(_, Right names)] ->
1000 do let name = Name.fromChars (List.intercalate "." names)
1001 matchingDirs <- filterM (isInsideSrcDirByName root names) srcDirs
1002 case matchingDirs of
1004 do let p1 = d1 </> FP.joinPath names <.> "elm"
1005 let p2 = d2 </> FP.joinPath names <.> "elm"
1006 return $ Left $ Exit.BP_MainNameDuplicate name p1 p2
1009 return $ Right $ Location absolutePath path (LInside name)
1011 [(s, Left names)] ->
1012 return $ Left $ Exit.BP_MainNameInvalid path s names
1015 return $ Left $ Exit.BP_WithAmbiguousSrcDir path s1 s2
1019isInsideSrcDirByName :: FilePath -> [String] -> FilePath -> IO Bool
1020isInsideSrcDirByName root names srcDir =
1021 File.exists (root </> srcDir </> FP.joinPath names <.> "elm")
1024isInsideSrcDirByPath :: [String] -> FilePath -> Maybe (FilePath, Either [String] [String])
1025isInsideSrcDirByPath segments srcDir =
1026 case dropPrefix (FP.splitDirectories srcDir) segments of
1031 if all isGoodName names
1032 then Just (srcDir, Right names)
1033 else Just (srcDir, Left names)
1036isGoodName :: [Char] -> Bool
1043 Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
1046dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
1047dropPrefix roots paths =
1058 ".":ps -> dropPrefix roots ps
1059 p:ps -> if r == p then dropPrefix rs ps else Nothing
1067 = SInside ModuleName.Raw
1068 | SOutsideOk Details.Local B.ByteString Src.Module
1069 | SOutsideErr Error.Module
1072crawlMain :: Env -> MVar StatusDict -> MainLocation -> IO MainStatus
1073crawlMain env@(Env _ _ pkg _ buildID _ _) mvar given =
1076 do statusMVar <- newEmptyMVar
1077 statusDict <- takeMVar mvar
1078 putMVar mvar (Map.insert name statusMVar statusDict)
1079 putMVar statusMVar =<< crawlModule env mvar (DocsNeed False) name
1080 return (SInside name)
1083 do time <- File.getTime path
1084 source <- File.readUtf8 path
1085 case Parse.fromByteString pkg source of
1086 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
1087 do let deps = map Src.getImportName imports
1088 let local = Details.Local path time deps (any isMain values) buildID buildID
1089 crawlDeps env mvar deps (SOutsideOk local source modul)
1092 return $ SOutsideErr $
1093 Error.Module "???" path time source (Error.BadSyntax syntaxError)
1101 = RInside ModuleName.Raw
1102 | ROutsideOk ModuleName.Raw I.Interface Opt.LocalGraph
1103 | ROutsideErr Error.Module
1107checkMain :: Env -> ResultDict -> MainStatus -> IO MainResult
1108checkMain env@(Env _ root _ _ _ _ _) results pendingMain =
1111 return (RInside name)
1114 return (ROutsideErr err)
1116 SOutsideOk local@(Details.Local path time deps _ _ lastCompile) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
1117 do depsStatus <- checkDeps root results deps lastCompile
1119 DepsChange ifaces ->
1120 compileOutside env local source ifaces modul
1122 DepsSame same cached ->
1123 do maybeLoaded <- loadInterfaces root same cached
1125 Nothing -> return ROutsideBlocked
1126 Just ifaces -> compileOutside env local source ifaces modul
1129 return ROutsideBlocked
1131 DepsNotFound problems ->
1132 return $ ROutsideErr $ Error.Module (Src.getName modul) path time source $
1133 Error.BadImports (toImportErrors env results imports problems)
1136compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO MainResult
1137compileOutside (Env key _ pkg _ _ _ _) (Details.Local path time _ _ _ _) source ifaces modul =
1139 name = Src.getName modul
1141 case Compile.compile pkg ifaces modul of
1142 Right (Compile.Artifacts canonical annotations objects) ->
1143 do Reporting.report key Reporting.BDone
1144 return $ ROutsideOk name (I.fromModule pkg canonical annotations) objects
1147 return $ ROutsideErr $ Error.Module name path time source errors
1155 = Inside ModuleName.Raw
1156 | Outside ModuleName.Raw I.Interface Opt.LocalGraph
1159toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either Exit.BuildProblem Artifacts
1160toArtifacts (Env _ _ pkg _ _ _ _) foreigns results mainResults =
1161 case gatherProblemsOrMains results mainResults of
1162 Left (NE.List e es) ->
1163 Left (Exit.BuildBadModules e es)
1166 Right $ Artifacts pkg foreigns mains $
1167 Map.foldrWithKey addInside (foldr addOutside [] mainResults) results
1170gatherProblemsOrMains :: Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either (NE.List Error.Module) (NE.List Main)
1171gatherProblemsOrMains results (NE.List mainResult mainResults) =
1173 sortMain result (es, mains) =
1175 RInside n -> ( es, Inside n : mains)
1176 ROutsideOk n i o -> ( es, Outside n i o : mains)
1177 ROutsideErr e -> (e:es, mains)
1178 ROutsideBlocked -> ( es, mains)
1180 errors = Map.foldr addErrors [] results
1182 case (mainResult, foldr sortMain (errors, []) mainResults) of
1183 (RInside n , ( [], ms)) -> Right (NE.List (Inside n) ms)
1184 (RInside _ , (e:es, _ )) -> Left (NE.List e es)
1185 (ROutsideOk n i o, ( [], ms)) -> Right (NE.List (Outside n i o) ms)
1186 (ROutsideOk _ _ _, (e:es, _ )) -> Left (NE.List e es)
1187 (ROutsideErr e , ( es, _ )) -> Left (NE.List e es)
1188 (ROutsideBlocked , ( [], _ )) -> error "seems like elm-stuff/ is corrupted"
1189 (ROutsideBlocked , (e:es, _ )) -> Left (NE.List e es)
1192addInside :: ModuleName.Raw -> Result -> [Module] -> [Module]
1193addInside name result modules =
1195 RNew _ iface objs _ -> Fresh name iface objs : modules
1196 RSame _ iface objs _ -> Fresh name iface objs : modules
1197 RCached main _ mvar -> Cached name main mvar : modules
1198 RNotFound _ -> error (badInside name)
1199 RProblem _ -> error (badInside name)
1200 RBlocked -> error (badInside name)
1201 RForeign _ -> modules
1205badInside :: ModuleName.Raw -> [Char]
1207 "Error from `" ++ Name.toChars name ++ "` should have been reported already."
1210addOutside :: MainResult -> [Module] -> [Module]
1211addOutside main modules =
1213 RInside _ -> modules
1214 ROutsideOk name iface objs -> Fresh name iface objs : modules
1215 ROutsideErr _ -> modules
1216 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