@@ -10,16 +10,19 @@ import System.Console.CmdArgs hiding (program)
1010import System.Directory
1111import System.Exit
1212import System.FilePath
13+import System.IO
1314import GHC.Conc
1415
1516import qualified Text.Blaze.Html.Renderer.Pretty as Pretty
1617import qualified Text.Blaze.Html.Renderer.String as Normal
1718import qualified Text.Jasmine as JS
1819import qualified Data.ByteString.Lazy.Char8 as BS
20+import qualified Data.ByteString.Lazy as L
1921
2022import qualified Metadata.Prelude as Prelude
2123import qualified Transform.Canonicalize as Canonical
2224import SourceSyntax.Module
25+import Parse.Module (getModuleName)
2326import Initialize (buildFromSource, getSortedDependencies)
2427import Generate.JavaScript (jsModule)
2528import Generate.Html (createHtml, JSStyle(..), JSSource(..))
@@ -40,7 +43,8 @@ data Flags =
4043 , scripts :: [FilePath]
4144 , no_prelude :: Bool
4245 , minify :: Bool
43− , output_directory :: FilePath
46+ , cache_dir :: FilePath
47+ , build_dir :: FilePath
4448 }
4549 deriving (Data,Typeable,Show,Eq)
4650
@@ -62,8 +66,10 @@ flags = Flags
6266 &= help "Do not import Prelude by default, used only when compiling standard libraries."
6367 , minify = False
6468 &= help "Minify generated JavaScript and HTML"
65− , output_directory = "ElmFiles" &= typFile
66− &= help "Output files to directory specified. Defaults to ElmFiles/ directory."
69+ , cache_dir = "cache" &= typFile
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."
6773 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
6874 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
6975
@@ -78,25 +84,32 @@ compileArgs flags =
7884 fs -> mapM_ (build flags) fs
7985
8086
81−file :: Flags -> FilePath -> String -> FilePath
82−file flags filePath ext = output_directory flags </> replaceExtension filePath ext
87+buildPath :: Flags -> FilePath -> String -> FilePath
88+buildPath flags filePath ext = build_dir flags </> replaceExtension filePath ext
89+
90+cachePath :: Flags -> FilePath -> String -> FilePath
91+cachePath flags filePath ext = cache_dir flags </> replaceExtension filePath ext
8392
8493elmo :: Flags -> FilePath -> FilePath
85−elmo flags filePath = file flags filePath "elmo"
94+elmo flags filePath = cachePath flags filePath "elmo"
8695
8796elmi :: Flags -> FilePath -> FilePath
88−elmi flags filePath = file flags filePath "elmi"
97+elmi flags filePath = cachePath flags filePath "elmi"
8998
9099
91−buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO ModuleInterface
100+buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String,ModuleInterface)
92101buildFile flags moduleNum numModules interfaces filePath =
93102 do compiled <- alreadyCompiled
94− if not compiled then compile
95− else getInterface `fmap` Binary.decodeFile (elmi flags filePath)
103+ case compiled of
104+ False -> compile
105+ True -> do
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
111+ return info
96112 where
97− getInterface :: (String, ModuleInterface) -> ModuleInterface
98− getInterface = snd
99−
100113 alreadyCompiled :: IO Bool
101114 alreadyCompiled = do
102115 existsi <- doesFileExist (elmi flags filePath)
@@ -110,16 +123,18 @@ buildFile flags moduleNum numModules interfaces filePath =
110123 number :: String
111124 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
112125
113− name :: String
114− name = List.intercalate "." (splitDirectories (dropExtensions filePath))
115−
116− compile :: IO ModuleInterface
126+ compile :: IO (String,ModuleInterface)
117127 compile = do
128+ source <- readFile filePath
129+ let name = case getModuleName source of
130+ Just n -> n
131+ Nothing -> "Main"
118132 putStrLn $ concat [ number, " Compiling ", name
119133 , replicate (max 1 (20 - length name)) ' '
120134 , "( " ++ filePath ++ " )" ]
121− source <- readFile filePath
122− createDirectoryIfMissing True (output_directory flags)
135+
136+ createDirectoryIfMissing True (cache_dir flags)
137+ createDirectoryIfMissing True (build_dir flags)
123138 metaModule <-
124139 case buildFromSource (no_prelude flags) interfaces source of
125140 Left errors -> do
@@ -139,9 +154,11 @@ buildFile flags moduleNum numModules interfaces filePath =
139154 iAliases = aliases metaModule
140155 }
141156 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))
159+ hClose handle
143160 writeFile (elmo flags filePath) (jsModule metaModule)
144− return interface
161+ return (name,interface)
145162
146163printTypes metaModule = do
147164 putStrLn ""
@@ -161,18 +178,20 @@ build flags rootFile = do
161178 let noPrelude = no_prelude flags
162179 files <- if make flags then getSortedDependencies noPrelude rootFile else return [rootFile]
163180 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
165182 js <- foldM appendToOutput "" files
166183 case only_js flags of
167184 True -> do
168185 putStr "Generating JavaScript ... "
169− writeFile (file flags rootFile "js") (genJs js)
186+ writeFile (buildPath flags rootFile "js") (genJs js)
170187 putStrLn "Done"
171188 False -> do
172189 putStr "Generating HTML ... "
173190 runtime <- getRuntime flags
174− let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) ""
175− writeFile (file flags rootFile "html") html
191+ let html = genHtml $ createHtml runtime (takeBaseName rootFile) (sources js) moduleName ""
192+ htmlFile = buildPath flags rootFile "html"
193+ createDirectoryIfMissing True (takeDirectory htmlFile)
194+ writeFile htmlFile html
176195 putStrLn "Done"
177196
178197 where
@@ -187,10 +206,9 @@ build flags rootFile = do
187206 [ Source (if minify flags then Minified else Readable) js ]
188207
189208
190−buildFiles :: Flags -> Int -> Interfaces -> [FilePath] -> IO Interfaces
191−buildFiles _ _ interfaces [] = return interfaces
192−buildFiles flags numModules interfaces (filePath:rest) = do
193− interface <- buildFile flags (numModules - length rest) numModules interfaces filePath
194− let moduleName = List.intercalate "." . splitDirectories $ dropExtensions filePath
195− interfaces' = Map.insert moduleName interface interfaces
196− buildFiles flags numModules interfaces' rest
209+buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
210+buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces)
211+buildFiles flags numModules interfaces _ (filePath:rest) = do
212+ (name,interface) <- buildFile flags (numModules - length rest) numModules interfaces filePath
213+ let interfaces' = Map.insert name interface interfaces
214+ buildFiles flags numModules interfaces' name rest