on master help sign in
Merge branch 'javascript' into dev
a8fedacEvan Czaplicki
Elm.cabal+4−4
@@ -32,8 +32,7 @@ source-repository head
32Library
32Library
33 exposed-modules: Language.Elm
33 exposed-modules: Language.Elm
34 Hs-Source-Dirs: compiler
34 Hs-Source-Dirs: compiler
35− other-modules: Unique,
36− SourceSyntax.Declaration,
35+ other-modules: SourceSyntax.Declaration,
37 SourceSyntax.Expression,
36 SourceSyntax.Expression,
38 SourceSyntax.Everything,
37 SourceSyntax.Everything,
39 SourceSyntax.Helpers,
38 SourceSyntax.Helpers,
@@ -90,6 +89,7 @@ Library
90 filepath,
89 filepath,
91 hjsmin,
90 hjsmin,
92 indents,
91 indents,
92+ language-ecmascript,
93 mtl >= 2,
93 mtl >= 2,
94 pandoc >= 1.10,
94 pandoc >= 1.10,
95 parsec >= 3.1.1,
95 parsec >= 3.1.1,
@@ -102,8 +102,7 @@ Executable elm
102 Main-is: Compiler.hs
102 Main-is: Compiler.hs
103 ghc-options: -threaded -O2
103 ghc-options: -threaded -O2
104 Hs-Source-Dirs: compiler
104 Hs-Source-Dirs: compiler
105− other-modules: Unique,
106− SourceSyntax.Declaration,
105+ other-modules: SourceSyntax.Declaration,
107 SourceSyntax.Expression,
106 SourceSyntax.Expression,
108 SourceSyntax.Everything,
107 SourceSyntax.Everything,
109 SourceSyntax.Helpers,
108 SourceSyntax.Helpers,
@@ -160,6 +159,7 @@ Executable elm
160 filepath,
159 filepath,
161 hjsmin,
160 hjsmin,
162 indents,
161 indents,
162+ language-ecmascript,
163 mtl >= 2,
163 mtl >= 2,
164 pandoc >= 1.10,
164 pandoc >= 1.10,
165 parsec >= 3.1.1,
165 parsec >= 3.1.1,
Setup.hs+2−2
@@ -145,8 +145,8 @@ buildInterfaces lbi elmis = do
145buildRuntime :: LocalBuildInfo -> [FilePath] -> IO ()
145buildRuntime :: LocalBuildInfo -> [FilePath] -> IO ()
146buildRuntime lbi elmos = do
146buildRuntime lbi elmos = do
147 createDirectoryIfMissing True (rtsDir lbi)
147 createDirectoryIfMissing True (rtsDir lbi)
148− writeFile (rts lbi) "Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
148+ writeFile (rts lbi) "var Elm = {}; Elm.Native = {}; Elm.Native.Graphics = {};\n\
149− \Elm.Graphics = {}; ElmRuntime = {}; ElmRuntime.Render = {};\n"
149+ \var ElmRuntime = {}; ElmRuntime.Render = {};\n"
150 mapM_ (appendJS lbi) =<< getFiles ".js" "libraries"
150 mapM_ (appendJS lbi) =<< getFiles ".js" "libraries"
151 mapM_ (appendJS lbi) elmos
151 mapM_ (appendJS lbi) elmos
152 mapM_ (appendJS lbi) =<< getFiles ".js" "runtime"
152 mapM_ (appendJS lbi) =<< getFiles ".js" "runtime"
compiler/Generate/Cases.hs+15−14
@@ -1,22 +1,25 @@
1module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where
1module Generate.Cases (caseToMatch, Match (..), Clause (..), matchSubst) where
2
2
3+import Control.Applicative ((<$>),(<*>))
3import Control.Arrow (first)
4import Control.Arrow (first)
4−import Control.Monad (liftM,foldM)
5+import Control.Monad.State
5import Data.List (groupBy,sortBy,lookup)
6import Data.List (groupBy,sortBy,lookup)
6import Data.Maybe (fromMaybe)
7import Data.Maybe (fromMaybe)
7
8
8−import Unique
9import SourceSyntax.Location
9import SourceSyntax.Location
10import SourceSyntax.Literal
10import SourceSyntax.Literal
11import SourceSyntax.Pattern
11import SourceSyntax.Pattern
12import SourceSyntax.Expression
12import SourceSyntax.Expression
13import Transform.Substitute
13import Transform.Substitute
14
14
15+
16+caseToMatch :: [(Pattern, LExpr t v)] -> (String, Match t v)
15−caseToMatch patterns = do
17+caseToMatch patterns = flip evalState 0 $ do
16 v <- newVar
18 v <- newVar
17− (,) v `liftM` match [v] (map (first (:[])) patterns) Fail
19+ (,) v <$> match [v] (map (first (:[])) patterns) Fail
18
20
19−newVar = do n <- guid
21+newVar = do n <- get
22+ modify (+1)
20 return $ "case" ++ show n
23 return $ "case" ++ show n
21
24
22data Match t v
25data Match t v
@@ -51,7 +54,7 @@ isCon (p:ps, e) =
51
54
52isVar p = not (isCon p)
55isVar p = not (isCon p)
53
56
54−match :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> Unique (Match t v)
57+match :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
55match [] [] def = return def
58match [] [] def = return def
56match [] [([],e)] Fail = return $ Other e
59match [] [([],e)] Fail = return $ Other e
57match [] [([],e)] Break = return $ Other e
60match [] [([],e)] Break = return $ Other e
@@ -68,8 +71,7 @@ dealias v c@(p:ps, L s e) =
68 PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e)
71 PAlias x pattern -> (pattern:ps, L s $ subst x (Var v) e)
69 _ -> c
72 _ -> c
70
73
71−matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v
74+matchVar :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
72− -> Unique (Match t v)
73matchVar (v:vs) cs def = match vs (map subVar cs) def
75matchVar (v:vs) cs def = match vs (map subVar cs) def
74 where
76 where
75 subVar (p:ps, ce@(L s e)) = (ps, L s $ subOnePattern p e)
77 subVar (p:ps, ce@(L s e)) = (ps, L s $ subOnePattern p e)
@@ -82,8 +84,8 @@ matchVar (v:vs) cs def = match vs (map subVar cs) def
82 foldr (\x -> subst x (Access (L s (Var v)) x)) e fs
84 foldr (\x -> subst x (Access (L s (Var v)) x)) e fs
83
85
84matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v
86matchCon :: [String] -> [([Pattern],LExpr t v)] -> Match t v
85− -> Unique (Match t v)
87+ -> State Int (Match t v)
86−matchCon (v:vs) cs def = (flip (Match v) def) `liftM` mapM toClause css
88+matchCon (v:vs) cs def = (flip (Match v) def) <$> mapM toClause css
87 where
89 where
88 css = groupBy eq (sortBy cmp cs)
90 css = groupBy eq (sortBy cmp cs)
89
91
@@ -106,10 +108,10 @@ matchClause :: Either String Literal
106 -> [String]
108 -> [String]
107 -> [([Pattern],LExpr t v)]
109 -> [([Pattern],LExpr t v)]
108 -> Match t v
110 -> Match t v
109− -> Unique (Clause t v)
111+ -> State Int (Clause t v)
110matchClause c (v:vs) cs def =
112matchClause c (v:vs) cs def =
111 do vs' <- getVars
113 do vs' <- getVars
112− Clause c vs' `liftM` match (vs' ++ vs) (map flatten cs) def
114+ Clause c vs' <$> match (vs' ++ vs) (map flatten cs) def
113 where
115 where
114
116
115 flatten (p:ps, e) =
117 flatten (p:ps, e) =
@@ -122,7 +124,6 @@ matchClause c (v:vs) cs def =
122 (PData _ ps : _, _) -> mapM (\_ -> newVar) ps
124 (PData _ ps : _, _) -> mapM (\_ -> newVar) ps
123 (PLiteral _ : _, _) -> return []
125 (PLiteral _ : _, _) -> return []
124
126
125−matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v
127+matchMix :: [String] -> [([Pattern],LExpr t v)] -> Match t v -> State Int (Match t v)
126− -> Unique (Match t v)
127matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
128matchMix vs cs def = foldM (flip $ match vs) def (reverse css)
128 where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
129 where css = groupBy (\p1 p2 -> isCon p1 == isCon p2) cs
compiler/Generate/JavaScript.hs+321−326
@@ -1,293 +1,223 @@
1−module Generate.JavaScript (jsModule) where
1+module Generate.JavaScript where
2
2
3−import Control.Arrow (first,second)
3+import Control.Arrow ((***))
4−import Control.Monad (liftM,(<=<),join,ap)
5−import Data.Char (isAlpha,isDigit)
6import qualified Data.List as List
4import qualified Data.List as List
7import qualified Data.Map as Map
5import qualified Data.Map as Map
8import qualified Data.Set as Set
6import qualified Data.Set as Set
9−import Data.Either (partitionEithers)
10import qualified Text.Pandoc as Pan
7import qualified Text.Pandoc as Pan
11
8
12−import Unique
13import Generate.Cases
9import Generate.Cases
14import SourceSyntax.Everything
10import SourceSyntax.Everything
15import SourceSyntax.Location
11import SourceSyntax.Location
16import qualified Transform.SortDefinitions as SD
12import qualified Transform.SortDefinitions as SD
13+import Language.ECMAScript3.Syntax
14+import Language.ECMAScript3.PrettyPrint
15+import Parse.Helpers (jsReserveds)
17
16
18−indent = concatMap f
17+makeSafe :: String -> String
19− where f '\n' = "\n "
18+makeSafe = dereserve . deprime
20− f c = [c]
21−
22−internalImports name =
23− [ ("N" , "Elm.Native"),
24− ("_N", "N.Utils(elm)"),
25− ("_L", "N.List(elm)"),
26− ("_E", "N.Error(elm)"),
27− ("_J", "N.JavaScript(elm)"),
28− ("_str", "_J.toString"),
29− ("$moduleName", quoted name)
30− ]
31−
32−parens s = "(" ++ s ++ ")"
33−brackets s = "{" ++ s ++ "}"
34−commaSep = List.intercalate ", "
35−dotSep = List.intercalate "."
36−jsObj = brackets . commaSep
37−jsList ss = "["++ List.intercalate "," ss ++"]"
38−jsFunc args body = "function(" ++ args ++ "){" ++ indent body ++ "}"
39−assign x e = "\nvar " ++ x ++ " = " ++ e ++ ";"
40−ret e = "\nreturn "++ e ++";"
41−quoted s = "'" ++ concatMap f s ++ "'"
42− where f '\n' = "\\n"
43− f '\'' = "\\'"
44− f '\t' = "\\t"
45− f '\"' = "\\\""
46− f '\\' = "\\\\"
47− f c = [c]
48−
49−globalAssign n e = "\n" ++ assign' n e ++ ";"
50−assign' n e = n ++ " = " ++ e
51−
52−jsModule :: MetadataModule t v -> String
53−jsModule modul =
54− run $ do
55− body <- toJS . fst . SD.flattenLets [] $ program modul
56− foreignImport <- mapM importEvent (foreignImports modul)
57− return $ concat [ setup ("Elm" : names modul)
58− , globalAssign ("Elm." ++ modName)
59− (jsFunc "elm" $ makeProgram body foreignImport) ]
60 where
19 where
61− modName = dotSep (names modul)
20+ deprime = map (\c -> if c == '\'' then '$' else c)
62− makeProgram body foreignImport =
21+ dereserve x = case Set.member x jsReserveds of
63− concat [ setup ("elm" : names modul)
22+ False -> x
64− , "\nif (elm." ++ modName ++ ") return elm." ++ modName ++ ";"
23+ True -> "$" ++ x
65− , "\nvar " ++ usefulFuncs ++ ";"
66− , concatMap jsImport (imports modul)
67− , concat foreignImport
68− , assign "_op" "{}"
69− , body
70− , concatMap exportEvent $ foreignExports modul
71− , jsExports
72− ]
73− setup names = concatMap (\n -> globalAssign n $ n ++ " || {}") .
74− map dotSep . drop 2 . List.inits $ init names
75− usefulFuncs = commaSep (map (uncurry assign') (internalImports modName))
76−
77− jsExports = ret (assign' ("elm." ++ modName) (brackets exs))
78− where
79− exs = indent . commaSep . concatMap pair $ "_op" : exports modul
80− pair x | isOp x = []
81− | otherwise = ["\n" ++ x ++ " : " ++ x]
82−
83−
84− importEvent (js,base,elm,_) =
85− do v <- toJS' base
86− return $ concat [ "\nvar " ++ elm ++ "=Signal.constant(" ++ v ++ ");"
87− , "\ndocument.addEventListener('", js
88− , "_' + elm.id, function(e) { elm.notify(", elm
89− , ".id, e.value); });" ]
90
24
91− exportEvent (js,elm,_) =
25+split = go []
92− concat [ "\nA2( Signal.lift, function(v) { "
93− , "var e = document.createEvent('Event');"
94− , "e.initEvent('", js, "_' + elm.id, true, true);"
95− , "e.value = v;"
96− , "document.dispatchEvent(e); return v; }, ", elm, ");" ]
97−
98−jsImport (modul, method) =
99− concat $ zipWith3 (\s n v -> s ++ assign' n v ++ ";") starters subnames values
100 where
26 where
101− starters = "\nvar " : repeat "\n"
27+ go vars str =
102− values = map (\name -> name ++ " || {}") (init subnames) ++
28+ case break (=='.') str of
103− ["Elm." ++ modul ++ parens "elm"]
29+ (x,'.':rest) -> go (vars ++ [x]) rest
104− subnames = map dotSep . tail . List.inits $ split modul
30+ (x,[]) -> vars ++ [x]
105−
106− split names = case go [] names of
107− (name, []) -> [name]
108− (name, ns) -> name : split ns
109− go name str = case str of
110− '.':rest -> (reverse name, rest)
111− c:rest -> go (c:name) rest
112− [] -> (reverse name, [])
113−
114−
115−class ToJS a where
116− toJS :: a -> Unique String
117−
118
31
119−instance ToJS (Def t v) where
32+var name = Id () (makeSafe name)
33+ref name = VarRef () (var name)
34+prop name = PropId () (var name)
35+f <| x = CallExpr () f [x]
36+args ==> e = FuncExpr () Nothing (map var args) [ ReturnStmt () (Just e) ]
37+function args stmts = FuncExpr () Nothing (map var args) stmts
38+call = CallExpr ()
39+string = StringLit ()
120
40
121− -- TODO: Make this handle patterns besides plain variables
41+dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
122− toJS (Def (PVar x) e)
42+get = dotSep . split
123− | isOp x = globalAssign ("_op['" ++ x ++ "']") `liftM` toJS' e
124− | otherwise = assign x `liftM` toJS' e
125
43
126− toJS (Def pattern e@(L s _)) =
44+varDecl x expr =
127− do n <- guid
45+ VarDecl () (var x) (Just expr)
128− let x = "_" ++ show n
129− var = L s . Var
130− toDef y = Def (PVar y) (L s $ Case (var x) [(pattern, var y)])
131− stmt <- assign x `liftM` toJS' e
132− vars <- toJS . map toDef . Set.toList $ SD.boundVars pattern
133− return (stmt ++ vars)
134
46
135− toJS (TypeAnnotation _ _) = return ""
47+include alias moduleName =
48+ varDecl alias (get moduleName <| ref "elm")
136
49
50+internalImports name =
51+ VarDeclStmt ()
52+ [ varDecl "N" (get "Elm.Native")
53+ , include "_N" "N.Utils"
54+ , include "_L" "N.List"
55+ , include "_E" "N.Error"
56+ , include "_J" "N.JavaScript"
57+ , varDecl "_str" (get "_J.toString")
58+ , varDecl "$moduleName" (string name)
59+ ]
137
60
138−instance ToJS a => ToJS [a] where
61+literal lit =
139− toJS xs = concat `liftM` mapM toJS xs
140−
141−toJS' :: LExpr t v -> Unique String
142−toJS' (L span expr) =
143− case expr of
144− MultiIf ps -> multiIfToJS span ps
145− Case e cases -> caseToJS span e cases
146− _ -> toJS expr
147−
148−remove x e = "_N.remove('" ++ x ++ "', " ++ e ++ ")"
149−addField x v e = "_N.insert('" ++ x ++ "', " ++ v ++ ", " ++ e ++ ")"
150−setField fs e = "_N.replace(" ++ jsList (map f fs) ++ ", " ++ e ++ ")"
151− where f (x,v) = "['" ++ x ++ "'," ++ v ++ "]"
152−access x e = e ++ "." ++ x
153−makeRecord kvs = record `liftM` collect kvs
154− where
155− combine r (k,v) = Map.insertWith (++) k v r
156− collect = liftM (List.foldl' combine Map.empty) . mapM prep
157− prep (k, e) =
158− do v <- toJS' e
159− return (k, [v])
160− fields fs =
161− brackets ("\n "++List.intercalate ",\n " (map (\(k,v) -> k++":"++v) fs))
162− hidden = fields . map (second jsList) .
163− filter (not . null . snd) . Map.toList . Map.map tail
164− record kvs = fields . (("_", hidden kvs) :) . Map.toList . Map.map head $ kvs
165−
166−
167−instance ToJS Literal where
168− toJS lit =
169 case lit of
62 case lit of
170− Chr c -> return $ quoted [c]
63+ Chr c -> string [c]
171− Str s -> return $ "_str" ++ parens (quoted s)
64+ Str s -> ref "_str" <| string s
172− IntNum n -> return $ show n
65+ IntNum n -> IntLit () n
173− FloatNum n -> return $ show n
66+ FloatNum n -> NumLit () n
174− Boolean b -> return $ if b then "true" else "false"
67+ Boolean b -> BoolLit () b
175−
68+
176−
69+expression :: LExpr () () -> Expression ()
177−instance ToJS (Expr t v) where
70+expression (L span expr) =
178− toJS expr =
179− case expr of
71+ case expr of
180− Var x -> return x
72+ Var x -> ref x
181− Literal lit -> toJS lit
73+ Literal lit -> literal lit
182− Range lo hi -> jsRange `liftM` toJS' lo `ap` toJS' hi
74+ Range lo hi -> get "_L.range" `call` [expression lo, expression hi]
183− Access e x -> access x `liftM` toJS' e
75+
76+ Access e x -> DotRef () (expression e) (var x)
184− Remove e x -> remove x `liftM` toJS' e
77+ Remove e x -> get "_N.remove" `call` [string x, expression e]
185− Insert e x v -> addField x `liftM` toJS' v `ap` toJS' e
78+ Insert e x v -> get "_N.insert" `call` [string x, expression v, expression e]
186− Modify e fs -> do fs' <- (mapM (\(x,v) -> (,) x `liftM` toJS' v) fs)
79+ Modify e fs ->
187− setField fs' `liftM` toJS' e
80+ let modify (f,v) = ArrayLit () [string f, expression v]
188− Record fs -> makeRecord fs
81+ in get "_N.replace" `call` [ArrayLit () (map modify fs), expression e]
189− Binop op e1 e2 -> binop op e1 e2
82+
190−
83+ Record fields -> ObjectLit () $ (PropId () (var "_"), hidden) : visible
191− Lambda p e@(L s _) -> liftM fastFunc (toJS' body)
192 where
84 where
193− fastFunc body
85+ combine r (k,v) = Map.insertWith (++) k [v] r
86+ fieldMap = List.foldl' combine Map.empty fields
87+ hidden = ObjectLit () . map ((PropId () . var) *** (ArrayLit () . map expression)) .
88+ Map.toList . Map.filter (not . null) $ Map.map tail fieldMap
89+ visible = map ((PropId () . var) *** expression) . Map.toList $ Map.map head fieldMap
90+
91+ Binop op e1 e2 -> binop span op e1 e2
92+
93+ Lambda p e@(L s _) -> fastFunc
94+ where
95+ fastFunc
194− | length args < 2 || length args > 9 =
96+ | length args < 2 || length args > 9 =
195− foldr (\arg bod -> jsFunc arg (ret bod)) body args
97+ foldr (==>) (expression body) (map (:[]) args)
196− | otherwise =
98+ | otherwise =
197− "F" ++ show (length args) ++ parens (jsFunc (commaSep args) (ret body))
99+ ref ("F" ++ show (length args)) <| (args ==> expression body)
198−
100+
199− (args, body) = first reverse $ foldr depattern ([], innerBody) (zip patterns [1..])
101+ (args, body) = foldr depattern ([], innerBody) (zip patterns [0..])
200−
102+
201− depattern (pattern,n) (args, body) =
103+ depattern (pattern,n) (args, body) =
202− case pattern of
104+ case pattern of
203− PVar x -> (x : args, body)
105+ PVar x -> (args ++ [x], body)
204− _ -> let arg = "arg" ++ show n
106+ _ -> let arg = "arg" ++ show n
205− in (arg:args, L s (Case (L s (Var arg)) [(pattern, body)]))
107+ in (args ++ [arg], L s (Case (L s (Var arg)) [(pattern, body)]))
206−
108+
207− (patterns, innerBody) = collect [p] e
109+ (patterns, innerBody) = collect [p] e
208−
110+
209− collect patterns lexpr@(L _ expr) =
111+ collect patterns lexpr@(L _ expr) =
210− case expr of
112+ case expr of
211− Lambda p e -> collect (p:patterns) e
113+ Lambda p e -> collect (p:patterns) e
212− _ -> (patterns, lexpr)
114+ _ -> (patterns, lexpr)
213−
115+
214− App e1 e2 -> jsApp e1 e2
116+ App e1 e2 ->
117+ case args of
118+ [arg] -> func <| arg
119+ _ -> ref aN `call` (func:args)
120+ where
121+ aN = "A" ++ show (length args)
122+ (func, args) = getArgs e1 [e2]
123+ getArgs func args =
124+ case func of
125+ (L _ (App f arg)) -> getArgs f (arg : args)
126+ _ -> (expression func, map expression args)
127+
128+ Let defs e -> function [] stmts `call` []
129+ where
215− Let defs e -> jsLet $ SD.flattenLets defs e
130+ (defs',e') = SD.flattenLets defs e
216−
131+ stmts = concatMap definition defs' ++ [ ReturnStmt () (Just (expression e')) ]
132+
133+ MultiIf branches ->
134+ case last branches of
135+ (L _ (Var "otherwise"), e) -> ifs (init branches) (expression e)
136+ _ -> ifs branches (get "_E.If" `call` [ ref "$moduleName", string (show span) ])
137+ where
138+ ifs branches finally = foldr iff finally branches
139+ iff (if', then') else' = CondExpr () (expression if') (expression then') else'
140+
141+ Case e cases -> function [] (stmt ++ match span revisedMatch) `call` []
142+ where
143+ (tempVar,initialMatch) = caseToMatch cases
144+ (revisedMatch, stmt) =
145+ case e of
146+ L _ (Var x) -> (matchSubst [(tempVar,x)] initialMatch, [])
147+ _ -> (initialMatch, [VarDeclStmt () [varDecl tempVar (expression e)]])
148+
217− ExplicitList es ->
149+ ExplicitList es ->
218− do es' <- mapM toJS' es
150+ get "_J.toList" <| ArrayLit () (map expression es)
219− return $ "_J.toList" ++ parens (jsList es')
151+
220−
221− Data name es ->
152+ Data name es ->
222− do fs <- mapM toJS' es
153+ ObjectLit () (ctor : fields)
223− return $ case name of
154+ where
224− "[]" -> jsNil
155+ ctor = (prop "ctor", string (makeSafe name))
225− "::" -> jsCons (head fs) ((head . tail) fs)
226− _ -> jsObj $ ("ctor:" ++ show name) : fields
227− where fields = zipWith (\n e -> "_" ++ show n ++ ":" ++ e) [0..] fs
156+ fields = zipWith (\n e -> (prop ("_" ++ show n), expression e)) [0..] es
228−
157+
229− Markdown doc -> return $ "Text.text('" ++ pad ++ md ++ pad ++ "')"
158+ Markdown doc -> get "Text.text" <| string (pad ++ md ++ pad)
230− where pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
159+ where pad = "<div style=\"height:0;width:0;\">&nbsp;</div>"
231− md = formatMarkdown $ Pan.writeHtmlString Pan.def doc
160+ md = Pan.writeHtmlString Pan.def doc
232−
161+
233−jsApp e1 e2 =
162+
234− do f <- toJS' func
163+definition def =
235− as <- mapM toJS' args
164+ case def of
236− return $ case as of
165+ TypeAnnotation _ _ -> []
237− [a] -> f ++ parens a
166+ Def pattern expr@(L span _) ->
238− _ -> "A" ++ show (length as) ++ parens (commaSep (f:as))
167+ let assign x = varDecl x (expression expr) in
239− where
168+ case pattern of
240− (func, args) = go [e2] e1
169+ PVar x
241− go args e =
170+ | isOp x ->
242− case e of
171+ let op = LBracket () (ref "_op") (string x) in
243− (L _ (App e1 e2)) -> go (e2 : args) e1
172+ [ ExprStmt () (AssignExpr () OpAssign op (expression expr)) ]
244− _ -> (e, args)
173+ | otherwise ->
245−
174+ [ VarDeclStmt () [ assign x ] ]
246−formatMarkdown = concatMap f
175+
247− where f '\'' = "\\'"
176+ PRecord fields -> [ VarDeclStmt () (assign "$" : map setField fields) ]
248− f '\n' = "\\n"
177+ where
249− f '"' = "\""
178+ setField f = varDecl f (dotSep ["$",f])
250− f c = [c]
179+
251−
180+ PData name patterns | vars /= Nothing ->
252−multiIfToJS span ps =
181+ case vars of
253− case last ps of
182+ Just vs -> [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
254− (L _ (Var "otherwise"), e) -> toJS' e >>= \b -> format b (init ps)
255− _ -> format ("_E.If" ++ parens ("$moduleName," ++ quoted (show span))) ps
256− where
183+ where
257− format base ps =
184+ vars = getVars patterns
258− foldr (\c e -> parens $ c ++ " : " ++ e) base `liftM` mapM f ps
185+ getVars patterns =
259− f (b,e) = do b' <- toJS' b
186+ case patterns of
260− e' <- toJS' e
187+ PVar x : rest -> (x:) `fmap` getVars rest
261− return (b' ++ " ? " ++ e')
188+ [] -> Just []
262−
189+ _ -> Nothing
263−jsLet (defs,e') = do ds <- mapM toJS defs
190+
264− e <- toJS' e'
191+ decl x n = varDecl x (dotSep ["$","_" ++ show n])
265− return $ jsFunc "" (concat ds ++ ret e) ++ "()"
192+ setup vars
266−
193+ | isTuple name = assign "$" : vars
267−caseToJS span e ps = do
194+ | otherwise = safeAssign : vars
268− (tempVar,match) <- caseToMatch ps
195+
269− e' <- toJS' e
196+ safeAssign = varDecl "$" (CondExpr () if' (expression expr) exception)
270− let (match',stmt) = case e of
197+ if' = InfixExpr () OpStrictEq (get "$.ctor") (string name)
271− L _ (Var x) -> (matchSubst [(tempVar,x)] match, "")
198+ exception = get "_E.Case" `call` [ref "$moduleName", string (show span)]
272− _ -> (match, assign tempVar e')
199+
273− matches <- matchToJS span match'
200+ _ -> VarDeclStmt () [assign "$"] : concatMap toDef vars
274− return $ jsFunc "" (stmt ++ matches) ++ "()"
201+ where
275−
202+ vars = Set.toList $ SD.boundVars pattern
276−matchToJS span match =
203+ mkVar = L span . Var
204+ toDef y = definition $
205+ Def (PVar y) (L span $ Case (mkVar "$") [(pattern, mkVar y)])
206+
207+match span mtch =
277− case match of
208+ case mtch of
278− Match name clauses def ->
209+ Match name clauses mtch' -> SwitchStmt () (access name) clauses' : match span mtch'
279− do cases <- concat `liftM` mapM (clauseToJS span name) clauses
210+ where
280− finally <- matchToJS span def
211+ clauses' = map (clause span name) clauses
281− let isLiteral p = case p of
212+ isLiteral p = case p of
282− Clause (Right _) _ _ -> True
213+ Clause (Right _) _ _ -> True
283− _ -> False
214+ _ -> False
284− access = if any isLiteral clauses then "" else ".ctor"
215+ access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
285− return $ concat [ "\nswitch (", name, access, ") {"
216+
286− , indent cases, "\n}", finally ]
287− Fail -> return ("_E.Case" ++ parens ("$moduleName," ++ quoted (show span)))
217+ Fail -> [ ExprStmt () (get "_E.Case" `call` [ref "$moduleName", string (show span)]) ]
288− Break -> return "break;"
218+ Break -> []
289− Other e -> ret `liftM` toJS' e
219+ Other e -> [ ReturnStmt () (Just $ expression e) ]
290− Seq ms -> concat `liftM` mapM (matchToJS span) (dropEnd [] ms)
220+ Seq ms -> concatMap (match span) (dropEnd [] ms)
291 where
221 where
292 dropEnd acc [] = acc
222 dropEnd acc [] = acc
293 dropEnd acc (m:ms) =
223 dropEnd acc (m:ms) =
@@ -295,68 +225,133 @@ matchToJS span match =
295 Other _ -> acc ++ [m]
225 Other _ -> acc ++ [m]
296 _ -> dropEnd (acc ++ [m]) ms
226 _ -> dropEnd (acc ++ [m]) ms
297
227
298−clauseToJS span var (Clause value vars e) = do
228+clause span variable (Clause value vars mtch) =
229+ CaseClause () pattern stmt
230+ where
299− let vars' = map (\n -> var ++ "._" ++ show n) [0..]
231+ vars' = map (\n -> variable ++ "._" ++ show n) [0..]
300− s <- matchToJS span $ matchSubst (zip vars vars') e
232+ stmt = match span $ matchSubst (zip vars vars') mtch
301− pattern <- case value of
233+ pattern = case value of
302− Right (Boolean True) -> return "true"
234+ Right (Boolean b) -> BoolLit () b
303− Right (Boolean False) -> return "false"
304− Right lit -> toJS lit
235+ Right lit -> literal lit
305− Left name -> return . quoted $ case List.elemIndices '.' name of
236+ Left name -> string $ case List.elemIndices '.' name of
306− [] -> name
237+ [] -> name
307− is -> drop (last is + 1) name
238+ is -> drop (last is + 1) name
308− return $ concat [ "\ncase ", pattern, ":", indent s ]
239+
309−
240+jsModule :: MetadataModule () () -> String -- [Statement ()]
310−jsNil = "_L.Nil"
241+jsModule modul = show . prettyPrint $ setup (Just "Elm") (names modul) ++
311−jsCons e1 e2 = "_L.Cons(" ++ e1 ++ "," ++ e2 ++ ")"
242+ [ assign ("Elm" : names modul) (function ["elm"] programStmts) ]
312−jsRange e1 e2 = "_L.range" ++ parens (e1 ++ "," ++ e2)
313−jsCompare e1 e2 op = parens ("_N.cmp(" ++ e1 ++ "," ++ e2 ++ ")" ++ op)
314−
315−
316−binop op e1 e2
317− | op == "Basics.." =
318− do ss <- mapM toJS' (e1 : collect [] e2)
319− return . jsFunc "$" . ret $ apply "$" ss
320− | op == "Basics.<|" =
321− do arg <- toJS' e2
322− funcs <- mapM toJS' (collect [] e1)
323− return (apply arg funcs)
324− | otherwise =
325− binopNormal op `liftM` toJS' e1 `ap` toJS' e2
326 where
243 where
327− apply = foldr (\f arg-> f ++ parens arg)
244+ thisModule = dotSep ("elm" : names modul)
245+ programStmts =
246+ concat [ setup (Just "elm") (names modul)
247+ , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
248+ , [ internalImports (List.intercalate "." (names modul)) ]
249+ , concatMap jsImport (imports modul)
250+ , concatMap importEvent (foreignImports modul)
251+ , [ assign ["_op"] (ObjectLit () []) ]
252+ , concatMap definition . fst . SD.flattenLets [] $ program modul
253+ , map exportEvent $ foreignExports modul
254+ , [ jsExports ]
255+ , [ ReturnStmt () (Just thisModule) ]
256+ ]
257+
258+ jsExports = assign ("elm" : names modul) (ObjectLit () exs)
259+ where
260+ exs = map entry . filter (not . isOp) $ "_op" : exports modul
261+ entry x = (PropId () (var x), ref x)
262+
263+ assign path expr =
264+ case path of
265+ [x] -> VarDeclStmt () [ varDecl x expr ]
266+ _ -> ExprStmt () $
267+ AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
268+
269+ jsImport (modul,_) = setup Nothing path ++ [ assign path (dotSep ("Elm" : path) <| ref "elm") ]
270+ where
271+ path = split modul
328
272
273+ setup namespace path = map create paths
274+ where
275+ create name = assign name (InfixExpr () OpLOr (dotSep name) (ObjectLit () []))
276+ paths = case namespace of
277+ Nothing -> tail . init $ List.inits path
278+ Just nmspc -> drop 2 . init . List.inits $ nmspc : path
279+
280+ addId js = InfixExpr () OpAdd (string (js++"_")) (get "elm.id")
281+
282+ importEvent (js,base,elm,_) =
283+ [ VarDeclStmt () [ varDecl elm $ get "Signal.constant" <| expression base ]
284+ , ExprStmt () $
285+ get "document.addEventListener" `call`
286+ [ addId js
287+ , function ["e"]
288+ [ ExprStmt () $ get "elm.notify" `call` [dotSep [elm,"id"], get "e.value"] ]
289+ ]
290+ ]
291+
292+ exportEvent (js,elm,_) =
293+ ExprStmt () $
294+ ref "A2" `call`
295+ [ get "Signal.lift"
296+ , function ["v"]
297+ [ VarDeclStmt () [varDecl "e" $ get "document.createEvent" <| string "Event"]
298+ , ExprStmt () $
299+ get "e.initEvent" `call` [ addId js, BoolLit () True, BoolLit () True ]
300+ , ExprStmt () $ AssignExpr () OpAssign (LDot () (ref "e") "value") (ref "v")
301+ , ExprStmt () $ get "document.dispatchEvent" <| ref "e"
302+ , ReturnStmt () (Just $ ref "v")
303+ ]
304+ , ref elm ]
305+
306+
307+binop span op e1 e2 =
308+ case op of
309+ "Basics.." -> ["$"] ==> foldr (<|) (ref "$") (map expression (e1 : collect [] e2))
310+ "Basics.<|" -> foldr (<|) (expression e2) (map expression (collect [] e1))
311+ "::" -> expression (L span (Data "::" [e1,e2]))
312+ "List.++" -> get "_L.append" `call` [js1, js2]
313+ _ -> case Map.lookup op opDict of
314+ Just f -> f js1 js2
315+ Nothing -> ref "A2" `call` [ func, js1, js2 ]
316+ where
329 collect es e =
317 collect es e =
330 case e of
318 case e of
331 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
319 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
332 _ -> es ++ [e]
320 _ -> es ++ [e]
333
321
334−binopNormal op s1 s2 =
322+ js1 = expression e1
335− case Map.lookup op opDict of
323+ js2 = expression e2
336− Just e -> e
324+
337− Nothing -> "A2" ++ parens (commaSep [ prefix ++ func, s1, s2 ])
325+ func | isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string op)
338− where
339− func | isOp op' = "_op['" ++ op' ++ "']"
340− | otherwise = op'
326+ | otherwise = dotSep parts
341− (prefix, op') = case List.elemIndices '.' op of
327+ where
342− [] -> ("", op)
328+ parts = split op
343− xs -> splitAt (last xs + 1) op
329+ operator = last parts
344−
330+
345− opDict = Map.fromList $ basics ++
331+ opDict = Map.fromList (infixOps ++ specialOps)
346− [ ("::", jsCons s1 s2)
332+
347− , ("List.++", "_L.append" ++ parens (s1 ++ "," ++ s2)) ]
333+ specialOp str func = ("Basics." ++ str, func)
348−
334+ infixOp str op = specialOp str (InfixExpr () op)
349− ops = pow : map (\op -> (op, parens (s1 ++ op ++ s2))) ["+","-","*","/","&&","||"]
335+
350− where pow = ("^" , "Math.pow(" ++ s1 ++ "," ++ s2 ++ ")")
336+ infixOps =
351−
337+ [ infixOp "+" OpAdd
352− basics = ops ++ map (\(op,e) -> ("Basics." ++ op, e))
338+ , infixOp "-" OpSub
353− (ops ++ [ ("<|", s1 ++ parens s2)
339+ , infixOp "*" OpMul
354− , ("|>", s2 ++ parens s1)
340+ , infixOp "/" OpDiv
355− , ("==", "_N.eq(" ++ s1 ++ "," ++ s2 ++ ")")
341+ , infixOp "&&" OpLAnd
356− , ("/=", "!_N.eq(" ++ s1 ++ "," ++ s2 ++ ")")
342+ , infixOp "||" OpLOr
357− , ("<" , jsCompare s1 s2 "<0")
343+ ]
358− , (">" , jsCompare s1 s2 ">0")
344+
359− , ("<=", jsCompare s1 s2 "<1")
345+ specialOps =
360− , (">=", jsCompare s1 s2 ">-1")
346+ [ specialOp "^" $ \a b -> get "Math.pow" `call` [a,b]
361− , ("div", parens (s1 ++ "/" ++ s2 ++ "|0"))
347+ , specialOp "|>" $ flip (<|)
362− ])
348+ , specialOp "==" $ \a b -> get "_N.eq" `call` [a,b]
349+ , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (get "_N.eq" `call` [a,b])
350+ , specialOp "<" $ cmp OpLT 0
351+ , specialOp ">" $ cmp OpGT 0
352+ , specialOp "<=" $ cmp OpLT 1
353+ , specialOp ">=" $ cmp OpGT (-1)
354+ , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
355+ ]
356+
357+ cmp op n a b = InfixExpr () op (get "_N.cmp" `call` [a,b]) (IntLit () n)
compiler/Parse/Declaration.hs−1
@@ -14,7 +14,6 @@ import qualified SourceSyntax.Type as T
14import qualified Parse.Type as Type
14import qualified Parse.Type as Type
15import SourceSyntax.Declaration (Declaration(..), Assoc(..))
15import SourceSyntax.Declaration (Declaration(..), Assoc(..))
16
16
17−import Unique
18
17
19declaration :: IParser (Declaration t v)
18declaration :: IParser (Declaration t v)
20declaration = alias <|> datatype <|> infixDecl <|> foreignDef <|> definition
19declaration = alias <|> datatype <|> infixDecl <|> foreignDef <|> definition
compiler/Parse/Expression.hs−2
@@ -18,8 +18,6 @@ import qualified SourceSyntax.Literal as Literal
18import SourceSyntax.Expression
18import SourceSyntax.Expression
19import SourceSyntax.Declaration (Declaration(Definition))
19import SourceSyntax.Declaration (Declaration(Definition))
20
20
21−import Unique
22−
23
21
24-------- Basic Terms --------
22-------- Basic Terms --------
25
23
compiler/Parse/Helpers.hs+1−9
@@ -64,18 +64,10 @@ rLabel = lowVar
64innerVarChar :: IParser Char
64innerVarChar :: IParser Char
65innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
65innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
66
66
67−makeSafe :: String -> String
68−makeSafe = dereserve . deprime
69− where
70− deprime = map (\c -> if c == '\'' then '$' else c)
71− dereserve x = case Set.member x jsReserveds of
72− False -> x
73− True -> "$" ++ x
74−
75makeVar :: IParser Char -> IParser String
67makeVar :: IParser Char -> IParser String
76makeVar p = do v <- (:) <$> p <*> many innerVarChar
68makeVar p = do v <- (:) <$> p <*> many innerVarChar
77 guard (v `notElem` reserveds)
69 guard (v `notElem` reserveds)
78− return (makeSafe v)
70+ return v
79
71
80reserved :: String -> IParser String
72reserved :: String -> IParser String
81reserved word =
73reserved word =
compiler/Parse/Pattern.hs−1
@@ -6,7 +6,6 @@ import Control.Monad
6import Control.Monad.State
6import Control.Monad.State
7import Data.Char (isUpper)
7import Data.Char (isUpper)
8import Data.List (intercalate)
8import Data.List (intercalate)
9−import Unique
10import Text.Parsec hiding (newline,spaces,State)
9import Text.Parsec hiding (newline,spaces,State)
11import Text.Parsec.Indent
10import Text.Parsec.Indent
12
11
compiler/Parse/Type.hs−1
@@ -9,7 +9,6 @@ import Text.Parsec.Indent
9
9
10import SourceSyntax.Type as T
10import SourceSyntax.Type as T
11import Parse.Helpers
11import Parse.Helpers
12−import Unique
13
12
14tvar :: IParser T.Type
13tvar :: IParser T.Type
15tvar = T.Var <$> lowVar <?> "type variable"
14tvar = T.Var <$> lowVar <?> "type variable"
compiler/SourceSyntax/Literal.hs+2−2
@@ -6,7 +6,7 @@ import SourceSyntax.PrettyPrint
6import qualified Text.PrettyPrint as PP
6import qualified Text.PrettyPrint as PP
7
7
8data Literal = IntNum Int
8data Literal = IntNum Int
9− | FloatNum Float
9+ | FloatNum Double
10 | Chr Char
10 | Chr Char
11 | Str String
11 | Str String
12 | Boolean Bool
12 | Boolean Bool
@@ -16,7 +16,7 @@ instance Pretty Literal where
16 pretty literal =
16 pretty literal =
17 case literal of
17 case literal of
18 IntNum n -> PP.int n
18 IntNum n -> PP.int n
19− FloatNum n -> PP.float n
19+ FloatNum n -> PP.double n
20 Chr c -> PP.quotes (PP.char c)
20 Chr c -> PP.quotes (PP.char c)
21 Str s -> PP.text (show s)
21 Str s -> PP.text (show s)
22 Boolean bool -> PP.text (show bool)
22 Boolean bool -> PP.text (show bool)
compiler/Unique.hsdeleted−19
@@ -1,19 +0,0 @@
1−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2−module Unique (guid, set, run, runAt, Unique) where
3−
4−import Control.Monad.State (evalState, State, get, put)
5−
6−-- Wrapper around State monad.
7−newtype Unique a = U { runU :: State Int a }
8− deriving (Monad)
9−
10−-- Get the next GUID, incrementing the counter.
11−guid :: Unique Int
12−guid = U $ do n <- get
13− put (n + 1)
14− return n
15−
16−set n = U (put n)
17−
18−run = runAt 0
19−runAt n x = evalState (runU x) n