@@ -10,16 +10,19 @@ import System.Console.CmdArgs hiding (program)
10import System.Directory
10import System.Directory
11import System.Exit
11import System.Exit
12import System.FilePath
12import System.FilePath
13import GHC.Conc
14import GHC.Conc
15import qualified Text.Blaze.Html.Renderer.Pretty as Pretty
16import qualified Text.Blaze.Html.Renderer.Pretty as Pretty
16import qualified Text.Blaze.Html.Renderer.String as Normal
17import qualified Text.Blaze.Html.Renderer.String as Normal
17import qualified Text.Jasmine as JS
18import qualified Text.Jasmine as JS
18import qualified Data.ByteString.Lazy.Char8 as BS
19import qualified Data.ByteString.Lazy.Char8 as BS
20+import qualified Data.ByteString.Lazy as L
20import qualified Metadata.Prelude as Prelude
22import qualified Metadata.Prelude as Prelude
21import qualified Transform.Canonicalize as Canonical
23import qualified Transform.Canonicalize as Canonical
22import SourceSyntax.Module
24import SourceSyntax.Module
25+import Parse.Module (getModuleName)
23import Initialize (buildFromSource, getSortedDependencies)
26import Initialize (buildFromSource, getSortedDependencies)
24import Generate.JavaScript (jsModule)
27import Generate.JavaScript (jsModule)
25import Generate.Html (createHtml, JSStyle(..), JSSource(..))
28import Generate.Html (createHtml, JSStyle(..), JSSource(..))
@@ -40,7 +43,8 @@ data Flags =
40 , scripts :: [FilePath]
43 , scripts :: [FilePath]
41 , no_prelude :: Bool
44 , no_prelude :: Bool
42 , minify :: Bool
45 , minify :: Bool
43− , output_directory :: FilePath
46+ , cache_dir :: FilePath
47+ , build_dir :: FilePath
45 deriving (Data,Typeable,Show,Eq)
49 deriving (Data,Typeable,Show,Eq)
@@ -62,8 +66,10 @@ flags = Flags
62 &= help "Do not import Prelude by default, used only when compiling standard libraries."
66 &= help "Do not import Prelude by default, used only when compiling standard libraries."
63 , minify = False
67 , minify = False
64 &= help "Minify generated JavaScript and HTML"
68 &= help "Minify generated JavaScript and HTML"
65− , output_directory = "ElmFiles" &= typFile
69+ , cache_dir = "cache" &= typFile
66− &= help "Output files to directory specified. Defaults to ElmFiles/ directory."
70+ &= help "Directory for files cached to make builds faster. Defaults to cache/ directory."
71+ , build_dir = "build" &= typFile
72+ &= help "Directory for generated HTML and JS files. Defaults to build/ directory."
67 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
73 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
68 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
74 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
@@ -78,25 +84,32 @@ compileArgs flags =
78 fs -> mapM_ (build flags) fs
84 fs -> mapM_ (build flags) fs
81−file :: Flags -> FilePath -> String -> FilePath
87+buildPath :: Flags -> FilePath -> String -> FilePath
88+buildPath flags filePath ext = build_dir flags </> replaceExtension filePath ext
90+cachePath :: Flags -> FilePath -> String -> FilePath
82−file flags filePath ext = output_directory flags </> replaceExtension filePath ext
91+cachePath flags filePath ext = cache_dir flags </> replaceExtension filePath ext
84elmo :: Flags -> FilePath -> FilePath
93elmo :: Flags -> FilePath -> FilePath
85−elmo flags filePath = file flags filePath "elmo"
94+elmo flags filePath = cachePath flags filePath "elmo"
87elmi :: Flags -> FilePath -> FilePath
96elmi :: Flags -> FilePath -> FilePath
88−elmi flags filePath = file flags filePath "elmi"
97+elmi flags filePath = cachePath flags filePath "elmi"
91−buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO ModuleInterface
100+buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String,ModuleInterface)
92buildFile flags moduleNum numModules interfaces filePath =
101buildFile flags moduleNum numModules interfaces filePath =
93 do compiled <- alreadyCompiled
102 do compiled <- alreadyCompiled
94− if not compiled then compile
103+ case compiled of
95− else getInterface `fmap` Binary.decodeFile (elmi flags filePath)
104+ False -> compile
106+ handle <- openBinaryFile (elmi flags filePath) ReadMode
107+ bits <- L.hGetContents handle
108+ let info :: (String, ModuleInterface)
109+ info = Binary.decode bits
110+ L.length bits `seq` hClose handle
97− getInterface :: (String, ModuleInterface) -> ModuleInterface
100 alreadyCompiled :: IO Bool
113 alreadyCompiled :: IO Bool
101 alreadyCompiled = do
114 alreadyCompiled = do
102 existsi <- doesFileExist (elmi flags filePath)
115 existsi <- doesFileExist (elmi flags filePath)
@@ -110,16 +123,18 @@ buildFile flags moduleNum numModules interfaces filePath =
110 number :: String
123 number :: String
111 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
124 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
114− name = List.intercalate "." (splitDirectories (dropExtensions filePath))
116− compile :: IO ModuleInterface
126+ compile :: IO (String,ModuleInterface)
117 compile = do
127 compile = do
128+ source <- readFile filePath
129+ let name = case getModuleName source of
118 putStrLn $ concat [ number, " Compiling ", name
132 putStrLn $ concat [ number, " Compiling ", name
119 , replicate (max 1 (20 - length name)) ' '
133 , replicate (max 1 (20 - length name)) ' '
120 , "( " ++ filePath ++ " )" ]
134 , "( " ++ filePath ++ " )" ]
121− source <- readFile filePath
135+
136+ createDirectoryIfMissing True (cache_dir flags)
122− createDirectoryIfMissing True (output_directory flags)
137+ createDirectoryIfMissing True (build_dir flags)
123 metaModule <-
138 metaModule <-
124 case buildFromSource (no_prelude flags) interfaces source of
139 case buildFromSource (no_prelude flags) interfaces source of
125 Left errors -> do
140 Left errors -> do
@@ -139,9 +154,11 @@ buildFile flags moduleNum numModules interfaces filePath =
139 iAliases = aliases metaModule
154 iAliases = aliases metaModule
141 createDirectoryIfMissing True . dropFileName $ elmi flags filePath
156 createDirectoryIfMissing True . dropFileName $ elmi flags filePath
142− Binary.encodeFile (elmi flags filePath) (name,interface)
157+ handle <- openBinaryFile (elmi flags filePath) WriteMode
158+ L.hPut handle (Binary.encode (name,interface))
143 writeFile (elmo flags filePath) (jsModule metaModule)
160 writeFile (elmo flags filePath) (jsModule metaModule)
144− return interface
161+ return (name,interface)
146printTypes metaModule = do
163printTypes metaModule = do
147 putStrLn ""
164 putStrLn ""
@@ -161,18 +178,20 @@ build flags rootFile = do
161 let noPrelude = no_prelude flags
178 let noPrelude = no_prelude flags
162 files <- if make flags then getSortedDependencies noPrelude rootFile else return [rootFile]
179 files <- if make flags then getSortedDependencies noPrelude rootFile else return [rootFile]
163 let ifaces = if noPrelude then Map.empty else Prelude.interfaces
180 let ifaces = if noPrelude then Map.empty else Prelude.interfaces
164− interfaces <- buildFiles flags (length files) ifaces files
181+ (moduleName, interfaces) <- buildFiles flags (length files) ifaces "" files
165 js <- foldM appendToOutput "" files
182 js <- foldM appendToOutput "" files
166 case only_js flags of
183 case only_js flags of
167 True -> do
184 True -> do
168 putStr "Generating JavaScript ... "
185 putStr "Generating JavaScript ... "
169− writeFile (file flags rootFile "js") (genJs js)
186+ writeFile (buildPath flags rootFile "js") (genJs js)
170 putStrLn "Done"
187 putStrLn "Done"
171 False -> do
188 False -> do
172 putStr "Generating HTML ... "
189 putStr "Generating HTML ... "
173 runtime <- getRuntime flags
190 runtime <- getRuntime flags
174− let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) ""
191+ let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) moduleName ""
175− writeFile (file flags rootFile "html") html
192+ htmlFile = buildPath flags rootFile "html"
193+ createDirectoryIfMissing True (takeDirectory htmlFile)
194+ writeFile htmlFile html
176 putStrLn "Done"
195 putStrLn "Done"
@@ -187,10 +206,9 @@ build flags rootFile = do
187 [ Source (if minify flags then Minified else Readable) js ]
206 [ Source (if minify flags then Minified else Readable) js ]
190−buildFiles :: Flags -> Int -> Interfaces -> [FilePath] -> IO Interfaces
209+buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
191−buildFiles _ _ interfaces [] = return interfaces
210+buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces)
192−buildFiles flags numModules interfaces (filePath:rest) = do
211+buildFiles flags numModules interfaces _ (filePath:rest) = do
193− interface <- buildFile flags (numModules - length rest) numModules interfaces filePath
212+ (name,interface) <- buildFile flags (numModules - length rest) numModules interfaces filePath
194− let moduleName = List.intercalate "." . splitDirectories $ dropExtensions filePath
195− interfaces' = Map.insert moduleName interface interfaces
213+ let interfaces' = Map.insert name interface interfaces
196− buildFiles flags numModules interfaces' rest
214+ buildFiles flags numModules interfaces' name rest