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(..))
29import SourceSyntax.PrettyPrint (pretty, variable)
30import Text.PrettyPrint as P
31import qualified Type.Type as Type
32import qualified Type.Alias as Alias
37 , runtime :: Maybe FilePath
40 , print_program :: 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"
68 &= help "Print out infered types of top-level definitions."
69 , print_program = False
70 &= help "Print out an internal representation of a program."
71 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
72 &= helpArg [explicit, name "help", name "h"]
73 &= versionArg [explicit, name "version", name "v", summary (showVersion version)]
74 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki 2011-2013")
77main = do setNumCapabilities =<< getNumProcessors
78 compileArgs =<< cmdArgs flags
80compileArgs :: Flags -> IO ()
83 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
84 fs -> mapM_ (build flags) fs
87buildPath :: Flags -> FilePath -> String -> FilePath
88buildPath flags filePath ext = build_dir flags </> replaceExtension filePath ext
90cachePath :: Flags -> FilePath -> String -> FilePath
91cachePath flags filePath ext = cache_dir flags </> replaceExtension filePath ext
93elmo :: Flags -> FilePath -> FilePath
94elmo flags filePath = cachePath flags filePath "elmo"
96elmi :: Flags -> FilePath -> FilePath
97elmi flags filePath = cachePath flags filePath "elmi"
100buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String,ModuleInterface)
101buildFile flags moduleNum numModules interfaces filePath =
102 do compiled <- alreadyCompiled
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
113 alreadyCompiled :: IO Bool
115 existsi <- doesFileExist (elmi flags filePath)
116 existso <- doesFileExist (elmo flags filePath)
117 if not existsi || not existso
119 else do tsrc <- getModificationTime filePath
120 tint <- getModificationTime (elmo flags filePath)
121 return (tsrc <= tint)
124 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
126 compile :: IO (String,ModuleInterface)
128 source <- readFile filePath
129 let name = case getModuleName source of
132 putStrLn $ concat [ number, " Compiling ", name
133 , replicate (max 1 (20 - length name)) ' '
134 , "( " ++ filePath ++ " )" ]
136 createDirectoryIfMissing True (cache_dir flags)
137 createDirectoryIfMissing True (build_dir flags)
139 case buildFromSource (no_prelude flags) interfaces source of
141 mapM print (List.intersperse (P.text " ") errors)
144 case print_program flags of
146 True -> print . pretty $ program modul
149 when (print_types flags) (printTypes interfaces metaModule)
150 let interface = Canonical.interface name $ ModuleInterface {
151 iTypes = types metaModule,
152 iAdts = datatypes metaModule,
153 iAliases = aliases metaModule,
154 iFixities = fixities metaModule
156 createDirectoryIfMissing True . dropFileName $ elmi flags filePath
157 handle <- openBinaryFile (elmi flags filePath) WriteMode
158 L.hPut handle (Binary.encode (name,interface))
160 writeFile (elmo flags filePath) (jsModule metaModule)
161 return (name,interface)
163printTypes interfaces metaModule = do
165 let rules = Alias.rules interfaces metaModule
166 forM_ (Map.toList $ types metaModule) $ \(n,t) -> do
167 print $ variable n <+> P.text ":" <+> pretty (Alias.realias rules t)
170getRuntime :: Flags -> IO FilePath
172 case runtime flags of
174 Nothing -> getDataFileName "elm-runtime.js"
176build :: Flags -> FilePath -> IO ()
177build flags rootFile = do
178 let noPrelude = no_prelude flags
179 files <- if make flags then getSortedDependencies (src_dir flags) noPrelude rootFile
180 else return [rootFile]
181 let ifaces = if noPrelude then Map.empty else Prelude.interfaces
182 (moduleName, interfaces) <- buildFiles flags (length files) ifaces "" files
183 js <- foldM appendToOutput BS.empty files
185 (extension, code) <- case only_js flags of
187 putStr "Generating JavaScript ... "
190 putStr "Generating HTML ... "
191 rtsPath <- getRuntime flags
192 return ("html", BS.pack . renderHtml $
193 createHtml rtsPath (takeBaseName rootFile) (sources js) moduleName "")
195 let targetFile = buildPath flags rootFile extension
196 createDirectoryIfMissing True (takeDirectory targetFile)
197 BS.writeFile targetFile code
201 appendToOutput :: BS.ByteString -> FilePath -> IO BS.ByteString
202 appendToOutput js filePath =
203 do src <- BS.readFile (elmo flags filePath)
204 return (BS.append src js)
206 sources js = map Link (scripts flags) ++ [ Source js ]
209buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
210buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces)
211buildFiles 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
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