@@ -1,10 +1,12 @@
1−module Initialize (initialize) where
1+module Initialize (build,buildFromSource) where
3import Control.Applicative ((<$>))
3import Control.Applicative ((<$>))
4import Control.Monad.Error
4import Control.Monad.Error
5import Data.List (lookup)
5import Data.List (lookup)
8+import Data.Either (lefts,rights)
9+import Data.List (intercalate,partition)
8import Parse.Parser (parseProgram)
10import Parse.Parser (parseProgram)
9import Rename
11import Rename
10import Types.Types ((-:))
12import Types.Types ((-:))
@@ -13,15 +15,81 @@ import Types.Unify
13import Types.Alias
15import Types.Alias
14import Optimize
16import Optimize
16−initialize :: String -> Either String ([String], Module)
18+checkMistakes :: Module -> Either String Module
18− Module name ex im stmts <- parseProgram str
19+checkMistakes modul@(Module name ex im stmts) =
19 case mistakes stmts of
20 case mistakes stmts of
20 m:ms -> Left (unlines (m:ms))
21 m:ms -> Left (unlines (m:ms))
24+checkTypes :: Module -> Either String ([String], Module)
25+checkTypes (Module name ex im stmts) =
21− [] -> let stmts' = dealias stmts
26+ let stmts' = dealias stmts
22− modul = Module name ex im stmts'
27+ modul = Module name ex im stmts'
23− in do (escapees, subs) <- unify hints modul
28+ in do (escapees, subs) <- unify hints modul
24− let im' | any ((=="Prelude") . fst) im = im
29+ let im' | any ((=="Prelude") . fst) im = im
25− | otherwise = ("Prelude", Hiding []) : im
30+ | otherwise = ("Prelude", Hiding []) : im
26− modul' = optimize . renameModule $ Module name ex im' stmts'
31+ modul' = optimize . renameModule $ Module name ex im' stmts'
27− subs `seq` return (escapees, modul')
32+ subs `seq` return (escapees, modul')
34+check :: Module -> Either String ([String], Module)
35+check = checkMistakes >=> checkTypes
37+buildFromSource :: String -> Either String ([String],Module)
38+buildFromSource = parseProgram >=> check
40+build :: Bool -> FilePath -> IO (Either String ([String],[Module]))
42+ proj <- parse make root
45+ (escapeess, modules) <- unzip `liftM` mapM check ms
46+ sortedModules <- (if make then sort else return) modules
47+ return (concat escapeess, sortedModules)
49+parse :: Bool -> FilePath -> IO (Either String [Module])
50+parse make root = parseProject [] make root
52+parseProject :: [FilePath] -> Bool -> FilePath -> IO (Either String [Module])
53+parseProject seen make root = do
55+ case parseProgram txt of
56+ Left err -> return (Left err)
57+ Right modul@(Module names exs ims stmts) ->
58+ let allDeps = map toFilePath (getDeps modul)
59+ newDeps = if make then filter (`notElem` seen) allDeps else []
60+ name = intercalate "." names
61+ in do ps <- mapM (parseProject (name : seen ++ newDeps) make) newDeps
62+ return $ case unlines (lefts ps) of
64+ _ -> Right (modul : concat (rights ps))
66+toFilePath :: String -> FilePath
67+toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm"
69+getDeps :: Module -> [String]
70+getDeps (Module _ _ is _) = filter (`notElem` builtInModules) (map fst is)
73+ ["List","Char","Either","Maybe","Dict","Set","Automaton","Date",
74+ "Signal","Mouse","Keyboard.Raw","Keyboard","Touch",
75+ "WebSocket","Window","Time","HTTP","Input","Random",
76+ "Graphics","Text","Color","JavaScript",
77+ "JavaScript.Experimental","Prelude","JSON"]
80+sort :: [Module] -> Either String [Module]
83+ msg = "A cyclical or missing module dependency or was detected in: "
84+ getName (Module names _ _ _) = intercalate "." names
86+ has name modul = name == getName modul
87+ within ms name = any (has name) ms
89+ go :: [Module] -> [Module] -> Either String [Module]
90+ go sorted [] = Right sorted
92+ case partition (all (within sorted) . getDeps) unsorted of
93+ ([],m:ms) -> Left (msg ++ intercalate ", " (map getName (m:ms)))
94+ (srtd,unsrtd) -> go (sorted ++ srtd) unsrtd