on master help sign in
Get compiler working with multiple source files.
00619e6evancz
elm/Elm.cabal+5−3
@@ -1,6 +1,6 @@
1
1
2Name: Elm
2Name: Elm
3−Version: 0.2.1
3+Version: 0.3.0
4Synopsis: The Elm language module.
4Synopsis: The Elm language module.
5Description: Elm aims to make client-side web-development more pleasant.
5Description: Elm aims to make client-side web-development more pleasant.
6 It is a statically/strongly typed, functional reactive
6 It is a statically/strongly typed, functional reactive
@@ -21,7 +21,8 @@ Category: Compiler, Language
21
21
22Build-type: Simple
22Build-type: Simple
23
23
24−--Extra-source-files: README.md
24+Extra-source-files: README.md
25+Data-files: elm-runtime-0.3.0.js
25Cabal-version: >=1.8
26Cabal-version: >=1.8
26
27
27source-repository head
28source-repository head
@@ -96,4 +97,5 @@ Executable elm
96 parsec >= 3.1.1,
97 parsec >= 3.1.1,
97 blaze-html == 0.5.0.*,
98 blaze-html == 0.5.0.*,
98 blaze-markup == 0.5.1.*,
99 blaze-markup == 0.5.1.*,
99− deepseq
100+ deepseq,
101+ cmdargs
elm/src/Compiler.hs+77−43
@@ -1,49 +1,83 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
1module Main where
2module Main where
2
3
3−import Data.List (isPrefixOf)
4+import Data.Either (lefts, rights)
5+import Data.List (intersect, intercalate)
6+import Data.Maybe (fromMaybe)
7+import System.Console.CmdArgs
8+import Text.Blaze.Html.Renderer.String (renderHtml)
9+
10+import Ast
11+import Initialize
4import CompileToJS
12import CompileToJS
5import GenerateHtml
13import GenerateHtml
6−import System.Environment
14+import Paths_Elm
7−import Text.Blaze.Html.Renderer.String (renderHtml)
15+
16+
17+data ELM =
18+ ELM { make :: Bool
19+ , files :: [FilePath]
20+ , runtime :: Maybe FilePath
21+-- , separate_js :: Bool
22+-- , only_js :: Bool
23+-- , verbose_js :: Bool
24+ }
25+ deriving (Data,Typeable,Show,Eq)
26+
27+elm = ELM { make = False &= help "automatically compile dependencies."
28+ , files = def &= args &= typ "FILES"
29+ , runtime = Nothing &= typ "FILE" &=
30+ help "Specify a custom location for Elm's runtime system."
31+-- , separate_js = False &= help "Compile to separate HTML and JS files."
32+-- , only_js = False &= help "Compile only to JavaScript."
33+-- , verbose_js = False &= help "Produce JavaScript that may be easier to debug."
34+ } &=
35+ help "Compile Elm programs to HTML, CSS, and JavaScript." &=
36+ summary "The Elm Compiler v0.3.0, (c) Evan Czaplicki"
8
37
9−main :: IO ()
38+main = do
10−main = getArgs >>= parse
39+ args <- cmdArgs elm
11−
40+ mini <- getDataFileName "elm-runtime-0.3.0.js"
12−parse :: [String] -> IO ()
41+ compileArgs mini args
13−parse ("--help":_) = putStrLn usage
42+
14−parse ("--version":_) = putStrLn "The Elm Compiler 0.2.0.1"
43+compileArgs mini (ELM _ [] _) =
15−parse [loc,file]
44+ putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
16− | "--runtime-location=" `isPrefixOf` loc =
45+compileArgs mini (ELM make files rtLoc) =
46+ mapM_ (fileToHtml $ fromMaybe mini rtLoc) files
47+
48+fileToHtml rtLoc file = do
49+ ems <- getModules [] file
50+ case ems of
51+ Left err -> putStrLn $ "Error while compiling " ++ file ++ ":\n" ++ err
52+ Right ms ->
17− produceHtml (tail $ dropWhile (/='=') loc) file
53+ let name = reverse . tail . dropWhile (/='.') $ reverse file in
18− | otherwise = putStrLn usageMini
54+ writeFile (name ++ ".html") . renderHtml $
19−parse [file] = produceHtml "elm-mini.js" file
55+ modulesToHtml rtLoc ms
20−parse _ = putStrLn usageMini
56+
21−
57+
22−produceHtml :: String -> FilePath -> IO ()
58+getModules :: [String] -> FilePath -> IO (Either String [Module])
23−produceHtml libLoc file = do
59+getModules uses file = do
24 code <- readFile file
60 code <- readFile file
25− let name = takeWhile (/='.') file
61+ case initialize code of
26− case compile code of
62+ Left err -> return . Left $ "Error in " ++ file ++ ":\n" ++ err
27− Left err -> putStrLn err
63+ Right modul@(Module _ _ imports _) ->
28− Right jsCode -> writeFile (name ++ ".html") . renderHtml $
64+ let imps = filter (`notElem` builtInModules) $ map fst imports in
29− generateHtml libLoc name code
65+ case intersect uses imps of
30−
66+ x:_ -> return . Left $ "Error: Cyclic dependency. Module " ++
31−usageMini :: String
67+ x ++ " depends on itself."
32−usageMini =
68+ [] -> do
33− "Usage: elm [OPTIONS] FILE\n\
69+ ems <- mapM (getModules (uses ++ imps) . toFilePath) imps
34− \Try `elm --help' for more information."
70+ return $ case lefts ems of
35−
71+ [] -> Right $ concat (rights ems) ++ [modul]
36−usage :: String
72+ errs -> Left $ intercalate "\n" errs
37−usage =
73+
38− "Usage: elm [OPTIONS] FILE\n\
74+toFilePath :: String -> FilePath
39− \Compile .elm files to .html files.\n\
75+toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm"
40− \Example: elm --runtime-location=../elm-mini.js main.elm\n\
76+
41− \\n\
77+builtInModules =
42− \Resource Locations:\n\
78+ concat [ map ("Data."++) [ "List", "Char", "Maybe" ]
43− \ --runtime-location set the location of the Elm runtime (elm-mini.js)\n\
79+ , map ("Signal."++) [ "Mouse", "Keyboard.Raw"
44− \\n\
80+ , "Window", "Time", "HTTP", "Input", "Random" ]
45− \Compiler Information:\n\
81+ , [ "Element", "Text", "Color", "Line" ]
46− \ --version print the version information and exit\n\
82+ , [ "Prelude" ]
47− \ --help display this help and exit\n\
83+ ]
48− \\n\
49− \Elm home page: <http://elm-lang.org>"
elm/src/Gen/CompileToJS.hs+7−8
@@ -1,5 +1,5 @@
1
1
2−module CompileToJS (compile, compileToJS) where
2+module CompileToJS (showErr, jsModule) where
3
3
4import Ast
4import Ast
5import Control.Monad (liftM,(<=<),join)
5import Control.Monad (liftM,(<=<),join)
@@ -14,9 +14,6 @@ showErr :: String -> String
14showErr err = mainEquals $ "text(monospace(" ++ msg ++ "))"
14showErr err = mainEquals $ "text(monospace(" ++ msg ++ "))"
15 where msg = show . concatMap (++"<br>") . lines $ err
15 where msg = show . concatMap (++"<br>") . lines $ err
16
16
17−compile str = jsModule `liftM` initialize str
18−compileToJS = either showErr jsModule
19−
20parens = ("("++) . (++")")
17parens = ("("++) . (++")")
21braces = ("{"++) . (++"}")
18braces = ("{"++) . (++"}")
22jsList = ("["++) . (++"]") . intercalate ","
19jsList = ("["++) . (++"]") . intercalate ","
@@ -28,11 +25,13 @@ iff a b c = a ++ "?" ++ b ++ ":" ++ c
28mainEquals s = globalAssign "ElmCode.main" (jsFunc "" (ret s))
25mainEquals s = globalAssign "ElmCode.main" (jsFunc "" (ret s))
29globalAssign m s = "\n" ++ m ++ "=" ++ s ++ ";"
26globalAssign m s = "\n" ++ m ++ "=" ++ s ++ ";"
30
27
31−tryBlock e =
28+tryBlock names e =
32 unlines [ "\ntry{\n" ++ e ++ "\n\n} catch (e) {"
29 unlines [ "\ntry{\n" ++ e ++ "\n\n} catch (e) {"
33 , "ElmCode.main=function() {"
30 , "ElmCode.main=function() {"
34− , "var msg = ('<br><h2>Your browser may not be supported. Are you using a modern browser?</h2>' +" ++
31+ , "var msg = ('<br><h2>Your browser may not be supported. " ++
32+ "Are you using a modern browser?</h2>' +" ++
35− " '<br><span style=\"grey\">Runtime Error:<br>' + e + '</span>')"
33+ " '<br><span style=\"color:grey\">Runtime Error in " ++
34+ intercalate "." names ++ " module:<br>' + e + '</span>')"
36 , "document.body.innerHTML = Text.monospace(msg);"
35 , "document.body.innerHTML = Text.monospace(msg);"
37 , "throw e;"
36 , "throw e;"
38 , "};}"
37 , "};}"
@@ -40,7 +39,7 @@ tryBlock e =
40
39
41
40
42jsModule (Module names exports imports defs) =
41jsModule (Module names exports imports defs) =
43− tryBlock $ unwords
42+ tryBlock (tail modNames) $ unwords
44 [ concatMap (\n -> globalAssign n $ n ++ " || {}") . map (intercalate ".") . drop 2 . inits $ take (length modNames - 1) modNames
43 [ concatMap (\n -> globalAssign n $ n ++ " || {}") . map (intercalate ".") . drop 2 . inits $ take (length modNames - 1) modNames
45 , "\nif (" ++ modName ++ ") throw 'Module name collision, " ++ intercalate "." names ++ " is already defined.'; "
44 , "\nif (" ++ modName ++ ") throw 'Module name collision, " ++ intercalate "." names ++ " is already defined.'; "
46 , globalAssign modName $ jsFunc "" (includes ++ body ++ export) ++ "()"
45 , globalAssign modName $ jsFunc "" (includes ++ body ++ export) ++ "()"
elm/src/Gen/GenerateHtml.hs+13−19
@@ -1,6 +1,7 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2−module GenerateHtml (generateHtml, body, css, widgetBody) where
2+module GenerateHtml (generateHtml, body, css, widgetBody, modulesToHtml) where
3
3
4+import Data.List (intercalate)
4import Text.Blaze (preEscapedToMarkup)
5import Text.Blaze (preEscapedToMarkup)
5import Text.Blaze.Html (Html)
6import Text.Blaze.Html (Html)
6import qualified Text.Blaze.Html5 as H
7import qualified Text.Blaze.Html5 as H
@@ -25,17 +26,6 @@ css = H.style ! A.type_ "text/css" $ preEscapedToMarkup
25makeScript :: String -> H.Html
26makeScript :: String -> H.Html
26makeScript s = H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ ""
27makeScript s = H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ ""
27
28
28−scriptForModule :: String -> H.Html
29−scriptForModule modul =
30− makeScript $ "/" ++ map (\c -> if c == '.' then '/' else c) modul ++ ".js"
31−
32−builtInModules =
33− concat [ map ("Data."++) [ "List", "Char", "Maybe" ]
34− , map ("Signal."++) [ "Mouse", "Keyboard.Raw"
35− , "Window", "Time", "HTTP", "Input", "Random" ]
36− , [ "Element", "Text", "Color", "Line" ]
37− , [ "Prelude" ]
38− ]
39
29
40-- |This function compiles Elm code into simple HTML.
30-- |This function compiles Elm code into simple HTML.
41--
31--
@@ -47,18 +37,22 @@ generateHtml :: String -- ^ Location of elm-min.js as expected by the browser
47 -> String -- ^ The elm source code.
37 -> String -- ^ The elm source code.
48 -> Html
38 -> Html
49generateHtml libLoc title source =
39generateHtml libLoc title source =
50− let modul = initialize source
40+ case initialize source of
51− imports = filter (`notElem` builtInModules) $
41+ Left err -> createHtml libLoc title (showErr err) (H.noscript "")
52− either (const []) (\(Module _ _ is _) -> map fst is) modul
42+ Right modul -> modulesToHtml libLoc [modul]
53− js = compileToJS modul
43+
44+
45+modulesToHtml libLoc modules = createHtml libLoc title js noscript
46+ where title = (\(Module names _ _ _) -> intercalate "." names) $ last modules
47+ js = concatMap jsModule modules
54− noscript = either id extract modul
48+ noscript = extract $ last modules
55− in
49+
50+createHtml libLoc title js noscript =
56 H.docTypeHtml $ do
51 H.docTypeHtml $ do
57 H.head $ do
52 H.head $ do
58 H.meta ! A.charset "UTF-8"
53 H.meta ! A.charset "UTF-8"
59 H.title . H.toHtml $ title
54 H.title . H.toHtml $ title
60 makeScript libLoc
55 makeScript libLoc
61− mapM scriptForModule imports
62 H.script ! A.type_ "text/javascript" $ preEscapedToMarkup js
56 H.script ! A.type_ "text/javascript" $ preEscapedToMarkup js
63 css
57 css
64 H.body $ body noscript
58 H.body $ body noscript
elm/src/Language/Elm.hs+3−3
@@ -69,6 +69,6 @@ instance ElmSource (t -> Elm) where
69-- build helper to avoid boilerplate repetition
69-- build helper to avoid boilerplate repetition
70toPartsHelper :: String -> (Html, Html, String)
70toPartsHelper :: String -> (Html, Html, String)
71toPartsHelper source = (html, css, js)
71toPartsHelper source = (html, css, js)
72− where expr = initialize source
72+ where modul = initialize source
73− js = compileToJS expr
73+ js = either showErr jsModule modul
74− html = widgetBody $ either id extract expr
74+ html = widgetBody $ either id extract modul