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
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 qualified Metadata.Prelude as Prelude
20import SourceSyntax.Module
21import Initialize (buildFromSource, getSortedModuleNames, Interfaces)
22import Generate.JavaScript (jsModule)
23import Generate.Html (createHtml, JSStyle(..), JSSource(..))
26import SourceSyntax.PrettyPrint (pretty, variable)
27import Text.PrettyPrint as P
28import qualified Type.Type as Type
29import qualified Parse.Type as Parse
30import qualified Data.Traversable as Traverse
35 , runtime :: Maybe FilePath
38 , print_program :: Bool
39 , scripts :: [FilePath]
42 , output_directory :: FilePath
44 deriving (Data,Typeable,Show,Eq)
48 &= help "automatically compile dependencies."
49 , files = def &= args &= typ "FILES"
50 , runtime = Nothing &= typFile
51 &= help "Specify a custom location for Elm's runtime system."
53 &= help "Compile only to JavaScript."
55 &= help "Print out infered types of top-level definitions."
56 , print_program = False
57 &= help "Print out an internal representation of a program."
58 , scripts = [] &= typFile
59 &= help "Load JavaScript files in generated HTML. Files will be included in the given order."
61 &= help "Do not import Prelude by default, used only when compiling standard libraries."
63 &= help "Minify generated JavaScript and HTML"
64 , output_directory = "ElmFiles" &= typFile
65 &= help "Output files to directory specified. Defaults to ElmFiles/ directory."
66 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
67 &= summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
70main = compileArgs =<< cmdArgs flags
72compileArgs :: Flags -> IO ()
75 [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
76 fs -> mapM_ (build flags) fs
79file :: Flags -> FilePath -> String -> FilePath
80file flags filePath ext = output_directory flags </> replaceExtension filePath ext
82elmo :: Flags -> FilePath -> FilePath
83elmo flags filePath = file flags filePath "elmo"
84elmi flags filePath = file flags filePath "elmi"
87buildFile :: Flags -> Int -> Int -> Interfaces -> FilePath -> IO ModuleInterface
88buildFile flags moduleNum numModules interfaces filePath =
89 do compiled <- alreadyCompiled
90 if compiled then Binary.decodeFile (elmi flags filePath) else compile
93 alreadyCompiled :: IO Bool
95 exists <- doesFileExist (elmo flags filePath)
96 if not exists then return False
97 else do tsrc <- getModificationTime filePath
98 tint <- getModificationTime (elmo flags filePath)
102 number = "[" ++ show moduleNum ++ " of " ++ show numModules ++ "]"
105 name = List.intercalate "." (splitDirectories (dropExtensions filePath))
107 compile :: IO ModuleInterface
109 putStrLn (number ++ " Compiling " ++ name)
110 source <- readFile filePath
111 createDirectoryIfMissing True (output_directory flags)
113 case buildFromSource interfaces source of
114 Left err -> mapM print err >> exitFailure
116 if print_program flags then print . pretty $ program modul else return ()
119 if print_types flags then printTypes metaModule else return ()
120 tipes <- toSrcTypes (types metaModule)
121 let interface = ModuleInterface {
123 iAdts = datatypes metaModule,
124 iAliases = aliases metaModule
126 Binary.encodeFile (elmi flags filePath) interface
127 let js = jsModule metaModule
128 writeFile (elmo flags filePath) js
131toSrcTypes tipes = Traverse.traverse convert tipes
133 convert t = fmap (Parse.readType . P.render) (Type.extraPretty t)
135printTypes metaModule = do
137 forM_ (Map.toList $ types metaModule) $ \(n,t) -> do
138 pt <- Type.extraPretty t
139 print $ variable n <+> P.text ":" <+> pt
142getRuntime :: Flags -> IO FilePath
144 case runtime flags of
146 Nothing -> getDataFileName "elm-runtime.js"
148build :: Flags -> FilePath -> IO ()
149build flags rootFile = do
150 files <- if make flags then getSortedModuleNames rootFile else return [rootFile]
151 interfaces <- buildFiles flags (length files) Prelude.interfaces files
152 js <- foldM appendToOutput "" files
153 case only_js flags of
155 putStr "Generating JavaScript ... "
156 writeFile (file flags rootFile "js") (genJs js)
159 putStr "Generating HTML ... "
160 runtime <- getRuntime flags
161 let html = genHtml $ createHtml runtime rootFile (sources js) ""
162 writeFile (file flags rootFile "html") html
166 appendToOutput :: String -> FilePath -> IO String
167 appendToOutput js filePath =
168 do src <- readFile (elmo flags filePath)
171 genHtml = if minify flags then Normal.renderHtml else Pretty.renderHtml
172 genJs = if minify flags then BS.unpack . JS.minify . BS.pack else id
173 sources js = map Link (scripts flags) ++
174 [ Source (if minify flags then Minified else Readable) js ]
177buildFiles :: Flags -> Int -> Interfaces -> [FilePath] -> IO Interfaces
178buildFiles _ _ interfaces [] = return interfaces
179buildFiles flags numModules interfaces (filePath:rest) = do
180 interface <- buildFile flags (numModules - length rest) numModules interfaces filePath
181 let moduleName = List.intercalate "." (splitDirectories (dropExtensions filePath))
182 interfaces' = Map.insert moduleName interface interfaces
183 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