on master help sign in
Change semantics of import:

- No more 'hiding' - 'import' means allow the use of a the module, not import everything Make the --make command more robust. Begin making it possible to read Native files in core. Switch representation of let-expressions to no longer use an anonymous function. This is significantly faster! Begin disallowing undefined variables (stop passing escapees around so much).

commitc5519e304631605bc8a23ed2ddb67b5960138d2b authorevancz <info@elm-lang.org> dateTue 26 Feb 2013, 23:33 (14 years ago) parent389a6f5
12 files changed+205−207
elm/Elm.cabal+2 elm/src/Ast.hs+1−1 elm/src/Compiler.hs+5−5 elm/src/Gen/CompileToJS.hs+97−114 elm/src/Gen/GenerateHtml.hs+9−10 elm/src/Initialize.hs+66−56 elm/src/Language/Elm.hs+1−1 elm/src/Parse/Library.hs+1−1 elm/src/Parse/Modules.hs+1−6 elm/src/Parse/Parser.hs+17−4 elm/src/Types/Constrain.hs+4−3 elm/src/Types/Unify.hs+1−6
elm/Elm.cabal+2
@@ -41,6 +41,7 @@ Library
4141 ExtractNoscript,
4242 GenerateHtml,
4343 Guid,
44+ LetBoundVars,
4445 Optimize,
4546 Initialize,
4647 Rename,
@@ -89,6 +90,7 @@ Executable elm
8990 ExtractNoscript,
9091 GenerateHtml,
9192 Guid,
93+ LetBoundVars,
9294 Optimize,
9395 Initialize,
9496 Rename,
elm/src/Ast.hs+1−1
@@ -12,7 +12,7 @@ data Module = Module [String] Exports Imports [Statement]
1212type Exports = [String]
1313
1414type Imports = [(String, ImportMethod)]
15−data ImportMethod = As String | Hiding [String] | Importing [String]
15+data ImportMethod = As String | Importing [String]
1616 deriving (Eq,Ord)
1717
1818
elm/src/Compiler.hs+5−5
@@ -64,7 +64,8 @@ data What = JS | HTML | Split
6464fileTo isMini make what jsFiles noscript outputDir rtLoc file = do
6565 let jsStyle = if isMini then Minified else Readable
6666 formatJS = if isMini then BS.unpack . JS.minify . BS.pack else id
67− ems <- build make file
67+ ems <- if make then build file else do src <- readFile file
68+ return (fmap (:[]) (buildFromSource src))
6869 jss <- concat `fmap` mapM readFile jsFiles
6970 case ems of
7071 Left err -> putStrLn $ "Error while compiling " ++ file ++ ":\n" ++ err
@@ -72,12 +73,11 @@ fileTo isMini make what jsFiles noscript outputDir rtLoc file = do
7273 let path = fromMaybe "" outputDir </> file
7374 js = replaceExtension path ".js"
7475 html = replaceExtension path ".html"
75− pairs = map ((,) (fst ms)) (snd ms)
76− txt = jss ++ concatMap jsModule pairs
76+ txt = jss ++ concatMap jsModule ms
7777 in case what of
7878 JS -> writeFile js (formatJS txt)
7979 HTML -> writeFile html . renderHtml $
80− modulesToHtml jsStyle "" rtLoc jss noscript pairs
80+ modulesToHtml jsStyle "" rtLoc jss noscript ms
8181 Split ->
82− do writeFile html . renderHtml $ linkedHtml rtLoc js pairs
82+ do writeFile html . renderHtml $ linkedHtml rtLoc js ms
8383 writeFile js (formatJS txt)
elm/src/Gen/CompileToJS.hs+97−114
@@ -1,7 +1,5 @@
11module CompileToJS (showErr, jsModule) where
22
3−import Ast
4−import Context
53import Control.Arrow (first,second)
64import Control.Monad (liftM,(<=<),join,ap)
75import Data.Char (isAlpha,isDigit)
@@ -10,12 +8,15 @@ import qualified Data.Map as Map
108import Data.Either (partitionEithers)
119import qualified Text.Pandoc as Pan
1210
13−import Initialize
11+import Ast
12+import Context
1413import Rename (derename)
1514import Cases
1615import Guid
16+import LetBoundVars
1717import Parse.Library (isOp)
1818import Rename (deprime)
19+import Types.Types ( Type(RecordT) )
1920
2021showErr :: String -> String
2122showErr err = mainEquals $ "Elm.Graphics.text(Elm.Text.monospace(" ++ msg ++ "))"
@@ -41,47 +42,26 @@ quoted s = "'" ++ concatMap f s ++ "'"
4142 f c = [c]
4243
4344mainEquals s = globalAssign "Elm.main" (jsFunc "" (ret s))
44−globalAssign m s = "\n" ++ m ++ "=" ++ s ++ ";"
45−
46−tryBlock escapees names e =
47− concat [ "\ntry{\n" ++ e ++ "\n} catch (e) {"
48− , "\nElm.main=function() {"
49− , "\nvar msg = ('<br/><h2>Your browser may not be supported. " ++
50− "Are you using a modern browser?</h2>' +" ++
51− " '<br/><span style=\"color:grey\">Runtime Error in " ++
52− intercalate "." names ++ " module:<br/>' + e + '" ++ msg ++ "</span>');"
53− , "\ndocument.body.innerHTML = Elm.Text.monospace(msg);"
54− , "throw e;"
55− , "};}"
56− ]
57− where msg | escapees /= [] = concat [ "<br/><br/>The problem may stem from an improper usage of:<br/>"
58− , intercalate ", " $ map (concatMap escape) escapees ]
59− | otherwise = ""
60− escape '\'' = "\\'"
61− escape '"' = "\\\""
62− escape c = [c]
63−
64−
65−jsModule (escapees, Module names exports imports stmts) =
66− tryBlock escapees (tail modNames) $ concat
67− [ concatMap (\n -> globalAssign n $ n ++ " || {}") .
68− map (intercalate ".") . drop 2 . inits $
69− take (length modNames - 1) modNames
70− , "\nif (" ++ modName ++ ") throw new Error(\"Module name collision, '" ++
71− intercalate "." (tail modNames) ++ "' is already defined.\"); "
72− , globalAssign modName $ jsFunc "" (defs ++ includes ++ body ++ export) ++ "()"
73− , mainEquals $ modName ++ ".main" ]
74− where modNames = if null names then ["Elm", "Main"]
75− else "Elm" : names
76− modName = intercalate "." modNames
77− includes = concatMap jsImport $ map (first ("Elm."++)) imports
78− body = stmtsToJS stmts
79− export = getExports exports stmts
80− exps = if null exports then ["main"] else exports
81− defs = concat [ assign "$op" "{}"
82− , "\nfor(Elm['i'] in Elm){eval('var '+Elm['i']+'=Elm[Elm.i];');}" ]
83−
84−getExports names stmts = ret . brackets $ intercalate ",\n" (op : map fnPair fns)
45+globalAssign n e = "\n" ++ assign' n e ++ ";"
46+assign' n e = n ++ " = " ++ e
47+
48+jsModule (Module names exports imports stmts) =
49+ concat [ concatMap (\n -> globalAssign n $ n ++ " || {}") .
50+ map (intercalate ".") . drop 2 . inits $
51+ take (length modNames - 1) modNames
52+ , parens (jsFunc "" (defs ++ includes ++ body ++ globalAssign modName export) ++ "()")
53+ , mainEquals $ modName ++ ".main" ]
54+ where modNames = if null names then ["Elm", "Main"]
55+ else "Elm" : names
56+ modName = intercalate "." modNames
57+ includes = concatMap jsImport imports
58+ body = stmtsToJS stmts
59+ export = getExports exports stmts
60+ exps = if null exports then ["main"] else exports
61+ defs = assign "$op" "{}"
62+
63+getExports names stmts = brackets . ("\n "++) $
64+ intercalate ",\n " (op : map fnPair fns)
8565 where exNames n = either derename id n `elem` names
8666 exports | null names = concatMap get stmts
8767 | otherwise = filter exNames (concatMap get stmts)
@@ -104,75 +84,75 @@ getExports names stmts = ret . brackets $ intercalate ",\n" (op : map fnPair fns
10484
10585
10686jsImport (modul, how) =
107− concat [ "\ntry{\n if (!(" ++ modul ++ " instanceof Object)) throw new Error('module not found');\n} catch(e) {\n throw new Error(\"Module '"
108− , drop 1 (dropWhile (/='.') modul)
109− , "' is missing. Compile with --make flag or load missing "
110− , "module in a separate JavaScript file.\");\n}" ] ++
111− jsImport' (modul, how)
112−
113−jsImport' (modul, As name) = assign name modul
114−jsImport' (modul, Importing vs) = concatMap def vs
115− where def [] = []
116− def (o:p) | isOp o = let v = "$op['" ++ o:p ++ "']" in
117− "\n" ++ v ++ " = " ++ modul ++ "." ++ v ++ ";"
118− | otherwise = let v = deprime (o:p) in
119− assign v $ modul ++ "." ++ v
120−
121−jsImport' (modul, Hiding vs) =
122− concat [ assign "hiddenVars" . ("{"++) . (++"}") . intercalate "," $
123− map (\v -> v ++ ":true") (map deprime vs)
124− , "\nfor (Elm['i'] in " ++ modul ++ ") "
125− , brackets . indent . concat $
126− [ "\nif (hiddenVars[Elm['i']]) continue;"
127− , "\neval('var ' + Elm['i'] + ' = "
128− , modul, "[Elm.i];');" ]
129− ]
87+ case how of
88+ As name -> assign name ("Elm." ++ modul)
89+ Importing vs ->
90+ assign modul ("Elm." ++ modul) ++ concatMap def vs
91+ where
92+ imprt asgn v = asgn v ("Elm." ++ modul ++ "." ++ v)
93+ def (o:p) =
94+ if isOp o then imprt globalAssign ("$op['" ++ o:p ++ "']")
95+ else imprt assign (deprime (o:p))
96+
13097
13198stmtsToJS :: [Statement] -> String
132−stmtsToJS stmts = run (concat `liftM` mapM toJS (sortBy cmpStmt stmts))
133− where cmpStmt s1 s2 = compare (valueOf s1) (valueOf s2)
134− valueOf s = case s of
135− Datatype _ _ _ -> 1
136− ImportEvent _ _ _ _ -> 2
137− Definition (FnDef f [] _) ->
138− if derename f == "main" then 5 else 4
139− Definition _ -> 3
140− ExportEvent _ _ _ -> 6
141− TypeAlias _ _ _ -> 0
142− TypeAnnotation _ _ -> 0
99+stmtsToJS stmts = run $ do program <- mapM toJS (sortBy cmpStmt stmts)
100+ return (vars ++ concat program)
101+ where
102+ vars = "\nvar " ++ intercalate "," (letBoundVars stmts) ++ ";"
103+ cmpStmt s1 s2 = compare (valueOf s1) (valueOf s2)
104+ valueOf s = case s of
105+ Datatype _ _ _ -> 1
106+ ImportEvent _ _ _ _ -> 2
107+ Definition (FnDef f [] _) ->
108+ if derename f == "main" then 5 else 4
109+ Definition _ -> 3
110+ ExportEvent _ _ _ -> 6
111+ TypeAlias _ _ _ -> 0
112+ TypeAnnotation _ _ -> 0
143113
144114class ToJS a where
145115 toJS :: a -> GuidCounter String
146116
147117instance ToJS Def where
148− toJS (FnDef x [] e) = assign x `liftM` toJS' e
118+ toJS (FnDef x [] e) = assign' x `liftM` toJS' e
149119 toJS (FnDef f (a:as) e) =
150120 do body <- toJS' (foldr (\x e -> noContext (Lambda x e)) e as)
151− return $ concat ["\nfunction ",f,parens a, brackets . indent $ ret body]
121+ return $ assign' f (jsFunc a (ret body))
152122 toJS (OpDef op a1 a2 e) =
153123 do body <- toJS' (foldr (\x e -> noContext (Lambda x e)) e [a1,a2])
154124 return $ concat [ "\n$op['", op, "'] = ", body, ";" ]
155125
156126instance ToJS Statement where
157− toJS (Definition d) = toJS d
158− toJS (Datatype _ _ tcs) = concat `liftM` mapM (toJS . toDef) tcs
159− where toDef (name,args) = Definition . FnDef name vars . noContext $
160− Data (derename name) (map (noContext . Var) vars)
161− where vars = map (('a':) . show) [1..length args]
162− toJS (ImportEvent js base elm _) =
127+ toJS stmt =
128+ case stmt of
129+ Definition d -> (\asgn -> "\n" ++ asgn ++ ";") `liftM` toJS d
130+ Datatype _ _ tcs -> concat `liftM` mapM (toJS . toDef) tcs
131+ where toDef (name,args) =
132+ let vars = map (('a':) . show) [1..length args] in
133+ Definition . FnDef name vars . noContext $
134+ Data (derename name) (map (noContext . Var) vars)
135+ ImportEvent js base elm _ ->
163136 do v <- toJS' base
164137 return $ concat [ "\nvar " ++ elm ++ "=Elm.Signal.constant(" ++ v ++ ");"
165138 , "\nValue.addListener(document, '" ++ js
166139 , "', function(e) { Dispatcher.notify(" ++ elm
167140 , ".id, e.value); });" ]
168− toJS (ExportEvent js elm _) =
141+ ExportEvent js elm _ ->
169142 return $ concat [ "\nlift(function(v) { "
170143 , "var e = document.createEvent('Event');"
171144 , "e.initEvent('", js, "', true, true);"
172145 , "e.value = v;"
173146 , "document.dispatchEvent(e); return v; })(", elm, ");" ]
174− toJS (TypeAnnotation _ _) = return ""
175− toJS (TypeAlias _ _ _) = return ""
147+ TypeAnnotation _ _ -> return ""
148+ TypeAlias n _ t ->
149+ case t of
150+ RecordT kvs _ -> return $ "\nfunction" ++ args ++ brackets body
151+ where fs = Map.keys kvs
152+ args = parens (intercalate "," fs)
153+ body = ret . brackets . intercalate "," $
154+ map (\k -> k ++ ":" ++ k) fs
155+ _ -> return ""
176156
177157toJS' :: CExpr -> GuidCounter String
178158toJS' (C txt span expr) =
@@ -203,7 +183,7 @@ makeRecord kvs = record `liftM` collect kvs
203183instance ToJS Expr where
204184 toJS expr =
205185 case expr of
206− IntNum n -> return $ show n
186+ IntNum n -> return $ show n ++ "|0"
207187 FloatNum n -> return $ show n
208188 Var x -> return $ x
209189 Chr c -> return $ quoted [c]
@@ -249,22 +229,27 @@ formatMarkdown = concatMap f
249229 f '"' = "\""
250230 f c = [c]
251231
252−multiIfToJS span ps = format `liftM` mapM f ps
253− where format cs = foldr (\c e -> parens $ c ++ " : " ++ e) err cs
254− err = concat [ "(function(){throw new Error(\"Non-exhaustive "
255− , "multi-way-if expression (", show span, ")\");}())" ]
256− f (b,e) = do b' <- toJS' b
257− e' <- toJS' e
258− return (b' ++ " ? " ++ e')
259−
260−jsLet defs e' = do
261− body <- (++) `liftM` jsDefs defs `ap` (ret `liftM` toJS' e')
262− return $ jsFunc "" body ++ "()"
263−
264−jsDefs defs = concat `liftM` mapM toJS (sortBy f defs)
265− where f a b = compare (valueOf a) (valueOf b)
266− valueOf (FnDef _ args _) = min 1 (length args)
267− valueOf (OpDef _ _ _ _) = 1
232+multiIfToJS span ps =
233+ case last ps of
234+ (C _ _ (Var "otherwise"), e) -> toJS' e >>= \b -> format b (init ps)
235+ _ -> format err ps
236+ where
237+ format base ps =
238+ foldr (\c e -> parens $ c ++ " : " ++ e) base `liftM` mapM f ps
239+ err = "throw new Error('Non-exhaustive multi-way-if expression (" ++
240+ show span ++ ")')"
241+ f (b,e) = do b' <- toJS' b
242+ e' <- toJS' e
243+ return (b' ++ " ? " ++ e')
244+
245+jsLet defs e' = do ds <- jsDefs defs
246+ e <- toJS' e'
247+ return $ parens (intercalate ", " ds ++ ", " ++ e)
248+ where
249+ jsDefs defs = mapM toJS (sortBy f defs)
250+ f a b = compare (valueOf a) (valueOf b)
251+ valueOf (FnDef _ args _) = min 1 (length args)
252+ valueOf (OpDef _ _ _ _) = 1
268253
269254caseToJS span e ps = do
270255 match <- caseToMatch ps
@@ -280,8 +265,9 @@ matchToJS span (Match name clauses def) = do
280265 cases <- concat `liftM` mapM (clauseToJS span name) clauses
281266 finally <- matchToJS span def
282267 return $ concat [ "\nswitch(", name, ".ctor){", indent cases, "\n}", finally ]
283−matchToJS span Fail = return ("\nthrow new Error(\"Non-exhaustive pattern match " ++
284− "in case expression (" ++ show span ++ ")\");")
268+matchToJS span Fail =
269+ return ("\nthrow new Error(\"Non-exhaustive pattern match " ++
270+ "in case expression (" ++ show span ++ ")\");")
285271matchToJS span Break = return "break;"
286272matchToJS span (Other e) = ret `liftM` toJS' e
287273matchToJS span (Seq ms) = concat `liftM` mapM (matchToJS span) ms
@@ -291,12 +277,9 @@ clauseToJS span var (Clause name vars e) = do
291277 s <- matchToJS span $ matchSubst (zip vars vars') e
292278 return $ concat [ "\ncase ", quoted name, ":", s ]
293279
294−jsNil = "[\"Nil\"]"
295−jsCons e1 e2 = jsList [ quoted "Cons", e1, e2 ]
296−jsRange e1 e2 = (++"()") . jsFunc "" $
297− assign "lo" e1 ++ assign "hi" e2 ++ assign "lst" jsNil ++
298− "if(lo<=hi){do{lst=" ++ (jsCons "hi" "lst") ++ "}while(hi-->lo)}" ++
299− ret "lst"
280+jsNil = "{ctor:'Nil'}"
281+jsCons e1 e2 = "{ctor:'Cons',_0:" ++ e1 ++ ",_1:" ++ e2 ++ "}"
282+jsRange e1 e2 = "Elm.Native.List.range" ++ parens (e1 ++ "," ++ e2)
300283
301284binop (o:p) e1 e2
302285 | isAlpha o || '_' == o = (o:p) ++ parens e1 ++ parens e2
elm/src/Gen/GenerateHtml.hs+9−10
@@ -47,23 +47,22 @@ generateHtml :: String -- ^ Location of elm-min.js as expected by the browser
4747generateHtml libLoc title source =
4848 case buildFromSource source of
4949 Left err -> createHtml Readable libLoc title (Right $ showErr err) (H.noscript "")
50− Right (escs, modul) -> modulesToHtml Readable title libLoc [] True [(escs,modul)]
50+ Right modul -> modulesToHtml Readable title libLoc [] True [modul]
5151
5252
53−modulesToHtml jsStyle title libLoc jss nscrpt pairs =
53+modulesToHtml jsStyle title libLoc jss nscrpt modules =
5454 createHtml jsStyle libLoc title' js noscript
55− where modules = map snd pairs
56− js = Right $ jss ++ concatMap jsModule pairs
57− noscript = if nscrpt then extractNoscript $ last modules else ""
58− title' = if null title then altTitle else title
59− altTitle = (\(Module names _ _ _) -> intercalate "." names) $
60− last modules
55+ where
56+ js = Right $ jss ++ concatMap jsModule modules
57+ noscript = if nscrpt then extractNoscript $ last modules else ""
58+ title' = if null title then altTitle else title
59+ altTitle = (\(Module names _ _ _) -> intercalate "." names) $ last modules
6160
6261
6362linkedHtml rtLoc jsLoc modules =
6463 createHtml Readable rtLoc title (Left jsLoc) (H.noscript "")
65− where title = (\(Module names _ _ _) -> intercalate "." names) $
66− snd (last modules)
64+ where
65+ title = (\(Module names _ _ _) -> intercalate "." names) (last modules)
6766
6867
6968createHtml jsStyle libLoc title js noscript =
elm/src/Initialize.hs+66−56
@@ -1,19 +1,20 @@
1−module Initialize (build,buildFromSource) where
1+module Initialize (build, buildFromSource) where
22
33import Control.Applicative ((<$>))
44import Control.Monad.Error
5−import Data.List (lookup)
5+import Data.List (lookup,nub)
66
77import Ast
88import Data.Either (lefts,rights)
99import Data.List (intercalate,partition)
10−import Parse.Parser (parseProgram)
10+import Parse.Parser (parseProgram, preParse)
1111import Rename
1212import Types.Types ((-:))
1313import Types.Hints (hints)
1414import Types.Unify
1515import Types.Alias
1616import Optimize
17+import CompileToJS (jsModule)
1718
1819checkMistakes :: Module -> Either String Module
1920checkMistakes modul@(Module name ex im stmts) =
@@ -21,75 +22,84 @@ checkMistakes modul@(Module name ex im stmts) =
2122 m:ms -> Left (unlines (m:ms))
2223 [] -> return modul
2324
24−checkTypes :: Module -> Either String ([String], Module)
25+checkTypes :: Module -> Either String Module
2526checkTypes (Module name ex im stmts) =
2627 let stmts' = dealias stmts
2728 modul = Module name ex im stmts'
28− in do (escapees, subs) <- unify hints modul
29+ in do subs <- unify hints modul
2930 let im' | any ((=="Prelude") . fst) im = im
30− | otherwise = ("Prelude", Hiding []) : im
31+ | otherwise = ("Prelude", Importing []) : im
3132 modul' = optimize . renameModule $ Module name ex im' stmts'
32− subs `seq` return (escapees, modul')
33+ subs `seq` return modul'
3334
34−check :: Module -> Either String ([String], Module)
35+check :: Module -> Either String Module
3536check = checkMistakes >=> checkTypes
3637
37−buildFromSource :: String -> Either String ([String],Module)
38−buildFromSource = parseProgram >=> check
38+buildFromSource :: String -> Either String Module
39+buildFromSource src = check =<< parseProgram src
3940
40−build :: Bool -> FilePath -> IO (Either String ([String],[Module]))
41−build make root = do
42− proj <- parse make root
43− return $ do
44− ms <- proj
45− (escapeess, modules) <- unzip `liftM` mapM check ms
46− sortedModules <- (if make then sort else return) modules
47− return (concat escapeess, sortedModules)
48−
49−parse :: Bool -> FilePath -> IO (Either String [Module])
50−parse make root = parseProject [] make root
51−
52−parseProject :: [FilePath] -> Bool -> FilePath -> IO (Either String [Module])
53−parseProject seen make root = do
54− txt <- readFile root
55− case parseProgram txt of
41+build :: FilePath -> IO (Either String [Module])
42+build root = do
43+ names <- getSortedModuleNames root
44+ case names of
5645 Left err -> return (Left err)
57− Right modul@(Module names exs ims stmts) ->
58− let allDeps = map toFilePath (getDeps modul)
59− newDeps = if make then filter (`notElem` seen) allDeps else []
60− name = intercalate "." names
61− in do ps <- mapM (parseProject (name : seen ++ newDeps) make) newDeps
62− return $ case unlines (lefts ps) of
63− c:cs -> Left (c:cs)
64− _ -> Right (modul : concat (rights ps))
46+ Right ns -> do srcs <- zipWithM buildFile' [1..] ns
47+ return (sequence srcs)
48+ where
49+ buildFile' n name = putStrLn (msg n name) >> buildFile name
50+ msg n name = "["++show n++" of "++show (length ns)++"] Compiling "++name
6551
66−toFilePath :: String -> FilePath
67−toFilePath modul = map (\c -> if c == '.' then '/' else c) modul ++ ".elm"
52+buildFile :: String -> IO (Either String Module)
53+buildFile moduleName =
54+ let filePath = toFilePath moduleName in
55+ case isNative moduleName of
56+ True -> return (Right $ Module [moduleName] [] [] [])
57+ --return (Left "Can't do that yet")
58+ --Right `liftM` readFile filePath
59+ False -> do txt <- readFile filePath
60+ return $ buildFromSource txt
6861
69−getDeps :: Module -> [String]
70−getDeps (Module _ _ is _) = filter (`notElem` builtInModules) (map fst is)
71− where
72− builtInModules =
73− ["List","Char","Either","Maybe","Dict","Set","Automaton","Date",
74− "Signal","Mouse","Keyboard.Raw","Keyboard","Touch",
75− "WebSocket","Window","Time","HTTP","Input","Random",
76− "Graphics","Text","Color","JavaScript",
77− "JavaScript.Experimental","Prelude","JSON"]
7862
63+getSortedModuleNames :: FilePath -> IO (Either String [String])
64+getSortedModuleNames root = do
65+ deps <- readDeps [] root
66+ return (sortDeps =<< deps)
7967
80−sort :: [Module] -> Either String [Module]
81−sort = go []
68+type Deps = (String, [String])
69+
70+sortDeps :: [Deps] -> Either String [String]
71+sortDeps deps = go [] (nub deps)
8272 where
8373 msg = "A cyclical or missing module dependency or was detected in: "
84− getName (Module names _ _ _) = intercalate "." names
85−
86− has name modul = name == getName modul
87− within ms name = any (has name) ms
8874
89− go :: [Module] -> [Module] -> Either String [Module]
75+ go :: [String] -> [Deps] -> Either String [String]
9076 go sorted [] = Right sorted
9177 go sorted unsorted =
92− case partition (all (within sorted) . getDeps) unsorted of
93− ([],m:ms) -> Left (msg ++ intercalate ", " (map getName (m:ms)))
94− (srtd,unsrtd) -> go (sorted ++ srtd) unsrtd
95−
78+ case partition (all (`elem` sorted) . snd) unsorted of
79+ ([],m:ms) -> Left (msg ++ intercalate ", " (map fst (m:ms)) ++ show sorted ++ show unsorted)
80+ (srtd,unsrtd) -> go (sorted ++ map fst srtd) unsrtd
81+
82+readDeps :: [FilePath] -> FilePath -> IO (Either String [Deps])
83+readDeps seen root = do
84+ txt <- readFile root
85+ case preParse txt of
86+ Left err -> return (Left err)
87+ Right (name,deps) -> do rest <- mapM (readDeps seen' . toFilePath) newDeps
88+ return $ do rs <- sequence rest
89+ return ((name, realDeps) : concat rs)
90+ where realDeps = filter (`notElem` builtIns) deps
91+ newDeps = filter (`notElem` seen) realDeps
92+ seen' = root : seen ++ newDeps
93+ builtIns = [] {--
94+ ["List","Char","Either","Maybe","Dict","Set","Date",
95+ "Signal","Mouse","Keyboard.Raw","Keyboard","Touch",
96+ "WebSocket","Window","Time","HTTP","Input","Random",
97+ "Graphics","Text","Color","JavaScript","Automaton",
98+ "JavaScript.Experimental","Prelude","JSON"]
99+ --}
100+
101+isNative name = takeWhile (/='.') name == "Native"
102+toFilePath name = map swapDots name ++ ext
103+ where swapDots '.' = '/'
104+ swapDots c = c
105+ ext = if isNative name then ".js" else ".elm"
elm/src/Language/Elm.hs+1−1
@@ -79,4 +79,4 @@ toPartsHelper :: String -> (Html, Html, String)
7979toPartsHelper source = (html, css, js)
8080 where modul = buildFromSource source
8181 js = either showErr jsModule modul
82− html = widgetBody $ either id (extractNoscript . snd) modul
82+ html = widgetBody $ either id extractNoscript modul
elm/src/Parse/Library.hs+1−1
@@ -162,7 +162,7 @@ whitespace :: IParser ()
162162whitespace = optional forcedWS <?> ""
163163
164164freshLine :: IParser [[String]]
165−freshLine = try (do { many1 newline; many space_nl }) <|> try (many1 space_nl) <?> ""
165+freshLine = try (many1 newline >> many space_nl) <|> try (many1 space_nl) <?> ""
166166 where space_nl = try $ spaces >> many1 newline
167167
168168newline :: IParser String
elm/src/Parse/Modules.hs+1−6
@@ -31,17 +31,12 @@ import' = do
3131 reserved "import"
3232 whitespace
3333 name <- intercalate "." <$> dotSep1 capVar
34− method <- option (Hiding []) $ try (whitespace >>
35− (as' <|> hiding' <|> importing'))
34+ method <- option (Importing []) $ try (whitespace >> (as' <|> importing'))
3635 return (name, method)
3736
3837
3938as' :: IParser ImportMethod
4039as' = reserved "as" >> whitespace >> As <$> capVar <?> "alias for module"
4140
42−hiding' :: IParser ImportMethod
43−hiding' = reserved "hiding" >> whitespace >>
44− Hiding <$> varList <?> "listing of hidden values"
45−
4641importing' :: IParser ImportMethod
4742importing' = Importing <$> varList <?> "listing of imported values (x,y,z)"
elm/src/Parse/Parser.hs+17−4
@@ -1,10 +1,10 @@
1−module Parse.Parser (parseProgram) where
1+module Parse.Parser (parseProgram, preParse) where
22
33import Ast
44import Control.Applicative ((<$>), (<*>))
55import Control.Monad
66import Data.Char (isSymbol, isDigit)
7−import Data.List (foldl')
7+import Data.List (foldl',intercalate)
88import Text.Parsec hiding (newline,spaces)
99
1010import Parse.Library
@@ -33,7 +33,20 @@ program = do
3333 optional freshLine ; optional spaces ; eof
3434 return $ Module names exports is statements
3535
36−parseProgram source =
37− case iParse program "" source of
36+parseProgram = setupParser program
37+
38+preParse :: String -> Either String (String, [String])
39+preParse = setupParser $ do
40+ optional skip
41+ (,) <$> option "Main" moduleName <*> option [] imprts
42+ where
43+ skip = try (manyTill anyChar (try (string "/**")))
44+ imprts = fmap (map fst) imports `followedBy` freshLine
45+ getName = intercalate "." . fst
46+ moduleName = do optional freshLine
47+ getName <$> moduleDef `followedBy` freshLine
48+
49+setupParser p source =
50+ case iParse p "" source of
3851 Right result -> Right result
3952 Left err -> Left $ "Parse error at " ++ show err
elm/src/Types/Constrain.hs+4−3
@@ -24,7 +24,6 @@ getAliases imports hints = hints ++ concatMap aliasesFrom imports'
2424 aliasesFrom (name,method) =
2525 case method of
2626 As alias -> concatMap (findAlias name alias) hints
27− Hiding [] -> concatMap (findAlias name "") hints
2827 _ -> []
2928 findAlias mName' mAlias (name,tipe) =
3029 let mName = mName' ++ "." in
@@ -63,7 +62,7 @@ constrain typeHints (Module _ _ imports stmts) = do
6362 (as', cs', schemes) <- mergeSchemes schemess
6463 let constraints = Set.unions (cs':css)
6564 as = unionsA (as':ass)
66− extraImports = ("Time", Hiding ["read"]) : map (\n -> (n, Hiding []))
65+ extraImports = ("Time", Importing []) : map (\n -> (n, Importing []))
6766 ["List","Signal","Text","Graphics","Color"]
6867 aliasHints = getAliases (imports ++ extraImports) hints
6968 allHints = Map.union schemes (Map.fromList aliasHints)
@@ -73,7 +72,9 @@ constrain typeHints (Module _ _ imports stmts) = do
7372 let f k s vs = map (\v -> C (Just k) NoSpan $ v :<<: s) vs
7473 cs = concat . Map.elems $ Map.intersectionWithKey f allHints assumptions
7574 escapees = Map.keys $ Map.difference assumptions allHints
76− return . Right . (,) escapees $ Set.toList constraints ++ cs
75+ return $ case escapees of
76+ _ -> Right (Set.toList constraints ++ cs)
77+ --_ -> Left ("Undefined variable(s): " ++ intercalate ", " escapees)
7778
7879type TVarMap = Map.Map String [X]
7980type ConstraintSet = Set.Set (Context Constraint)
elm/src/Types/Unify.hs+1−6
@@ -10,10 +10,5 @@ import Types.Solver
1010
1111unify hints modul = run $ do
1212 constraints <- constrain hints modul
13− case constraints of
14− Left msg -> return (Left msg)
15− Right (escapees, cs) ->
16− do subs <- solver cs Map.empty
17− return $ do ss <- subs
18− return (escapees, ss)
13+ either (return . Left) (\cs -> solver cs Map.empty) constraints
1914