@@ -1,6 +1,8 @@
1module Generate.JavaScript where
1module Generate.JavaScript where
3−import Control.Arrow ((***))
3+import Control.Arrow (first,(***))
4+import Control.Applicative ((<$>),(<*>))
5+import Control.Monad.State
4import qualified Data.List as List
6import qualified Data.List as List
5import qualified Data.Map as Map
7import qualified Data.Map as Map
6import qualified Data.Set as Set
8import qualified Data.Set as Set
@@ -39,22 +41,22 @@ call = CallExpr ()
39string = StringLit ()
41string = StringLit ()
41dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
43dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
42−get = dotSep . split
44+obj = dotSep . split
44varDecl x expr =
46varDecl x expr =
45 VarDecl () (var x) (Just expr)
47 VarDecl () (var x) (Just expr)
47include alias moduleName =
49include alias moduleName =
48− varDecl alias (get moduleName <| ref "elm")
50+ varDecl alias (obj moduleName <| ref "elm")
50internalImports name =
52internalImports name =
51 VarDeclStmt ()
53 VarDeclStmt ()
52− [ varDecl "N" (get "Elm.Native")
54+ [ varDecl "N" (obj "Elm.Native")
53 , include "_N" "N.Utils"
55 , include "_N" "N.Utils"
54 , include "_L" "N.List"
56 , include "_L" "N.List"
55 , include "_E" "N.Error"
57 , include "_E" "N.Error"
56 , include "_J" "N.JavaScript"
58 , include "_J" "N.JavaScript"
57− , varDecl "_str" (get "_J.toString")
59+ , varDecl "_str" (obj "_J.toString")
58 , varDecl "$moduleName" (string name)
60 , varDecl "$moduleName" (string name)
@@ -66,38 +68,57 @@ literal lit =
66 FloatNum n -> NumLit () n
68 FloatNum n -> NumLit () n
67 Boolean b -> BoolLit () b
69 Boolean b -> BoolLit () b
69−expression :: LExpr () () -> Expression ()
71+expression :: LExpr () () -> State Int (Expression ())
70expression (L span expr) =
72expression (L span expr) =
71 case expr of
73 case expr of
72− Var x -> ref x
74+ Var x -> return $ ref x
73− Literal lit -> literal lit
75+ Literal lit -> return $ literal lit
74− Range lo hi -> get "_L.range" `call` [expression lo, expression hi]
76− Access e x -> DotRef () (expression e) (var x)
77+ Range lo hi ->
77− Remove e x -> get "_N.remove" `call` [string x, expression e]
78+ do lo' <- expression lo
78− Insert e x v -> get "_N.insert" `call` [string x, expression v, expression e]
79+ hi' <- expression hi
79− Modify e fs ->
80+ return $ obj "_L.range" `call` [lo',hi']
80− let modify (f,v) = ArrayLit () [string f, expression v]
81− in get "_N.replace" `call` [ArrayLit () (map modify fs), expression e]
83− Record fields -> ObjectLit () $ (PropId () (var "_"), hidden) : visible
82+ Access e x ->
84− where
83+ do e' <- expression e
85− combine r (k,v) = Map.insertWith (++) k [v] r
84+ return $ DotRef () e' (var x)
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
91− Binop op e1 e2 -> binop span op e1 e2
86+ Remove e x ->
87+ do e' <- expression e
88+ return $ obj "_N.remove" `call` [string x, e']
93− Lambda p e@(L s _) -> fastFunc
90+ Insert e x v ->
91+ do v' <- expression v
93+ return $ obj "_N.insert" `call` [string x, v', e']
96+ do e' <- expression e
97+ fs' <- forM fs $ \(f,v) -> do
99+ return $ ArrayLit () [string f, v']
100+ return $ obj "_N.replace" `call` [ArrayLit () fs', e']
103+ do fields' <- forM fields $ \(f,e) -> do
104+ (,) f <$> expression e
105+ let fieldMap = List.foldl' combine Map.empty fields'
106+ return $ ObjectLit () $ (PropId () (var "_"), hidden fieldMap) : visible fieldMap
95− fastFunc
108+ combine r (k,v) = Map.insertWith (++) k [v] r
96− | length args < 2 || length args > 9 =
109+ prop = PropId () . var
97− foldr (==>) (expression body) (map (:[]) args)
110+ hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
98− | otherwise =
111+ Map.toList . Map.filter (not . null) $ Map.map tail fs
99− ref ("F" ++ show (length args)) <| (args ==> expression body)
112+ visible fs = map (first prop) . Map.toList $ Map.map head fs
114+ Binop op e1 e2 -> binop span op e1 e2
116+ Lambda p e@(L s _) ->
117+ do body' <- expression body
118+ return $ case length args < 2 || length args > 9 of
119+ True -> foldr (==>) body' (map (:[]) args)
120+ False -> ref ("F" ++ show (length args)) <| (args ==> body')
101 (args, body) = foldr depattern ([], innerBody) (zip patterns [0..])
122 (args, body) = foldr depattern ([], innerBody) (zip patterns [0..])
103 depattern (pattern,n) (args, body) =
124 depattern (pattern,n) (args, body) =
@@ -114,72 +135,83 @@ expression (L span expr) =
114 _ -> (patterns, lexpr)
135 _ -> (patterns, lexpr)
116 App e1 e2 ->
137 App e1 e2 ->
138+ do func' <- expression func
139+ args' <- mapM expression args
117− case args of
140+ return $ case args' of
118− [arg] -> func <| arg
141+ [arg] -> func' <| arg
119− _ -> ref aN `call` (func:args)
142+ _ -> ref aN `call` (func':args')
121 aN = "A" ++ show (length args)
144 aN = "A" ++ show (length args)
122 (func, args) = getArgs e1 [e2]
145 (func, args) = getArgs e1 [e2]
123 getArgs func args =
146 getArgs func args =
124 case func of
147 case func of
125 (L _ (App f arg)) -> getArgs f (arg : args)
148 (L _ (App f arg)) -> getArgs f (arg : args)
126− _ -> (expression func, map expression args)
149+ _ -> (func, args)
128− Let defs e -> function [] stmts `call` []
151+ Let defs e ->
130− (defs',e') = SD.flattenLets defs e
152+ do let (defs',e') = SD.flattenLets defs e
131− stmts = concatMap definition defs' ++ [ ReturnStmt () (Just (expression e')) ]
153+ stmts <- concat <$> mapM definition defs'
154+ exp <- expression e'
155+ return $ function [] (stmts ++ [ ReturnStmt () (Just exp) ]) `call` []
133 MultiIf branches ->
157 MultiIf branches ->
158+ do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
134− case last branches of
159+ return $ case last branches of
135− (L _ (Var "otherwise"), e) -> ifs (init branches) (expression e)
160+ (L _ (Var "otherwise"), e) -> ifs (init branches') (snd (last branches'))
136− _ -> ifs branches (get "_E.If" `call` [ ref "$moduleName", string (show span) ])
162+ (obj "_E.If" `call` [ ref "$moduleName", string (show span) ])
138 ifs branches finally = foldr iff finally branches
164 ifs branches finally = foldr iff finally branches
139− iff (if', then') else' = CondExpr () (expression if') (expression then') else'
165+ iff (if', then') else' = CondExpr () if' then' else'
141− Case e cases -> function [] (stmt ++ match span revisedMatch) `call` []
167+ Case e cases ->
143− (tempVar,initialMatch) = caseToMatch cases
168+ do (tempVar,initialMatch) <- caseToMatch cases
144− (revisedMatch, stmt) =
169+ (revisedMatch, stmt) <-
145− case e of
170+ case e of
146− L _ (Var x) -> (matchSubst [(tempVar,x)] initialMatch, [])
171+ L _ (Var x) -> return (matchSubst [(tempVar,x)] initialMatch, [])
172+ _ -> do e' <- expression e
147− _ -> (initialMatch, [VarDeclStmt () [varDecl tempVar (expression e)]])
173+ return (initialMatch, [VarDeclStmt () [varDecl tempVar e']])
174+ match' <- match span revisedMatch
175+ return (function [] (stmt ++ match') `call` [])
149 ExplicitList es ->
177 ExplicitList es ->
178+ do es' <- mapM expression es
150− get "_J.toList" <| ArrayLit () (map expression es)
179+ return $ obj "_J.toList" <| ArrayLit () es'
152 Data name es ->
181 Data name es ->
182+ do es' <- mapM expression es
153− ObjectLit () (ctor : fields)
183+ return $ ObjectLit () (ctor : fields es')
155− ctor = (prop "ctor", string (makeSafe name))
185+ ctor = (prop "ctor", string (makeSafe name))
156− fields = zipWith (\n e -> (prop ("_" ++ show n), expression e)) [0..] es
186+ fields = zipWith (\n e -> (prop ("_" ++ show n), e)) [0..]
158− Markdown doc -> get "Text.text" <| string (pad ++ md ++ pad)
188+ Markdown doc -> return $ obj "Text.text" <| string (pad ++ md ++ pad)
159 where pad = "<div style=\"height:0;width:0;\"> </div>"
189 where pad = "<div style=\"height:0;width:0;\"> </div>"
160 md = Pan.writeHtmlString Pan.def doc
190 md = Pan.writeHtmlString Pan.def doc
162−
192+definition :: Def () () -> State Int [Statement ()]
163definition def =
193definition def =
164 case def of
194 case def of
165− TypeAnnotation _ _ -> []
195+ TypeAnnotation _ _ -> return []
166− Def pattern expr@(L span _) ->
197+ Def pattern expr@(L span _) -> do
198+ expr' <- expression expr
167− let assign x = varDecl x (expression expr) in
199+ let assign x = varDecl x expr'
168 case pattern of
200 case pattern of
170− | isOp x ->
202+ | isOp x ->
171− let op = LBracket () (ref "_op") (string x) in
203+ let op = LBracket () (ref "_op") (string x) in
172− [ ExprStmt () (AssignExpr () OpAssign op (expression expr)) ]
204+ return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
173− | otherwise ->
205+ | otherwise ->
174− [ VarDeclStmt () [ assign x ] ]
206+ return [ VarDeclStmt () [ assign x ] ]
209+ let setField f = varDecl f (dotSep ["$",f]) in
176− PRecord fields -> [ VarDeclStmt () (assign "$" : map setField fields) ]
210+ return [ VarDeclStmt () (assign "$" : map setField fields) ]
178− setField f = varDecl f (dotSep ["$",f])
180 PData name patterns | vars /= Nothing ->
212 PData name patterns | vars /= Nothing ->
181 case vars of
213 case vars of
182− Just vs -> [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
214+ Just vs -> return [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
184 vars = getVars patterns
216 vars = getVars patterns
185 getVars patterns =
217 getVars patterns =
@@ -193,11 +225,13 @@ definition def =
193 | isTuple name = assign "$" : vars
225 | isTuple name = assign "$" : vars
194 | otherwise = safeAssign : vars
226 | otherwise = safeAssign : vars
196− safeAssign = varDecl "$" (CondExpr () if' (expression expr) exception)
228+ safeAssign = varDecl "$" (CondExpr () if' expr' exception)
197− if' = InfixExpr () OpStrictEq (get "$.ctor") (string name)
229+ if' = InfixExpr () OpStrictEq (obj "$.ctor") (string name)
198− exception = get "_E.Case" `call` [ref "$moduleName", string (show span)]
230+ exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
233+ do defs' <- concat <$> mapM toDef vars
200− _ -> VarDeclStmt () [assign "$"] : concatMap toDef vars
234+ return (VarDeclStmt () [assign "$"] : defs')
202 vars = Set.toList $ SD.boundVars pattern
236 vars = Set.toList $ SD.boundVars pattern
203 mkVar = L span . Var
237 mkVar = L span . Var
@@ -206,18 +240,22 @@ definition def =
207match span mtch =
241match span mtch =
208 case mtch of
242 case mtch of
243+ Match name clauses mtch' ->
244+ do clauses' <- mapM (clause span name) clauses
245+ mtch'' <- match span mtch'
209− Match name clauses mtch' -> SwitchStmt () (access name) clauses' : match span mtch'
246+ return (SwitchStmt () (access name) clauses' : mtch'')
211− clauses' = map (clause span name) clauses
212 isLiteral p = case p of
248 isLiteral p = case p of
213 Clause (Right _) _ _ -> True
249 Clause (Right _) _ _ -> True
214 _ -> False
250 _ -> False
215 access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
251 access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
217− Fail -> [ ExprStmt () (get "_E.Case" `call` [ref "$moduleName", string (show span)]) ]
253+ Fail -> return [ ExprStmt () (obj "_E.Case" `call` [ref "$moduleName", string (show span)]) ]
218− Break -> []
254+ Break -> return []
256+ do e' <- expression e
219− Other e -> [ ReturnStmt () (Just $ expression e) ]
257+ return [ ReturnStmt () (Just e') ]
220− Seq ms -> concatMap (match span) (dropEnd [] ms)
258+ Seq ms -> concat <$> mapM (match span) (dropEnd [] ms)
222 dropEnd acc [] = acc
260 dropEnd acc [] = acc
223 dropEnd acc (m:ms) =
261 dropEnd acc (m:ms) =
@@ -226,10 +264,9 @@ match span mtch =
226 _ -> dropEnd (acc ++ [m]) ms
264 _ -> dropEnd (acc ++ [m]) ms
228clause span variable (Clause value vars mtch) =
266clause span variable (Clause value vars mtch) =
229− CaseClause () pattern stmt
267+ CaseClause () pattern <$> match span (matchSubst (zip vars vars') mtch)
231 vars' = map (\n -> variable ++ "._" ++ show n) [0..]
269 vars' = map (\n -> variable ++ "._" ++ show n) [0..]
232− stmt = match span $ matchSubst (zip vars vars') mtch
233 pattern = case value of
270 pattern = case value of
234 Right (Boolean b) -> BoolLit () b
271 Right (Boolean b) -> BoolLit () b
235 Right lit -> literal lit
272 Right lit -> literal lit
@@ -237,7 +274,8 @@ clause span variable (Clause value vars mtch) =
237 [] -> name
274 [] -> name
238 is -> drop (last is + 1) name
275 is -> drop (last is + 1) name
240−jsModule :: MetadataModule () () -> String -- [Statement ()]
278+jsModule :: MetadataModule () () -> String
241jsModule modul = show . prettyPrint $ setup (Just "Elm") (names modul) ++
279jsModule modul = show . prettyPrint $ setup (Just "Elm") (names modul) ++
242 [ assign ("Elm" : names modul) (function ["elm"] programStmts) ]
280 [ assign ("Elm" : names modul) (function ["elm"] programStmts) ]
@@ -249,7 +287,7 @@ jsModule modul = show . prettyPrint $ setup (Just "Elm") (names modul) ++
249 , concatMap jsImport (imports modul)
287 , concatMap jsImport (imports modul)
250 , concatMap importEvent (foreignImports modul)
288 , concatMap importEvent (foreignImports modul)
251 , [ assign ["_op"] (ObjectLit () []) ]
289 , [ assign ["_op"] (ObjectLit () []) ]
252− , concatMap definition . fst . SD.flattenLets [] $ program modul
290+ , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
253 , map exportEvent $ foreignExports modul
291 , map exportEvent $ foreignExports modul
254 , [ jsExports ]
292 , [ jsExports ]
255 , [ ReturnStmt () (Just thisModule) ]
293 , [ ReturnStmt () (Just thisModule) ]
@@ -277,42 +315,52 @@ jsModule modul = show . prettyPrint $ setup (Just "Elm") (names modul) ++
277 Nothing -> tail . init $ List.inits path
315 Nothing -> tail . init $ List.inits path
278 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
316 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
280− addId js = InfixExpr () OpAdd (string (js++"_")) (get "elm.id")
318+ addId js = InfixExpr () OpAdd (string (js++"_")) (obj "elm.id")
282 importEvent (js,base,elm,_) =
320 importEvent (js,base,elm,_) =
283− [ VarDeclStmt () [ varDecl elm $ get "Signal.constant" <| expression base ]
321+ [ VarDeclStmt () [ varDecl elm $ obj "Signal.constant" <| evalState (expression base) 0 ]
284 , ExprStmt () $
322 , ExprStmt () $
285− get "document.addEventListener" `call`
323+ obj "document.addEventListener" `call`
286 [ addId js
324 [ addId js
287 , function ["e"]
325 , function ["e"]
288− [ ExprStmt () $ get "elm.notify" `call` [dotSep [elm,"id"], get "e.value"] ]
326+ [ ExprStmt () $ obj "elm.notify" `call` [dotSep [elm,"id"], obj "e.value"] ]
292 exportEvent (js,elm,_) =
330 exportEvent (js,elm,_) =
293 ExprStmt () $
331 ExprStmt () $
294 ref "A2" `call`
332 ref "A2" `call`
295− [ get "Signal.lift"
333+ [ obj "Signal.lift"
296 , function ["v"]
334 , function ["v"]
297− [ VarDeclStmt () [varDecl "e" $ get "document.createEvent" <| string "Event"]
335+ [ VarDeclStmt () [varDecl "e" $ obj "document.createEvent" <| string "Event"]
298 , ExprStmt () $
336 , ExprStmt () $
299− get "e.initEvent" `call` [ addId js, BoolLit () True, BoolLit () True ]
337+ obj "e.initEvent" `call` [ addId js, BoolLit () True, BoolLit () True ]
300 , ExprStmt () $ AssignExpr () OpAssign (LDot () (ref "e") "value") (ref "v")
338 , ExprStmt () $ AssignExpr () OpAssign (LDot () (ref "e") "value") (ref "v")
301− , ExprStmt () $ get "document.dispatchEvent" <| ref "e"
339+ , ExprStmt () $ obj "document.dispatchEvent" <| ref "e"
302 , ReturnStmt () (Just $ ref "v")
340 , ReturnStmt () (Just $ ref "v")
304 , ref elm ]
342 , ref elm ]
307binop span op e1 e2 =
344binop span op e1 e2 =
308 case op of
345 case op of
309− "Basics.." -> ["$"] ==> foldr (<|) (ref "$") (map expression (e1 : collect [] e2))
347+ do es <- mapM expression (e1 : collect [] e2)
348+ return $ ["$"] ==> foldr (<|) (ref "$") es
350+ do e2' <- expression e2
310− "Basics.<|" -> foldr (<|) (expression e2) (map expression (collect [] e1))
351+ es <- mapM expression (collect [] e1)
311− "::" -> expression (L span (Data "::" [e1,e2]))
352+ return $ foldr (<|) e2' es
354+ do e1' <- expression e1
355+ e2' <- expression e2
312− "List.++" -> get "_L.append" `call` [js1, js2]
356+ return $ obj "_L.append" `call` [e1', e2']
357+ "::" -> expression (L span (Data "::" [e1,e2]))
359+ do e1' <- expression e1
360+ e2' <- expression e2
313− _ -> case Map.lookup op opDict of
361+ return $ case Map.lookup op opDict of
314− Just f -> f js1 js2
362+ Just f -> f e1' e2'
315− Nothing -> ref "A2" `call` [ func, js1, js2 ]
363+ Nothing -> ref "A2" `call` [ func, e1', e2' ]
317 collect es e =
365 collect es e =
318 case e of
366 case e of
@@ -343,10 +391,10 @@ binop span op e1 e2 =
345 specialOps =
393 specialOps =
346− [ specialOp "^" $ \a b -> get "Math.pow" `call` [a,b]
394+ [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
347 , specialOp "|>" $ flip (<|)
395 , specialOp "|>" $ flip (<|)
348− , specialOp "==" $ \a b -> get "_N.eq" `call` [a,b]
396+ , specialOp "==" $ \a b -> obj "_N.eq" `call` [a,b]
349− , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (get "_N.eq" `call` [a,b])
397+ , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_N.eq" `call` [a,b])
350 , specialOp "<" $ cmp OpLT 0
398 , specialOp "<" $ cmp OpLT 0
351 , specialOp ">" $ cmp OpGT 0
399 , specialOp ">" $ cmp OpGT 0
352 , specialOp "<=" $ cmp OpLT 1
400 , specialOp "<=" $ cmp OpLT 1
@@ -354,4 +402,4 @@ binop span op e1 e2 =
354 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
402 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
357− cmp op n a b = InfixExpr () op (get "_N.cmp" `call` [a,b]) (IntLit () n)
405+ cmp op n a b = InfixExpr () op (obj "_N.cmp" `call` [a,b]) (IntLit () n)