on 87be397 help sign in
elk/elm/src/Compiler.hs
112 lines 4.7 kB history raw
1{-# LANGUAGE DeriveDataTypeable #-}
2module Main where
4import Data.Either (lefts, rights)
5import Data.List (intersect, intercalate)
6import Data.Maybe (fromMaybe)
7import Data.Version (showVersion)
8import System.Console.CmdArgs
9import System.FilePath
10import Text.Blaze.Html.Renderer.String (renderHtml)
12import qualified Text.Jasmine as JS
13import qualified Data.ByteString.Lazy.Char8 as BS
15import Ast
16import Initialize
17import CompileToJS
18import GenerateHtml
19import Paths_Elm
21data ELM =
22 ELM { make :: Bool
23 , files :: [FilePath]
24 , runtime :: Maybe FilePath
25 , separate_js :: Bool
26 , only_js :: Bool
27 , import_js :: [FilePath]
28 , generate_noscript :: Bool
29 , minify :: Bool
30 , output_directory :: Maybe FilePath
31 }
32 deriving (Data,Typeable,Show,Eq)
34elm = ELM { make = False &= help "automatically compile dependencies."
35 , files = def &= args &= typ "FILES"
36 , runtime = Nothing &= typFile &=
37 help "Specify a custom location for Elm's runtime system."
38 , separate_js = False &= help "Compile to separate HTML and JS files."
39 , only_js = False &= help "Compile only to JavaScript."
40 , import_js = [] &= typFile &= help "Include a JavaScript file before the body of the Elm program. Can be used many times. Files will be included in the given order."
41 , generate_noscript = True &= help "Add generated <noscript> tag to HTML output."
42 , minify = False &= help "Minify generated JavaScript"
43 , output_directory = Nothing &= typFile &= help "Output files to directory specified. Defaults to the location of original file."
44 } &=
45 help "Compile Elm programs to HTML, CSS, and JavaScript." &=
46 summary ("The Elm Compiler " ++ showVersion version ++ ", (c) Evan Czaplicki")
48main = do
49 args <- cmdArgs elm
50 mini <- getDataFileName ("elm-runtime-" ++ showVersion version ++ ".js")
51 compileArgs mini args
53compileArgs mini (ELM _ [] _ _ _ _ _ _ _) =
54 putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
55compileArgs mini (ELM make files rtLoc split only js nscrpt isMini outputDir) =
56 mapM_ (fileTo isMini get what js nscrpt outputDir $ fromMaybe mini rtLoc) files
57 where get = if make then getModules [] else getModule
58 what = if only then JS else
59 if split then Split else HTML
61data What = JS | HTML | Split
63fileTo isMini get what jsFiles noscript outputDir rtLoc file = do
64 let jsStyle = if isMini then Minified else Readable
65 let formatJS = if isMini then BS.unpack . JS.minify . BS.pack else id
66 ems <- get file
67 jss <- concat `fmap` mapM readFile jsFiles
68 case ems of
69 Left err -> putStrLn $ "Error while compiling " ++ file ++ ":\n" ++ err
70 Right ms ->
71 let path = fromMaybe "" outputDir </> file
72 js = replaceExtension path ".js"
73 html = replaceExtension path ".html"
74 in case what of
75 JS -> writeFile js . formatJS $ jss ++ concatMap jsModule ms
76 HTML -> writeFile html . renderHtml $ modulesToHtml jsStyle "" rtLoc jss noscript ms
77 Split -> do
78 writeFile html . renderHtml $ linkedHtml rtLoc js ms
79 writeFile js . formatJS $ jss ++ concatMap jsModule ms
81getModules :: [String] -> FilePath -> IO (Either String [([String],Module)])
82getModules uses file = do
83 code <- readFile file
84 case initialize code of
85 Left err -> return . Left $ "Error in " ++ file ++ ":\n" ++ err
86 Right (escs, modul@(Module _ _ imports _)) ->
87 let imps = filter (`notElem` builtInModules) $ map fst imports in
88 case intersect uses imps of
89 x:_ -> return . Left $ "Error: Cyclic dependency. Module " ++
90 x ++ " depends on itself."
91 [] -> do
92 ems <- mapM (getModules (uses ++ imps) . toFilePath) imps
93 return $ case lefts ems of
94 [] -> Right $ concat (rights ems) ++ [(escs,modul)]
95 errs -> Left $ intercalate "\n" errs
97getModule :: FilePath -> IO (Either String [([String],Module)])
98getModule file = do
99 code <- readFile file
100 return . fmap (:[]) $ initialize code
102toFilePath :: String -> FilePath
103toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm"
105builtInModules =
106 concat [ [ "List", "Char", "Maybe", "Dict", "Set", "Automaton", "Date" ]
107 , [ "Signal", "Mouse", "Keyboard.Raw"
108 , "Window", "Time", "HTTP", "Input", "Random" ]
109 , [ "Graphics", "Text", "Color" ]
110 , map ("JavaScript"++) [ "", ".Experimental" ]
111 , [ "Prelude", "JSON" ]
112 ]