on master help sign in
Get compiler working with multiple source files.
commit00619e6d79e552128354ebebd9791ded8398462d authorevancz <info@elm-lang.org> dateThu 14 Jun 2012, 03:43 (14 years ago) parentc9a6398
5 files changed+105−76
elm/Elm.cabal+5−3 elm/src/Compiler.hs+77−43 elm/src/Gen/CompileToJS.hs+7−8 elm/src/Gen/GenerateHtml.hs+13−19 elm/src/Language/Elm.hs+3−3
elm/Elm.cabal+5−3
@@ -1,6 +1,6 @@
11
22Name: Elm
3−Version: 0.2.1
3+Version: 0.3.0
44Synopsis: The Elm language module.
55Description: Elm aims to make client-side web-development more pleasant.
66 It is a statically/strongly typed, functional reactive
@@ -21,7 +21,8 @@ Category: Compiler, Language
2121
2222Build-type: Simple
2323
24−--Extra-source-files: README.md
24+Extra-source-files: README.md
25+Data-files: elm-runtime-0.3.0.js
2526Cabal-version: >=1.8
2627
2728source-repository head
@@ -96,4 +97,5 @@ Executable elm
9697 parsec >= 3.1.1,
9798 blaze-html == 0.5.0.*,
9899 blaze-markup == 0.5.1.*,
99− deepseq
100+ deepseq,
101+ cmdargs
elm/src/Compiler.hs+77−43
@@ -1,49 +1,83 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
12module Main where
23
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
412import CompileToJS
513import GenerateHtml
6−import System.Environment
7−import Text.Blaze.Html.Renderer.String (renderHtml)
14+import Paths_Elm
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"
837
9−main :: IO ()
10−main = getArgs >>= parse
11−
12−parse :: [String] -> IO ()
13−parse ("--help":_) = putStrLn usage
14−parse ("--version":_) = putStrLn "The Elm Compiler 0.2.0.1"
15−parse [loc,file]
16− | "--runtime-location=" `isPrefixOf` loc =
17− produceHtml (tail $ dropWhile (/='=') loc) file
18− | otherwise = putStrLn usageMini
19−parse [file] = produceHtml "elm-mini.js" file
20−parse _ = putStrLn usageMini
21−
22−produceHtml :: String -> FilePath -> IO ()
23−produceHtml libLoc file = do
38+main = do
39+ args <- cmdArgs elm
40+ mini <- getDataFileName "elm-runtime-0.3.0.js"
41+ compileArgs mini args
42+
43+compileArgs mini (ELM _ [] _) =
44+ putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
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 ->
53+ let name = reverse . tail . dropWhile (/='.') $ reverse file in
54+ writeFile (name ++ ".html") . renderHtml $
55+ modulesToHtml rtLoc ms
56+
57+
58+getModules :: [String] -> FilePath -> IO (Either String [Module])
59+getModules uses file = do
2460 code <- readFile file
25− let name = takeWhile (/='.') file
26− case compile code of
27− Left err -> putStrLn err
28− Right jsCode -> writeFile (name ++ ".html") . renderHtml $
29− generateHtml libLoc name code
30−
31−usageMini :: String
32−usageMini =
33− "Usage: elm [OPTIONS] FILE\n\
34− \Try `elm --help' for more information."
35−
36−usage :: String
37−usage =
38− "Usage: elm [OPTIONS] FILE\n\
39− \Compile .elm files to .html files.\n\
40− \Example: elm --runtime-location=../elm-mini.js main.elm\n\
41− \\n\
42− \Resource Locations:\n\
43− \ --runtime-location set the location of the Elm runtime (elm-mini.js)\n\
44− \\n\
45− \Compiler Information:\n\
46− \ --version print the version information and exit\n\
47− \ --help display this help and exit\n\
48− \\n\
49− \Elm home page: <http://elm-lang.org>"
61+ case initialize code of
62+ Left err -> return . Left $ "Error in " ++ file ++ ":\n" ++ err
63+ Right modul@(Module _ _ imports _) ->
64+ let imps = filter (`notElem` builtInModules) $ map fst imports in
65+ case intersect uses imps of
66+ x:_ -> return . Left $ "Error: Cyclic dependency. Module " ++
67+ x ++ " depends on itself."
68+ [] -> do
69+ ems <- mapM (getModules (uses ++ imps) . toFilePath) imps
70+ return $ case lefts ems of
71+ [] -> Right $ concat (rights ems) ++ [modul]
72+ errs -> Left $ intercalate "\n" errs
73+
74+toFilePath :: String -> FilePath
75+toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm"
76+
77+builtInModules =
78+ concat [ map ("Data."++) [ "List", "Char", "Maybe" ]
79+ , map ("Signal."++) [ "Mouse", "Keyboard.Raw"
80+ , "Window", "Time", "HTTP", "Input", "Random" ]
81+ , [ "Element", "Text", "Color", "Line" ]
82+ , [ "Prelude" ]
83+ ]
elm/src/Gen/CompileToJS.hs+7−8
@@ -1,5 +1,5 @@
11
2−module CompileToJS (compile, compileToJS) where
2+module CompileToJS (showErr, jsModule) where
33
44import Ast
55import Control.Monad (liftM,(<=<),join)
@@ -14,9 +14,6 @@ showErr :: String -> String
1414showErr err = mainEquals $ "text(monospace(" ++ msg ++ "))"
1515 where msg = show . concatMap (++"<br>") . lines $ err
1616
17−compile str = jsModule `liftM` initialize str
18−compileToJS = either showErr jsModule
19−
2017parens = ("("++) . (++")")
2118braces = ("{"++) . (++"}")
2219jsList = ("["++) . (++"]") . intercalate ","
@@ -28,11 +25,13 @@ iff a b c = a ++ "?" ++ b ++ ":" ++ c
2825mainEquals s = globalAssign "ElmCode.main" (jsFunc "" (ret s))
2926globalAssign m s = "\n" ++ m ++ "=" ++ s ++ ";"
3027
31−tryBlock e =
28+tryBlock names e =
3229 unlines [ "\ntry{\n" ++ e ++ "\n\n} catch (e) {"
3330 , "ElmCode.main=function() {"
34− , "var msg = ('<br><h2>Your browser may not be supported. Are you using a modern browser?</h2>' +" ++
35− " '<br><span style=\"grey\">Runtime Error:<br>' + e + '</span>')"
31+ , "var msg = ('<br><h2>Your browser may not be supported. " ++
32+ "Are you using a modern browser?</h2>' +" ++
33+ " '<br><span style=\"color:grey\">Runtime Error in " ++
34+ intercalate "." names ++ " module:<br>' + e + '</span>')"
3635 , "document.body.innerHTML = Text.monospace(msg);"
3736 , "throw e;"
3837 , "};}"
@@ -40,7 +39,7 @@ tryBlock e =
4039
4140
4241jsModule (Module names exports imports defs) =
43− tryBlock $ unwords
42+ tryBlock (tail modNames) $ unwords
4443 [ concatMap (\n -> globalAssign n $ n ++ " || {}") . map (intercalate ".") . drop 2 . inits $ take (length modNames - 1) modNames
4544 , "\nif (" ++ modName ++ ") throw 'Module name collision, " ++ intercalate "." names ++ " is already defined.'; "
4645 , globalAssign modName $ jsFunc "" (includes ++ body ++ export) ++ "()"
elm/src/Gen/GenerateHtml.hs+13−19
@@ -1,6 +1,7 @@
11{-# LANGUAGE OverloadedStrings #-}
2−module GenerateHtml (generateHtml, body, css, widgetBody) where
2+module GenerateHtml (generateHtml, body, css, widgetBody, modulesToHtml) where
33
4+import Data.List (intercalate)
45import Text.Blaze (preEscapedToMarkup)
56import Text.Blaze.Html (Html)
67import qualified Text.Blaze.Html5 as H
@@ -25,17 +26,6 @@ css = H.style ! A.type_ "text/css" $ preEscapedToMarkup
2526makeScript :: String -> H.Html
2627makeScript s = H.script ! A.type_ "text/javascript" ! A.src (H.toValue s) $ ""
2728
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− ]
3929
4030-- |This function compiles Elm code into simple HTML.
4131--
@@ -47,18 +37,22 @@ generateHtml :: String -- ^ Location of elm-min.js as expected by the browser
4737 -> String -- ^ The elm source code.
4838 -> Html
4939generateHtml libLoc title source =
50− let modul = initialize source
51− imports = filter (`notElem` builtInModules) $
52− either (const []) (\(Module _ _ is _) -> map fst is) modul
53− js = compileToJS modul
54− noscript = either id extract modul
55− in
40+ case initialize source of
41+ Left err -> createHtml libLoc title (showErr err) (H.noscript "")
42+ Right modul -> modulesToHtml libLoc [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
48+ noscript = extract $ last modules
49+
50+createHtml libLoc title js noscript =
5651 H.docTypeHtml $ do
5752 H.head $ do
5853 H.meta ! A.charset "UTF-8"
5954 H.title . H.toHtml $ title
6055 makeScript libLoc
61− mapM scriptForModule imports
6256 H.script ! A.type_ "text/javascript" $ preEscapedToMarkup js
6357 css
6458 H.body $ body noscript
elm/src/Language/Elm.hs+3−3
@@ -69,6 +69,6 @@ instance ElmSource (t -> Elm) where
6969-- build helper to avoid boilerplate repetition
7070toPartsHelper :: String -> (Html, Html, String)
7171toPartsHelper source = (html, css, js)
72− where expr = initialize source
73− js = compileToJS expr
74− html = widgetBody $ either id extract expr
72+ where modul = initialize source
73+ js = either showErr jsModule modul
74+ html = widgetBody $ either id extract modul