@@ -1,75 +1,9 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2module Main where
1module Main where
5−import qualified Data.Map as Map
6−import qualified Data.List as List
7−import qualified Data.Binary as Binary
8−import Data.Version (showVersion)
9−import System.Console.CmdArgs hiding (program)
3+import System.Console.CmdArgs
10−import System.Directory
12−import System.FilePath
14import GHC.Conc
4import GHC.Conc
16−import Text.Blaze.Html.Renderer.Pretty (renderHtml)
17−import qualified Data.ByteString.Lazy.Char8 as BS
18−import qualified Data.ByteString.Lazy as L
20−import qualified Metadata.Prelude as Prelude
21−import qualified Transform.Canonicalize as Canonical
22−import SourceSyntax.Module
23−import Parse.Module (getModuleName)
24−import Initialize (buildFromSource, getSortedDependencies)
25−import Generate.JavaScript (jsModule)
26−import Generate.Html (createHtml, JSSource(..))
27−import qualified InterfaceSerialization as IS
30−import SourceSyntax.PrettyPrint (pretty, variable)
31−import Text.PrettyPrint as P
32−import qualified Type.Type as Type
33−import qualified Type.Alias as Alias
35−data Flags =
5+import Build.Flags
36− Flags { make :: Bool
6+import Build.Build
37− , files :: [FilePath]
38− , runtime :: Maybe FilePath
40− , print_types :: Bool
41− , scripts :: [FilePath]
43− , cache_dir :: FilePath
44− , build_dir :: FilePath
45− , src_dir :: [FilePath]
47− deriving (Data,Typeable,Show,Eq)
50− { files = def &= args &= typ "FILES"
52− &= help "automatically compile dependencies."
54− &= help "Compile only to JavaScript."
56− &= help "Do not import Prelude by default, used only when compiling standard libraries."
57− , scripts = [] &= typFile
58− &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
59− , runtime = Nothing &= typFile
60− &= help "Specify a custom location for Elm's runtime system."
61− , cache_dir = "cache" &= typFile
62− &= help "Directory for files cached to make builds faster. Defaults to cache/ directory."
63− , build_dir = "build" &= typFile
64− &= help "Directory for generated HTML and JS files. Defaults to build/ directory."
65− , src_dir = ["."] &= typFile
66− &= help "Additional source directories besides project root. Searched when using --make"
67− , print_types = False
68− &= help "Print out infered types of top-level definitions."
69− } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
70− &= helpArg [explicit, name "help", name "h"]
71− &= versionArg [explicit, name "version", name "v", summary (showVersion version)]
72− &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki 2011-2013")
74main :: IO ()
8main :: IO ()
75main = do setNumCapabilities =<< getNumProcessors
9main = do setNumCapabilities =<< getNumProcessors
@@ -80,146 +14,3 @@ compileArgs flags =
80 case files flags of
14 case files flags of
81 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
15 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
82 fs -> mapM_ (build flags) fs
16 fs -> mapM_ (build flags) fs
85−buildPath :: Flags -> FilePath -> String -> FilePath
86−buildPath flags filePath ext = build_dir flags </> replaceExtension filePath ext
88−cachePath :: Flags -> FilePath -> String -> FilePath
89−cachePath flags filePath ext = cache_dir flags </> replaceExtension filePath ext
91−elmo :: Flags -> FilePath -> FilePath
92−elmo flags filePath = cachePath flags filePath "elmo"
94−elmi :: Flags -> FilePath -> FilePath
95−elmi flags filePath = cachePath flags filePath "elmi"
97−buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String, ModuleInterface)
98−buildFile flags moduleNum numModules interfaces filePath = do
99− compiled <- alreadyCompiled
100− if not compiled then compile else do
101− bytes <- IS.loadInterface (elmi flags filePath)
102− let binary = IS.interfaceDecode (elmi flags filePath) =<< bytes
103− case IS.validVersion filePath =<< binary of
105− hPutStrLn stderr err
108− Right (name, interface) -> do
109− when (print_types flags) $
110− printTypes interfaces
112− (iAliases interface)
113− (iImports interface)
115− return (name, interface)
118− alreadyCompiled :: IO Bool
119− alreadyCompiled = do
120− existsi <- doesFileExist (elmi flags filePath)
121− existso <- doesFileExist (elmo flags filePath)
122− if not existsi || not existso
124− else do tsrc <- getModificationTime filePath
125− tint <- getModificationTime (elmo flags filePath)
126− return (tsrc <= tint)
129− number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
131− compile :: IO (String,ModuleInterface)
133− source <- readFile filePath
134− let name = case getModuleName source of
137− putStrLn $ concat [ number, " Compiling ", name
138− , replicate (max 1 (20 - length name)) ' '
139− , "( " ++ filePath ++ " )" ]
141− createDirectoryIfMissing True (cache_dir flags)
142− createDirectoryIfMissing True (build_dir flags)
145− case buildFromSource (no_prelude flags) interfaces source of
147− mapM print (List.intersperse (P.text " ") errors)
149− Right modul -> return modul
151− when (print_types flags)
152− (printTypes interfaces
153− (types metaModule) (aliases metaModule) (imports metaModule))
155− let interface = Canonical.interface name $ ModuleInterface {
156− iVersion = showVersion version,
157− iTypes = types metaModule,
158− iImports = imports metaModule,
159− iAdts = datatypes metaModule,
160− iAliases = aliases metaModule,
161− iFixities = fixities metaModule
164− createDirectoryIfMissing True . dropFileName $ elmi flags filePath
165− handle <- openBinaryFile (elmi flags filePath) WriteMode
166− L.hPut handle (Binary.encode (name,interface))
168− writeFile (elmo flags filePath) (jsModule metaModule)
169− return (name,interface)
171−printTypes interfaces moduleTypes moduleAliases moduleImports = do
173− let rules = Alias.rules interfaces moduleAliases moduleImports
174− forM_ (Map.toList moduleTypes) $ \(n,t) -> do
175− print $ variable n <+> P.text ":" <+> pretty (Alias.realias rules t)
178−getRuntime :: Flags -> IO FilePath
180− case runtime flags of
181− Just fp -> return fp
182− Nothing -> getDataFileName "elm-runtime.js"
184−build :: Flags -> FilePath -> IO ()
185−build flags rootFile = do
186− let noPrelude = no_prelude flags
187− builtIns <- if noPrelude then return Map.empty else Prelude.interfaces
189− files <- if make flags
190− then getSortedDependencies (src_dir flags) builtIns rootFile
191− else return [rootFile]
193− (moduleName, interfaces) <- buildFiles flags (length files) builtIns "" files
195− js <- foldM appendToOutput BS.empty files
197− (extension, code) <- case only_js flags of
199− putStr "Generating JavaScript ... "
202− putStr "Generating HTML ... "
203− rtsPath <- getRuntime flags
204− return ("html", BS.pack . renderHtml $
205− createHtml rtsPath (takeBaseName rootFile) (sources js) moduleName "")
207− let targetFile = buildPath flags rootFile extension
208− createDirectoryIfMissing True (takeDirectory targetFile)
209− BS.writeFile targetFile code
213− appendToOutput :: BS.ByteString -> FilePath -> IO BS.ByteString
214− appendToOutput js filePath =
215− do src <- BS.readFile (elmo flags filePath)
216− return (BS.append src js)
218− sources js = map Link (scripts flags) ++ [ Source js ]
220−buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
221−buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces)
222−buildFiles flags numModules interfaces _ (filePath:rest) = do
223− (name,interface) <- buildFile flags (numModules - length rest) numModules interfaces filePath
224− let interfaces' = Map.insert name interface interfaces
225− buildFiles flags numModules interfaces' name rest