@@ -1,3 +1,4 @@
1module Generate.JavaScript (generate) where
2module Generate.JavaScript (generate) where
3import Control.Arrow (first,(***))
4import Control.Arrow (first,(***))
@@ -7,67 +8,49 @@ import qualified Data.List as List
7import qualified Data.Map as Map
8import qualified Data.Map as Map
8import qualified Data.Set as Set
9import qualified Data.Set as Set
11+import Generate.JavaScript.Helpers
10import qualified Generate.Cases as Case
12import qualified Generate.Cases as Case
13+import qualified Generate.JavaScript.Ports as Port
11import qualified Generate.Markdown as MD
14import qualified Generate.Markdown as MD
12import qualified SourceSyntax.Helpers as Help
15import qualified SourceSyntax.Helpers as Help
13import SourceSyntax.Literal
16import SourceSyntax.Literal
14−import SourceSyntax.Pattern
17+import SourceSyntax.Pattern as Pattern
15import SourceSyntax.Location
18import SourceSyntax.Location
16import SourceSyntax.Expression
19import SourceSyntax.Expression
17import SourceSyntax.Module
20import SourceSyntax.Module
18−import qualified Transform.SortDefinitions as SD
19import Language.ECMAScript3.Syntax
21import Language.ECMAScript3.Syntax
20import Language.ECMAScript3.PrettyPrint
22import Language.ECMAScript3.PrettyPrint
21import qualified Transform.SafeNames as MakeSafe
23import qualified Transform.SafeNames as MakeSafe
23−split :: String -> [String]
27− case break (=='.') str of
28− (x,'.':rest) | Help.isOp x -> vars ++ [x ++ '.' : rest]
29− | otherwise -> go (vars ++ [x]) rest
30− (x,[]) -> vars ++ [x]
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
41−dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
44varDecl :: String -> Expression () -> VarDecl ()
25varDecl :: String -> Expression () -> VarDecl ()
45varDecl x expr =
26varDecl x expr =
46 VarDecl () (var x) (Just expr)
27 VarDecl () (var x) (Just expr)
29+include :: String -> String -> VarDecl ()
48include alias moduleName =
30include alias moduleName =
49 varDecl alias (obj (moduleName ++ ".make") <| ref "_elm")
31 varDecl alias (obj (moduleName ++ ".make") <| ref "_elm")
33+internalImports :: String -> Statement ()
51internalImports name =
34internalImports name =
52 VarDeclStmt ()
35 VarDeclStmt ()
53− [ varDecl "N" (obj "Elm.Native")
36+ [ varDecl "_N" (obj "Elm.Native")
54− , include "_N" "N.Utils"
37+ , include "_U" "_N.Utils"
55− , include "_L" "N.List"
38+ , include "_L" "_N.List"
56− , include "_E" "N.Error"
39+ , include "_E" "_N.Error"
57− , include "_J" "N.JavaScript"
40+ , include "_J" "_N.JavaScript"
58 , varDecl "$moduleName" (string name)
41 , varDecl "$moduleName" (string name)
61literal :: Literal -> Expression ()
44literal :: Literal -> Expression ()
62literal lit =
45literal lit =
63 case lit of
46 case lit of
64− Chr c -> obj "_N.chr" <| string [c]
47+ Chr c -> obj "_U.chr" <| string [c]
65 Str s -> string s
48 Str s -> string s
66 IntNum n -> IntLit () n
49 IntNum n -> IntLit () n
67 FloatNum n -> NumLit () n
50 FloatNum n -> NumLit () n
68 Boolean b -> BoolLit () b
51 Boolean b -> BoolLit () b
70−expression :: LExpr () () -> State Int (Expression ())
53+expression :: LExpr -> State Int (Expression ())
71expression (L span expr) =
54expression (L span expr) =
72 case expr of
55 case expr of
73 Var x -> return $ ref x
56 Var x -> return $ ref x
@@ -84,19 +67,19 @@ expression (L span expr) =
85 Remove e x ->
68 Remove e x ->
86 do e' <- expression e
69 do e' <- expression e
87− return $ obj "_N.remove" `call` [string x, e']
70+ return $ obj "_U.remove" `call` [string x, e']
89 Insert e x v ->
72 Insert e x v ->
90 do v' <- expression v
73 do v' <- expression v
91 e' <- expression e
74 e' <- expression e
92− return $ obj "_N.insert" `call` [string x, v', e']
75+ return $ obj "_U.insert" `call` [string x, v', e']
94 Modify e fs ->
77 Modify e fs ->
95 do e' <- expression e
78 do e' <- expression e
96 fs' <- forM fs $ \(f,v) -> do
79 fs' <- forM fs $ \(f,v) -> do
97 v' <- expression v
80 v' <- expression v
98 return $ ArrayLit () [string f, v']
81 return $ ArrayLit () [string f, v']
99− return $ obj "_N.replace" `call` [ArrayLit () fs', e']
82+ return $ obj "_U.replace" `call` [ArrayLit () fs', e']
101 Record fields ->
84 Record fields ->
102 do fields' <- forM fields $ \(f,e) -> do
85 do fields' <- forM fields $ \(f,e) -> do
@@ -148,10 +131,10 @@ expression (L span expr) =
148 _ -> (func, args)
131 _ -> (func, args)
150 Let defs e ->
133 Let defs e ->
151− do let (defs',e') = SD.flattenLets defs e
134+ do let (defs',e') = flattenLets defs e
152 stmts <- concat <$> mapM definition defs'
135 stmts <- concat <$> mapM definition defs'
153 exp <- expression e'
136 exp <- expression e'
154− return $ function [] (stmts ++ [ ReturnStmt () (Just exp) ]) `call` []
137+ return $ function [] (stmts ++ [ ret exp ]) `call` []
156 MultiIf branches ->
139 MultiIf branches ->
157 do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
140 do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
@@ -192,56 +175,59 @@ expression (L span expr) =
192 pad = "<div style=\"height:0;width:0;\"> </div>"
175 pad = "<div style=\"height:0;width:0;\"> </div>"
193 md = pad ++ MD.toHtml doc ++ pad
176 md = pad ++ MD.toHtml doc ++ pad
195−definition :: Def () () -> State Int [Statement ()]
178+ PortIn name tipe ->
196−definition def =
179+ return $ obj "Native.Ports.portIn" `call` [ string name, Port.incoming tipe ]
198− TypeAnnotation _ _ -> return []
181+ PortOut name tipe value ->
199−
182+ do value' <- expression value
183+ return $ obj "Native.Ports.portOut" `call`
184+ [ string name, Port.outgoing tipe, value' ]
186+definition :: Def -> State Int [Statement ()]
200− Def pattern expr@(L span _) -> do
187+definition (Definition pattern expr@(L span _) _) = do
201− expr' <- expression expr
188+ expr' <- expression expr
202− let assign x = varDecl x expr'
189+ let assign x = varDecl x expr'
203− case pattern of
190+ case pattern of
205− | Help.isOp x ->
192+ | Help.isOp x ->
206− let op = LBracket () (ref "_op") (string x) in
193+ let op = LBracket () (ref "_op") (string x) in
207− return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
194+ return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
208− | otherwise ->
195+ | otherwise ->
209− return [ VarDeclStmt () [ assign x ] ]
196+ return [ VarDeclStmt () [ assign x ] ]
211− PRecord fields ->
198+ PRecord fields ->
212− let setField f = varDecl f (dotSep ["$",f]) in
199+ let setField f = varDecl f (dotSep ["$",f]) in
213− return [ VarDeclStmt () (assign "$" : map setField fields) ]
200+ return [ VarDeclStmt () (assign "$" : map setField fields) ]
215− PData name patterns | vars /= Nothing ->
202+ PData name patterns | vars /= Nothing ->
217− Just vs -> return [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
203+ return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
219− vars = getVars patterns
205+ vars = getVars patterns
220− getVars patterns =
206+ getVars patterns =
221− case patterns of
207+ case patterns of
222− PVar x : rest -> (x:) `fmap` getVars rest
208+ PVar x : rest -> (x:) `fmap` getVars rest
223− [] -> Just []
209+ [] -> Just []
224− _ -> Nothing
210+ _ -> Nothing
226− decl x n = varDecl x (dotSep ["$","_" ++ show n])
212+ decl x n = varDecl x (dotSep ["$","_" ++ show n])
227− setup vars
213+ setup vars
228− | Help.isTuple name = assign "$" : vars
214+ | Help.isTuple name = assign "$" : vars
229− | otherwise = assign "$raw" : safeAssign : vars
215+ | otherwise = assign "$raw" : safeAssign : vars
231− safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
217+ safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
232− if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
218+ if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
233− exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
219+ exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
236− do defs' <- concat <$> mapM toDef vars
222+ do defs' <- concat <$> mapM toDef vars
237− return (VarDeclStmt () [assign "$"] : defs')
223+ return (VarDeclStmt () [assign "$"] : defs')
239− vars = Set.toList $ SD.boundVars pattern
225+ vars = Set.toList $ Pattern.boundVars pattern
240− mkVar = L span . Var
226+ mkVar = L span . Var
241− toDef y = definition $
242− Def (PVar y) (L span $ Case (mkVar "$") [(pattern, mkVar y)])
227+ toDef y = let expr = L span $ Case (mkVar "$") [(pattern, mkVar y)]
243−
228+ in definition $ Definition (PVar y) expr Nothing
244−match :: (Show a) => a -> Case.Match () () -> State Int [Statement ()]
230+match :: SrcSpan -> Case.Match -> State Int [Statement ()]
245match span mtch =
231match span mtch =
246 case mtch of
232 case mtch of
247 Case.Match name clauses mtch' ->
233 Case.Match name clauses mtch' ->
@@ -263,7 +249,7 @@ match span mtch =
263 Case.Break -> return [BreakStmt () Nothing]
249 Case.Break -> return [BreakStmt () Nothing]
264 Case.Other e ->
250 Case.Other e ->
265 do e' <- expression e
251 do e' <- expression e
266− return [ ReturnStmt () (Just e') ]
252+ return [ ret e' ]
267 Case.Seq ms -> concat <$> mapM (match span) (dropEnd [] ms)
253 Case.Seq ms -> concat <$> mapM (match span) (dropEnd [] ms)
269 dropEnd acc [] = acc
255 dropEnd acc [] = acc
@@ -272,6 +258,7 @@ match span mtch =
272 Case.Other _ -> acc ++ [m]
258 Case.Other _ -> acc ++ [m]
273 _ -> dropEnd (acc ++ [m]) ms
259 _ -> dropEnd (acc ++ [m]) ms
261+clause :: SrcSpan -> String -> Case.Clause -> State Int (Bool, CaseClause ())
275clause span variable (Case.Clause value vars mtch) =
262clause span variable (Case.Clause value vars mtch) =
276 (,) isChar . CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
263 (,) isChar . CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
@@ -286,8 +273,13 @@ clause span variable (Case.Clause value vars mtch) =
286 [] -> name
273 [] -> name
287 is -> drop (last is + 1) name
274 is -> drop (last is + 1) name
276+flattenLets :: [Def] -> LExpr -> ([Def], LExpr)
277+flattenLets defs lexpr@(L _ expr) =
279+ Let ds body -> flattenLets (defs ++ ds) body
290−generate :: MetadataModule () () -> String
282+generate :: MetadataModule -> String
291generate unsafeModule =
283generate unsafeModule =
292 show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
284 show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
293 [ assign ("Elm" : names modul ++ ["make"]) (function ["_elm"] programStmts) ]
285 [ assign ("Elm" : names modul ++ ["make"]) (function ["_elm"] programStmts) ]
@@ -295,17 +287,16 @@ generate unsafeModule =
295 modul = MakeSafe.metadataModule unsafeModule
287 modul = MakeSafe.metadataModule unsafeModule
296 thisModule = dotSep ("_elm" : names modul ++ ["values"])
288 thisModule = dotSep ("_elm" : names modul ++ ["values"])
297 programStmts =
289 programStmts =
298− concat [ setup (Just "_elm") (names modul ++ ["values"])
291+ [ setup (Just "_elm") (names modul ++ ["values"])
299− , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
292+ , [ IfSingleStmt () thisModule (ret thisModule) ]
300− , [ internalImports (List.intercalate "." (names modul)) ]
293+ , [ internalImports (List.intercalate "." (names modul)) ]
301− , concatMap jsImport (imports modul)
294+ , concatMap jsImport . Set.toList . Set.fromList . map fst $ imports modul
302− , concatMap importEvent (foreignImports modul)
303− , [ assign ["_op"] (ObjectLit () []) ]
295+ , [ assign ["_op"] (ObjectLit () []) ]
304− , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
296+ , concat $ evalState (mapM definition . fst . flattenLets [] $ program modul) 0
305− , map exportEvent $ foreignExports modul
306− , [ jsExports ]
297+ , [ jsExports ]
307− , [ ReturnStmt () (Just thisModule) ]
298+ , [ ret thisModule ]
310 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
301 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
@@ -318,7 +309,7 @@ generate unsafeModule =
318 _ -> ExprStmt () $
309 _ -> ExprStmt () $
319 AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
310 AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
321− jsImport (modul,_) = setup Nothing path ++ [ include ]
312+ jsImport modul = setup Nothing path ++ [ include ]
323 path = split modul
314 path = split modul
324 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
315 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
@@ -330,32 +321,7 @@ generate unsafeModule =
330 Nothing -> tail . init $ List.inits path
321 Nothing -> tail . init $ List.inits path
331 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
322 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
333− addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
324+binop :: SrcSpan -> String -> LExpr -> LExpr -> State Int (Expression ())
335− importEvent (js,base,elm,_) =
336− [ VarDeclStmt () [ varDecl elm $ obj "Signal.constant" <| evalState (expression base) 0 ]
338− obj "document.addEventListener" `call`
341− [ ExprStmt () $ obj "_elm.notify" `call` [dotSep [elm,"id"], obj "_e.value"] ]
345− exportEvent (js,elm,_) =
350− [ VarDeclStmt () [varDecl "_e" $ obj "document.createEvent" <| string "Event"]
352− obj "_e.initEvent" `call` [ addId js, BoolLit () True, BoolLit () True ]
353− , ExprStmt () $ AssignExpr () OpAssign (LDot () (ref "_e") "value") (ref "_v")
354− , ExprStmt () $ obj "document.dispatchEvent" <| ref "_e"
355− , ReturnStmt () (Just $ ref "_v")
359binop span op e1 e2 =
325binop span op e1 e2 =
360 case op of
326 case op of
361 "Basics.." ->
327 "Basics.." ->
@@ -382,9 +348,6 @@ binop span op e1 e2 =
382 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
348 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
383 _ -> es ++ [e]
349 _ -> es ++ [e]
388 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
351 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
389 | otherwise = dotSep parts
352 | otherwise = dotSep parts
@@ -408,8 +371,8 @@ binop span op e1 e2 =
408 specialOps = concat
371 specialOps = concat
409 [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
372 [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
410 , specialOp "|>" $ flip (<|)
373 , specialOp "|>" $ flip (<|)
411− , specialOp "==" $ \a b -> obj "_N.eq" `call` [a,b]
374+ , specialOp "==" $ \a b -> obj "_U.eq" `call` [a,b]
412− , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_N.eq" `call` [a,b])
375+ , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_U.eq" `call` [a,b])
413 , specialOp "<" $ cmp OpLT 0
376 , specialOp "<" $ cmp OpLT 0
414 , specialOp ">" $ cmp OpGT 0
377 , specialOp ">" $ cmp OpGT 0
415 , specialOp "<=" $ cmp OpLT 1
378 , specialOp "<=" $ cmp OpLT 1
@@ -417,4 +380,4 @@ binop span op e1 e2 =
417 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
380 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
420− cmp op n a b = InfixExpr () op (obj "_N.cmp" `call` [a,b]) (IntLit () n)
383+ cmp op n a b = InfixExpr () op (obj "_U.cmp" `call` [a,b]) (IntLit () n)