elm/compiler/Initialize.hs

98 lines
3.4 KiB
Haskell
Raw Normal View History

module Initialize (build, buildFromSource) where
import Control.Applicative ((<$>))
import Control.Monad.Error
import Data.List (lookup,nub)
import qualified Data.Map as Map
import Ast
2013-02-08 09:33:21 +00:00
import Data.Either (lefts,rights)
import Data.List (intercalate,partition)
import Parse.Parser (parseProgram, preParse)
import Rename
2013-04-08 08:48:30 +00:00
import qualified Libraries as Libs
import Types.Types ((-:))
import Types.Hints (hints)
2013-05-28 13:47:36 +00:00
import Types.Unify (unify)
2013-04-05 16:55:30 +00:00
import Types.Alias (dealias, mistakes)
import Optimize
import CompileToJS (jsModule)
2013-02-08 09:33:21 +00:00
checkMistakes :: Module -> Either String Module
checkMistakes modul@(Module name ex im stmts) =
case mistakes stmts of
m:ms -> Left (unlines (m:ms))
2013-02-08 09:33:21 +00:00
[] -> return modul
checkTypes :: Module -> Either String Module
2013-04-05 16:55:30 +00:00
checkTypes modul =
do subs <- unify hints modul
subs `seq` return (optimize (renameModule modul))
2013-02-08 09:33:21 +00:00
check :: Module -> Either String Module
2013-02-08 09:33:21 +00:00
check = checkMistakes >=> checkTypes
2013-04-08 08:48:30 +00:00
buildFromSource :: Bool -> String -> Either String Module
buildFromSource withPrelude src = (check . add) =<< (parseProgram src)
where add = if withPrelude then Libs.addPrelude else id
2013-02-08 09:33:21 +00:00
2013-04-08 08:48:30 +00:00
build :: Bool -> FilePath -> IO (Either String [Module])
build withPrelude root = do
names <- getSortedModuleNames root
case names of
2013-02-08 09:33:21 +00:00
Left err -> return (Left err)
Right ns -> do srcs <- zipWithM buildFile' [1..] ns
return (sequence srcs)
where
2013-04-08 08:48:30 +00:00
buildFile' n name = putStrLn (msg n name) >> buildFile withPrelude name
msg n name = "["++show n++" of "++show (length ns)++"] Compiling "++name
2013-02-08 09:33:21 +00:00
2013-04-08 08:48:30 +00:00
buildFile :: Bool -> String -> IO (Either String Module)
buildFile withPrelude moduleName =
let filePath = toFilePath moduleName in
case isNative moduleName of
True -> return (Right $ Module [moduleName] [] [] [])
--return (Left "Can't do that yet")
--Right `liftM` readFile filePath
False -> do txt <- readFile filePath
2013-04-08 08:48:30 +00:00
return $ buildFromSource withPrelude txt
2013-02-08 09:33:21 +00:00
getSortedModuleNames :: FilePath -> IO (Either String [String])
getSortedModuleNames root = do
deps <- readDeps [] root
return (sortDeps =<< deps)
2013-02-08 09:33:21 +00:00
type Deps = (String, [String])
sortDeps :: [Deps] -> Either String [String]
sortDeps deps = go [] (nub deps)
2013-02-08 09:33:21 +00:00
where
msg = "A cyclical or missing module dependency or was detected in: "
go :: [String] -> [Deps] -> Either String [String]
2013-02-08 09:33:21 +00:00
go sorted [] = Right sorted
go sorted unsorted =
case partition (all (`elem` sorted) . snd) unsorted of
([],m:ms) -> Left (msg ++ intercalate ", " (map fst (m:ms)) ++ show sorted ++ show unsorted)
(srtd,unsrtd) -> go (sorted ++ map fst srtd) unsrtd
readDeps :: [FilePath] -> FilePath -> IO (Either String [Deps])
readDeps seen root = do
txt <- readFile root
case preParse txt of
Left err -> return (Left err)
Right (name,deps) -> do rest <- mapM (readDeps seen' . toFilePath) newDeps
return $ do rs <- sequence rest
return ((name, realDeps) : concat rs)
where realDeps = filter (`notElem` builtIns) deps
newDeps = filter (`notElem` seen) realDeps
seen' = root : seen ++ newDeps
2013-04-08 08:48:30 +00:00
builtIns = Map.keys Libs.libraries
isNative name = takeWhile (/='.') name == "Native"
toFilePath name = map swapDots name ++ ext
where swapDots '.' = '/'
swapDots c = c
ext = if isNative name then ".js" else ".elm"