2013-02-27 07:33:47 +00:00
|
|
|
module Initialize (build, buildFromSource) where
|
2012-05-29 18:25:43 +00:00
|
|
|
|
2012-08-01 23:37:37 +00:00
|
|
|
import Control.Applicative ((<$>))
|
2012-06-12 06:28:45 +00:00
|
|
|
import Control.Monad.Error
|
2013-02-27 07:33:47 +00:00
|
|
|
import Data.List (lookup,nub)
|
2012-05-29 18:25:43 +00:00
|
|
|
|
2012-06-12 06:28:45 +00:00
|
|
|
import Ast
|
2013-02-08 09:33:21 +00:00
|
|
|
import Data.Either (lefts,rights)
|
|
|
|
import Data.List (intercalate,partition)
|
2013-02-27 07:33:47 +00:00
|
|
|
import Parse.Parser (parseProgram, preParse)
|
2012-06-12 06:28:45 +00:00
|
|
|
import Rename
|
2012-11-23 04:30:37 +00:00
|
|
|
import Types.Types ((-:))
|
2012-08-09 14:38:18 +00:00
|
|
|
import Types.Hints (hints)
|
|
|
|
import Types.Unify
|
2013-02-07 08:17:23 +00:00
|
|
|
import Types.Alias
|
2012-06-12 06:28:45 +00:00
|
|
|
import Optimize
|
2013-02-27 07:33:47 +00:00
|
|
|
import CompileToJS (jsModule)
|
2012-05-29 18:25:43 +00:00
|
|
|
|
2013-02-08 09:33:21 +00:00
|
|
|
checkMistakes :: Module -> Either String Module
|
|
|
|
checkMistakes modul@(Module name ex im stmts) =
|
2013-02-07 08:17:23 +00:00
|
|
|
case mistakes stmts of
|
|
|
|
m:ms -> Left (unlines (m:ms))
|
2013-02-08 09:33:21 +00:00
|
|
|
[] -> return modul
|
|
|
|
|
2013-02-27 07:33:47 +00:00
|
|
|
checkTypes :: Module -> Either String Module
|
2013-02-08 09:33:21 +00:00
|
|
|
checkTypes (Module name ex im stmts) =
|
|
|
|
let stmts' = dealias stmts
|
|
|
|
modul = Module name ex im stmts'
|
2013-02-27 07:33:47 +00:00
|
|
|
in do subs <- unify hints modul
|
2013-03-17 05:24:18 +00:00
|
|
|
let --im' | any ((=="Prelude") . fst) im = im
|
|
|
|
-- | otherwise = ("Prelude", Importing []) : im
|
|
|
|
modul' = optimize . renameModule $ Module name ex im stmts'
|
2013-02-27 07:33:47 +00:00
|
|
|
subs `seq` return modul'
|
2013-02-08 09:33:21 +00:00
|
|
|
|
2013-02-27 07:33:47 +00:00
|
|
|
check :: Module -> Either String Module
|
2013-02-08 09:33:21 +00:00
|
|
|
check = checkMistakes >=> checkTypes
|
|
|
|
|
2013-02-27 07:33:47 +00:00
|
|
|
buildFromSource :: String -> Either String Module
|
|
|
|
buildFromSource src = check =<< parseProgram src
|
2013-02-08 09:33:21 +00:00
|
|
|
|
2013-02-27 07:33:47 +00:00
|
|
|
build :: FilePath -> IO (Either String [Module])
|
|
|
|
build root = do
|
|
|
|
names <- getSortedModuleNames root
|
|
|
|
case names of
|
2013-02-08 09:33:21 +00:00
|
|
|
Left err -> return (Left err)
|
2013-02-27 07:33:47 +00:00
|
|
|
Right ns -> do srcs <- zipWithM buildFile' [1..] ns
|
|
|
|
return (sequence srcs)
|
|
|
|
where
|
|
|
|
buildFile' n name = putStrLn (msg n name) >> buildFile name
|
|
|
|
msg n name = "["++show n++" of "++show (length ns)++"] Compiling "++name
|
2013-02-08 09:33:21 +00:00
|
|
|
|
2013-02-27 07:33:47 +00:00
|
|
|
buildFile :: String -> IO (Either String Module)
|
|
|
|
buildFile 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
|
|
|
|
return $ buildFromSource txt
|
2013-02-08 09:33:21 +00:00
|
|
|
|
|
|
|
|
2013-02-27 07:33:47 +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
|
|
|
|
2013-02-27 07:33:47 +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: "
|
|
|
|
|
2013-02-27 07:33:47 +00:00
|
|
|
go :: [String] -> [Deps] -> Either String [String]
|
2013-02-08 09:33:21 +00:00
|
|
|
go sorted [] = Right sorted
|
|
|
|
go sorted unsorted =
|
2013-02-27 07:33:47 +00:00
|
|
|
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
|
|
|
|
builtIns = [] {--
|
|
|
|
["List","Char","Either","Maybe","Dict","Set","Date",
|
|
|
|
"Signal","Mouse","Keyboard.Raw","Keyboard","Touch",
|
|
|
|
"WebSocket","Window","Time","HTTP","Input","Random",
|
|
|
|
"Graphics","Text","Color","JavaScript","Automaton",
|
|
|
|
"JavaScript.Experimental","Prelude","JSON"]
|
|
|
|
--}
|
|
|
|
|
|
|
|
isNative name = takeWhile (/='.') name == "Native"
|
|
|
|
toFilePath name = map swapDots name ++ ext
|
|
|
|
where swapDots '.' = '/'
|
|
|
|
swapDots c = c
|
|
|
|
ext = if isNative name then ".js" else ".elm"
|