on 46df5ff help sign in
elk/elm/src/Compiler.hs
101 lines 3.9 kB history raw
1{-# LANGUAGE DeriveDataTypeable #-}
2module Main where
4import Data.Either (lefts, rights)
5import Data.List (intersect, intercalate)
6import Data.Maybe (fromMaybe)
7import System.Console.CmdArgs
8import Text.Blaze.Html.Renderer.String (renderHtml)
10import Ast
11import Initialize
12import CompileToJS
13import GenerateHtml
14import Paths_Elm
17data ELM =
18 ELM { make :: Bool
19 , files :: [FilePath]
20 , runtime :: Maybe FilePath
21 , separate_js :: Bool
22 , only_js :: Bool
23 , import_js :: [FilePath]
24 , generate_noscript :: Bool
25 }
26 deriving (Data,Typeable,Show,Eq)
28elm = ELM { make = False &= help "automatically compile dependencies."
29 , files = def &= args &= typ "FILES"
30 , runtime = Nothing &= typFile &=
31 help "Specify a custom location for Elm's runtime system."
32 , separate_js = False &= help "Compile to separate HTML and JS files."
33 , only_js = False &= help "Compile only to JavaScript."
34 , 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."
35 , generate_noscript = False &= help "Add generated <noscript> tag to HTML output."
36 } &=
37 help "Compile Elm programs to HTML, CSS, and JavaScript." &=
38 summary "The Elm Compiler v0.3.6, (c) Evan Czaplicki"
40main = do
41 args <- cmdArgs elm
42 mini <- getDataFileName "elm-runtime-0.3.6.js"
43 compileArgs mini args
45compileArgs mini (ELM _ [] _ _ _ _ _) =
46 putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
47compileArgs mini (ELM make files rtLoc split only js nscrpt) =
48 mapM_ (fileTo get what js nscrpt $ fromMaybe mini rtLoc) files
49 where get = if make then getModules [] else getModule
50 what = if only then JS else
51 if split then Split else HTML
53data What = JS | HTML | Split
55fileTo get what jsFiles noscript rtLoc file = do
56 ems <- get file
57 jss <- concat `fmap` mapM readFile jsFiles
58 case ems of
59 Left err -> putStrLn $ "Error while compiling " ++ file ++ ":\n" ++ err
60 Right ms ->
61 let name = reverse . tail . dropWhile (/='.') $ reverse file
62 js = name ++ ".js"
63 html = name ++ ".html"
64 in case what of
65 JS -> writeFile js $ jss ++ concatMap jsModule ms
66 HTML -> writeFile html . renderHtml $ modulesToHtml "" rtLoc jss noscript ms
67 Split -> do
68 writeFile html . renderHtml $ linkedHtml rtLoc js ms
69 writeFile js $ jss ++ concatMap jsModule ms
71getModules :: [String] -> FilePath -> IO (Either String [Module])
72getModules uses file = do
73 code <- readFile file
74 case initialize code of
75 Left err -> return . Left $ "Error in " ++ file ++ ":\n" ++ err
76 Right modul@(Module _ _ imports _) ->
77 let imps = filter (`notElem` builtInModules) $ map fst imports in
78 case intersect uses imps of
79 x:_ -> return . Left $ "Error: Cyclic dependency. Module " ++
80 x ++ " depends on itself."
81 [] -> do
82 ems <- mapM (getModules (uses ++ imps) . toFilePath) imps
83 return $ case lefts ems of
84 [] -> Right $ concat (rights ems) ++ [modul]
85 errs -> Left $ intercalate "\n" errs
87getModule :: FilePath -> IO (Either String [Module])
88getModule file = do
89 code <- readFile file
90 return . fmap (:[]) $ initialize code
92toFilePath :: String -> FilePath
93toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm"
95builtInModules =
96 concat [ map ("Data."++) [ "List", "Char", "Maybe" ]
97 , map ("Signal."++) [ "Mouse", "Keyboard.Raw"
98 , "Window", "Time", "HTTP", "Input", "Random" ]
99 , [ "Element", "Text", "Color", "Line" ]
100 , [ "Prelude" ]
101 ]