1{-# LANGUAGE DeriveDataTypeable #-}
5import qualified Data.Map as Map
6import qualified Data.List as List
7import Data.Binary (encodeFile, decodeFile)
8import Data.Version (showVersion)
9import System.Console.CmdArgs
10import System.Directory
14import qualified Text.Blaze.Html.Renderer.Pretty as Pretty
15import qualified Text.Blaze.Html.Renderer.String as Normal
16import qualified Text.Jasmine as JS
17import qualified Data.ByteString.Lazy.Char8 as BS
19import SourceSyntax.Module
20import Initialize (buildFromSource, getSortedModuleNames, TypeLibrary)
21import Generate.JavaScript (jsModule)
22import Generate.Html (createHtml, JSStyle(..), JSSource(..))
25import Text.PrettyPrint as P
26import qualified Type.Type as Type
27import qualified Parse.Type as Parse
28import qualified Data.Traversable as Traverse
33 , runtime :: Maybe FilePath
36 , scripts :: [FilePath]
39 , output_directory :: FilePath
41 deriving (Data,Typeable,Show,Eq)
45 &= help "automatically compile dependencies."
46 , files = def &= args &= typ "FILES"
47 , runtime = Nothing &= typFile
48 &= help "Specify a custom location for Elm's runtime system."
50 &= help "Compile only to JavaScript."
52 &= help "Print out infered types of top-level definitions."
53 , scripts = [] &= typFile
54 &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
56 &= help "Do not import Prelude by default, used only when compiling standard libraries."
58 &= help "Minify generated JavaScript and HTML"
59 , output_directory = "ElmFiles" &= typFile
60 &= help "Output files to directory specified. Defaults to ElmFiles/ directory."
61 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
62 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
65main = compileArgs =<< cmdArgs flags
67compileArgs :: Flags -> IO ()
70 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
71 fs -> mapM_ (build flags) fs
74file :: Flags -> FilePath -> String -> FilePath
75file flags filePath ext = output_directory flags </> replaceExtension filePath ext
77elmo :: Flags -> FilePath -> FilePath
78elmo flags filePath = file flags filePath "elmo"
79elmi flags filePath = file flags filePath "elmi"
82buildFile :: Flags -> Int -> Int -> TypeLibrary -> FilePath -> IO ModuleInterface
83buildFile flags moduleNum numModules interfaces filePath =
84 do compiled <- alreadyCompiled
85 if compiled then decodeFile (elmi flags filePath) else compile
88 alreadyCompiled :: IO Bool
90 exists <- doesFileExist (elmo flags filePath)
91 if not exists then return False
92 else do tsrc <- getModificationTime filePath
93 tint <- getModificationTime (elmo flags filePath)
97 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
100 name = List.intercalate "." (splitDirectories (dropExtensions filePath))
102 compile :: IO ModuleInterface
104 putStrLn (number ++ " Compiling " ++ name)
105 source <- readFile filePath
106 createDirectoryIfMissing True (output_directory flags)
108 case buildFromSource interfaces source of
109 Left err -> mapM print err >> exitFailure
110 Right modul -> return (modul :: MetadataModule () ())
111 if print_types flags then printTypes metaModule else return ()
112 tipes <- toSrcTypes (types metaModule)
113 let fmt (name, tvars, ctors) = (name, (length tvars, map fst ctors))
114 interface = ModuleInterface {
116 iAdts = Map.fromList . map fmt $ datatypes metaModule
118 encodeFile (elmi flags filePath) interface
119 let js = jsModule metaModule
120 writeFile (elmo flags filePath) js
123toSrcTypes tipes = Traverse.traverse convert tipes
125 convert t = fmap (Parse.readType . P.render) (Type.extraPretty t)
127printTypes metaModule = do
129 forM_ (Map.toList $ types metaModule) $ \(n,t) -> do
130 pt <- Type.extraPretty t
131 print $ P.text n <+> P.text ":" <+> pt
134getRuntime :: Flags -> IO FilePath
136 case runtime flags of
138 Nothing -> getDataFileName "elm-runtime.js"
140build :: Flags -> FilePath -> IO ()
141build flags rootFile = do
142 files <- if make flags then getSortedModuleNames rootFile else return [rootFile]
143 let initialInterface = if no_prelude flags then Map.empty else Map.empty
144 interfaces <- buildFiles flags (length files) initialInterface files
145 js <- foldM appendToOutput "" files
146 case only_js flags of
148 putStr "Generating JavaScript ... "
149 writeFile (file flags rootFile "js") (genJs js)
152 putStr "Generating HTML ... "
153 runtime <- getRuntime flags
154 let html = genHtml $ createHtml runtime rootFile (sources js) ""
155 writeFile (file flags rootFile "html") html
159 appendToOutput :: String -> FilePath -> IO String
160 appendToOutput js filePath =
161 do src <- readFile (elmo flags filePath)
164 genHtml = if minify flags then Normal.renderHtml else Pretty.renderHtml
165 genJs = if minify flags then BS.unpack . JS.minify . BS.pack else id
166 sources js = map Link (scripts flags) ++
167 [ Source (if minify flags then Minified else Readable) js ]
170buildFiles :: Flags -> Int -> TypeLibrary -> [FilePath] -> IO TypeLibrary
171buildFiles _ _ interfaces [] = return interfaces
172buildFiles flags numModules interfaces (filePath:rest) = do
173 interface <- buildFile flags (numModules - length rest) numModules interfaces filePath
174 let moduleName = List.intercalate "." (splitDirectories (dropExtensions filePath))
175 interfaces' = Map.insert moduleName interface interfaces
176 buildFiles flags numModules interfaces' 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