1{-# LANGUAGE DeriveDataTypeable #-}
5import qualified Data.Map as Map
6import qualified Data.List as List
7import qualified Data.Binary as Binary
8import Data.Version (showVersion)
9import System.Console.CmdArgs hiding (program)
10import System.Directory
16import Text.Blaze.Html.Renderer.Pretty (renderHtml)
17import qualified Data.ByteString.Lazy.Char8 as BS
18import qualified Data.ByteString.Lazy as L
20import qualified Metadata.Prelude as Prelude
21import qualified Transform.Canonicalize as Canonical
22import SourceSyntax.Module
23import Parse.Module (getModuleName)
24import Initialize (buildFromSource, getSortedDependencies)
25import Generate.JavaScript (jsModule)
26import Generate.Html (createHtml, JSSource(..))
27import qualified InterfaceSerialization as IS
30import SourceSyntax.PrettyPrint (pretty, variable)
31import Text.PrettyPrint as P
32import qualified Type.Type as Type
33import qualified Type.Alias as Alias
38 , runtime :: Maybe FilePath
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"
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")
75main = do setNumCapabilities =<< getNumProcessors
76 compileArgs =<< cmdArgs flags
78compileArgs :: Flags -> IO ()
81 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
82 fs -> mapM_ (build flags) fs
85buildPath :: Flags -> FilePath -> String -> FilePath
86buildPath flags filePath ext = build_dir flags </> replaceExtension filePath ext
88cachePath :: Flags -> FilePath -> String -> FilePath
89cachePath flags filePath ext = cache_dir flags </> replaceExtension filePath ext
91elmo :: Flags -> FilePath -> FilePath
92elmo flags filePath = cachePath flags filePath "elmo"
94elmi :: Flags -> FilePath -> FilePath
95elmi flags filePath = cachePath flags filePath "elmi"
97buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String, ModuleInterface)
98buildFile 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
108 Right (name, interface) -> do
109 when (print_types flags) $
110 printTypes interfaces
115 return (name, interface)
118 alreadyCompiled :: IO Bool
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)
171printTypes 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)
178getRuntime :: Flags -> IO FilePath
180 case runtime flags of
182 Nothing -> getDataFileName "elm-runtime.js"
184build :: Flags -> FilePath -> IO ()
185build 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 ]
220buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
221buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces)
222buildFiles 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
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list