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
46 deriving (Data,Typeable,Show,Eq)
50 &= help "automatically compile dependencies."
51 , files = def &= args &= typ "FILES"
52 , runtime = Nothing &= typFile
53 &= help "Specify a custom location for Elm's runtime system."
55 &= help "Compile only to JavaScript."
57 &= help "Print out infered types of top-level definitions."
58 , print_program = False
59 &= help "Print out an internal representation of a program."
60 , scripts = [] &= typFile
61 &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
63 &= help "Do not import Prelude by default, used only when compiling standard libraries."
64 , cache_dir = "cache" &= typFile
65 &= help "Directory for files cached to make builds faster. Defaults to cache/ directory."
66 , build_dir = "build" &= typFile
67 &= help "Directory for generated HTML and JS files. Defaults to build/ directory."
68 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
69 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
72main = do setNumCapabilities =<< getNumProcessors
73 compileArgs =<< cmdArgs flags
75compileArgs :: Flags -> IO ()
78 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
79 fs -> mapM_ (build flags) fs
82buildPath :: Flags -> FilePath -> String -> FilePath
83buildPath flags filePath ext = build_dir flags </> replaceExtension filePath ext
85cachePath :: Flags -> FilePath -> String -> FilePath
86cachePath flags filePath ext = cache_dir flags </> replaceExtension filePath ext
88elmo :: Flags -> FilePath -> FilePath
89elmo flags filePath = cachePath flags filePath "elmo"
91elmi :: Flags -> FilePath -> FilePath
92elmi flags filePath = cachePath flags filePath "elmi"
95buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO (String,ModuleInterface)
96buildFile flags moduleNum numModules interfaces filePath =
97 do compiled <- alreadyCompiled
101 handle <- openBinaryFile (elmi flags filePath) ReadMode
102 bits <- L.hGetContents handle
103 let info :: (String, ModuleInterface)
104 info = Binary.decode bits
105 L.length bits `seq` hClose handle
108 alreadyCompiled :: IO Bool
110 existsi <- doesFileExist (elmi flags filePath)
111 existso <- doesFileExist (elmo flags filePath)
112 if not existsi || not existso
114 else do tsrc <- getModificationTime filePath
115 tint <- getModificationTime (elmo flags filePath)
119 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
121 compile :: IO (String,ModuleInterface)
123 source <- readFile filePath
124 let name = case getModuleName source of
127 putStrLn $ concat [ number, " Compiling ", name
128 , replicate (max 1 (20 - length name)) ' '
129 , "( " ++ filePath ++ " )" ]
131 createDirectoryIfMissing True (cache_dir flags)
132 createDirectoryIfMissing True (build_dir flags)
134 case buildFromSource (no_prelude flags) interfaces source of
136 mapM print (List.intersperse (P.text " ") errors)
139 case print_program flags of
141 True -> print . pretty $ program modul
144 if print_types flags then printTypes interfaces metaModule else return ()
145 let interface = Canonical.interface name $ ModuleInterface {
146 iTypes = types metaModule,
147 iAdts = datatypes metaModule,
148 iAliases = aliases metaModule,
149 iFixities = fixities metaModule
151 createDirectoryIfMissing True . dropFileName $ elmi flags filePath
152 handle <- openBinaryFile (elmi flags filePath) WriteMode
153 L.hPut handle (Binary.encode (name,interface))
155 writeFile (elmo flags filePath) (jsModule metaModule)
156 return (name,interface)
158printTypes interfaces metaModule = do
160 let rules = Alias.rules interfaces metaModule
161 forM_ (Map.toList $ types metaModule) $ \(n,t) -> do
162 print $ variable n <+> P.text ":" <+> pretty (Alias.realias rules t)
165getRuntime :: Flags -> IO FilePath
167 case runtime flags of
169 Nothing -> getDataFileName "elm-runtime.js"
171build :: Flags -> FilePath -> IO ()
172build flags rootFile = do
173 let noPrelude = no_prelude flags
174 files <- if make flags then getSortedDependencies noPrelude rootFile else return [rootFile]
175 let ifaces = if noPrelude then Map.empty else Prelude.interfaces
176 (moduleName, interfaces) <- buildFiles flags (length files) ifaces "" files
177 js <- foldM appendToOutput BS.empty files
179 (extension, code) <- case only_js flags of
181 putStr "Generating JavaScript ... "
184 putStr "Generating HTML ... "
185 rtsPath <- getRuntime flags
186 return ("html", BS.pack . renderHtml $
187 createHtml rtsPath (takeBaseName rootFile) (sources js) moduleName "")
189 let targetFile = buildPath flags rootFile extension
190 createDirectoryIfMissing True (takeDirectory targetFile)
191 BS.writeFile targetFile code
195 appendToOutput :: BS.ByteString -> FilePath -> IO BS.ByteString
196 appendToOutput js filePath =
197 do src <- BS.readFile (elmo flags filePath)
198 return (BS.append src js)
200 sources js = map Link (scripts flags) ++ [ Source js ]
203buildFiles :: Flags -> Int -> Interfaces -> String -> [FilePath] -> IO (String, Interfaces)
204buildFiles _ _ interfaces moduleName [] = return (moduleName, interfaces)
205buildFiles flags numModules interfaces _ (filePath:rest) = do
206 (name,interface) <- buildFile flags (numModules - length rest) numModules interfaces filePath
207 let interfaces' = Map.insert name interface interfaces
208 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