@@ -1,5 +1,4 @@
1−{-# OPTIONS -Wall #-}
1+{-# OPTIONS_GHC -W #-}
3module Generate.JavaScript (generate) where
2module Generate.JavaScript (generate) where
5import Control.Arrow (first,(***))
4import Control.Arrow (first,(***))
@@ -13,11 +12,10 @@ import qualified Generate.Cases as Case
13import qualified Generate.Markdown as MD
12import qualified Generate.Markdown as MD
14import qualified SourceSyntax.Helpers as Help
13import qualified SourceSyntax.Helpers as Help
15import SourceSyntax.Literal
14import SourceSyntax.Literal
16−import SourceSyntax.Pattern
15+import SourceSyntax.Pattern as Pattern
17import SourceSyntax.Location
16import SourceSyntax.Location
18import SourceSyntax.Expression
17import SourceSyntax.Expression
19import SourceSyntax.Module
18import SourceSyntax.Module
20−import qualified Transform.SortDefinitions as SD
21import Language.ECMAScript3.Syntax
19import Language.ECMAScript3.Syntax
22import Language.ECMAScript3.PrettyPrint
20import Language.ECMAScript3.PrettyPrint
23import qualified Transform.SafeNames as MakeSafe
21import qualified Transform.SafeNames as MakeSafe
@@ -27,8 +25,8 @@ split = go []
28 go vars str =
26 go vars str =
29 case break (=='.') str of
27 case break (=='.') str of
30− (x,'.':rest) | Help.isOp x -> vars ++ [x ++ '.' : rest]
28+ (x,_:rest) | Help.isOp x -> vars ++ [x ++ '.' : rest]
31− | otherwise -> go (vars ++ [x]) rest
29+ | otherwise -> go (vars ++ [x]) rest
32 (x,[]) -> vars ++ [x]
30 (x,[]) -> vars ++ [x]
34var name = Id () name
32var name = Id () name
@@ -40,7 +38,11 @@ function args stmts = FuncExpr () Nothing (map var args) stmts
40call = CallExpr ()
38call = CallExpr ()
41string = StringLit ()
39string = StringLit ()
43−dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
43+ x:xs -> foldl (DotRef ()) (ref x) (map var xs)
44+ [] -> error "dotSep must be called on a non-empty list of variables"
44obj = dotSep . split
46obj = dotSep . split
46varDecl :: String -> Expression () -> VarDecl ()
48varDecl :: String -> Expression () -> VarDecl ()
@@ -52,24 +54,24 @@ include alias moduleName =
53internalImports name =
55internalImports name =
54 VarDeclStmt ()
56 VarDeclStmt ()
55− [ varDecl "N" (obj "Elm.Native")
57+ [ varDecl "_N" (obj "Elm.Native")
56− , include "_N" "N.Utils"
58+ , include "_U" "_N.Utils"
57− , include "_L" "N.List"
59+ , include "_L" "_N.List"
58− , include "_E" "N.Error"
60+ , include "_E" "_N.Error"
59− , include "_J" "N.JavaScript"
61+ , include "_J" "_N.JavaScript"
60 , varDecl "$moduleName" (string name)
62 , varDecl "$moduleName" (string name)
63literal :: Literal -> Expression ()
65literal :: Literal -> Expression ()
64literal lit =
66literal lit =
65 case lit of
67 case lit of
66− Chr c -> obj "_N.chr" <| string [c]
68+ Chr c -> obj "_U.chr" <| string [c]
67 Str s -> string s
69 Str s -> string s
68 IntNum n -> IntLit () n
70 IntNum n -> IntLit () n
69 FloatNum n -> NumLit () n
71 FloatNum n -> NumLit () n
70 Boolean b -> BoolLit () b
72 Boolean b -> BoolLit () b
72−expression :: LExpr () () -> State Int (Expression ())
74+expression :: LExpr -> State Int (Expression ())
73expression (L span expr) =
75expression (L span expr) =
74 case expr of
76 case expr of
75 Var x -> return $ ref x
77 Var x -> return $ ref x
@@ -86,19 +88,19 @@ expression (L span expr) =
87 Remove e x ->
89 Remove e x ->
88 do e' <- expression e
90 do e' <- expression e
89− return $ obj "_N.remove" `call` [string x, e']
91+ return $ obj "_U.remove" `call` [string x, e']
91 Insert e x v ->
93 Insert e x v ->
92 do v' <- expression v
94 do v' <- expression v
93 e' <- expression e
95 e' <- expression e
94− return $ obj "_N.insert" `call` [string x, v', e']
96+ return $ obj "_U.insert" `call` [string x, v', e']
96 Modify e fs ->
98 Modify e fs ->
97 do e' <- expression e
99 do e' <- expression e
98 fs' <- forM fs $ \(f,v) -> do
100 fs' <- forM fs $ \(f,v) -> do
99 v' <- expression v
101 v' <- expression v
100 return $ ArrayLit () [string f, v']
102 return $ ArrayLit () [string f, v']
101− return $ obj "_N.replace" `call` [ArrayLit () fs', e']
103+ return $ obj "_U.replace" `call` [ArrayLit () fs', e']
103 Record fields ->
105 Record fields ->
104 do fields' <- forM fields $ \(f,e) -> do
106 do fields' <- forM fields $ \(f,e) -> do
@@ -150,7 +152,7 @@ expression (L span expr) =
150 _ -> (func, args)
152 _ -> (func, args)
152 Let defs e ->
154 Let defs e ->
153− do let (defs',e') = SD.flattenLets defs e
155+ do let (defs',e') = flattenLets defs e
154 stmts <- concat <$> mapM definition defs'
156 stmts <- concat <$> mapM definition defs'
155 exp <- expression e'
157 exp <- expression e'
156 return $ function [] (stmts ++ [ ReturnStmt () (Just exp) ]) `call` []
158 return $ function [] (stmts ++ [ ReturnStmt () (Just exp) ]) `call` []
@@ -194,60 +196,62 @@ expression (L span expr) =
194 pad = "<div style=\"height:0;width:0;\"> </div>"
196 pad = "<div style=\"height:0;width:0;\"> </div>"
195 md = pad ++ MD.toHtml doc ++ pad
197 md = pad ++ MD.toHtml doc ++ pad
197− GLShader uid src ->
199+ GLShader _ src ->
198 return . literal $ Str src
200 return . literal $ Str src
202+ PortIn name _ _ handler ->
203+ do handler' <- expression handler
204+ return $ obj "Native.Ports.portIn" `call` [ string name, handler' ]
206+ PortOut name _ signal ->
207+ do signal' <- expression signal
208+ return $ obj "Native.Ports.portOut" `call` [ string name, signal' ]
210+definition :: Def -> State Int [Statement ()]
211+definition (Definition pattern expr@(L span _) _) = do
212+ expr' <- expression expr
213+ let assign x = varDecl x expr'
217+ let op = LBracket () (ref "_op") (string x) in
218+ return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
220+ return [ VarDeclStmt () [ assign x ] ]
223+ let setField f = varDecl f (dotSep ["$",f]) in
224+ return [ VarDeclStmt () (assign "$" : map setField fields) ]
226+ PData name patterns | vars /= Nothing ->
227+ return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
229+ vars = getVars patterns
232+ PVar x : rest -> (x:) `fmap` getVars rest
236+ decl x n = varDecl x (dotSep ["$","_" ++ show n])
238+ | Help.isTuple name = assign "$" : vars
239+ | otherwise = assign "$raw" : safeAssign : vars
241+ safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
242+ if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
243+ exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
246+ do defs' <- concat <$> mapM toDef vars
247+ return (VarDeclStmt () [assign "$"] : defs')
249+ vars = Set.toList $ Pattern.boundVars pattern
250+ mkVar = L span . Var
251+ toDef y = let expr = L span $ Case (mkVar "$") [(pattern, mkVar y)]
252+ in definition $ Definition (PVar y) expr Nothing
201−definition :: Def () () -> State Int [Statement ()]
204− TypeAnnotation _ _ -> return []
206− Def pattern expr@(L span _) -> do
207− expr' <- expression expr
208− let assign x = varDecl x expr'
212− let op = LBracket () (ref "_op") (string x) in
213− return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
215− return [ VarDeclStmt () [ assign x ] ]
218− let setField f = varDecl f (dotSep ["$",f]) in
219− return [ VarDeclStmt () (assign "$" : map setField fields) ]
221− PData name patterns | vars /= Nothing ->
223− Just vs -> return [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
225− vars = getVars patterns
228− PVar x : rest -> (x:) `fmap` getVars rest
232− decl x n = varDecl x (dotSep ["$","_" ++ show n])
234− | Help.isTuple name = assign "$" : vars
235− | otherwise = assign "$raw" : safeAssign : vars
237− safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
238− if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
239− exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
242− do defs' <- concat <$> mapM toDef vars
243− return (VarDeclStmt () [assign "$"] : defs')
245− vars = Set.toList $ SD.boundVars pattern
246− mkVar = L span . Var
247− toDef y = definition $
248− Def (PVar y) (L span $ Case (mkVar "$") [(pattern, mkVar y)])
250−match :: (Show a) => a -> Case.Match () () -> State Int [Statement ()]
254+match :: (Show a) => a -> Case.Match -> State Int [Statement ()]
251match span mtch =
255match span mtch =
252 case mtch of
256 case mtch of
253 Case.Match name clauses mtch' ->
257 Case.Match name clauses mtch' ->
@@ -292,8 +296,12 @@ clause span variable (Case.Clause value vars mtch) =
292 [] -> name
296 [] -> name
293 is -> drop (last is + 1) name
297 is -> drop (last is + 1) name
299+flattenLets defs lexpr@(L _ expr) =
301+ Let ds body -> flattenLets (defs ++ ds) body
296−generate :: MetadataModule () () -> String
304+generate :: MetadataModule -> String
297generate unsafeModule =
305generate unsafeModule =
298 show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
306 show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
299 [ assign ("Elm" : names modul ++ ["make"]) (function ["_elm"] programStmts) ]
307 [ assign ("Elm" : names modul ++ ["make"]) (function ["_elm"] programStmts) ]
@@ -301,17 +309,16 @@ generate unsafeModule =
301 modul = MakeSafe.metadataModule unsafeModule
309 modul = MakeSafe.metadataModule unsafeModule
302 thisModule = dotSep ("_elm" : names modul ++ ["values"])
310 thisModule = dotSep ("_elm" : names modul ++ ["values"])
303 programStmts =
311 programStmts =
304− concat [ setup (Just "_elm") (names modul ++ ["values"])
313+ [ setup (Just "_elm") (names modul ++ ["values"])
305− , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
314+ , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
306− , [ internalImports (List.intercalate "." (names modul)) ]
315+ , [ internalImports (List.intercalate "." (names modul)) ]
307− , concatMap jsImport (imports modul)
316+ , concatMap jsImport . Set.toList . Set.fromList . map fst $ imports modul
308− , concatMap importEvent (foreignImports modul)
309− , [ assign ["_op"] (ObjectLit () []) ]
317+ , [ assign ["_op"] (ObjectLit () []) ]
310− , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
318+ , concat $ evalState (mapM definition . fst . flattenLets [] $ program modul) 0
311− , map exportEvent $ foreignExports modul
312− , [ jsExports ]
319+ , [ jsExports ]
313− , [ ReturnStmt () (Just thisModule) ]
320+ , [ ReturnStmt () (Just thisModule) ]
316 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
323 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
@@ -324,7 +331,7 @@ generate unsafeModule =
324 _ -> ExprStmt () $
331 _ -> ExprStmt () $
325 AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
332 AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
327− jsImport (modul,_) = setup Nothing path ++ [ include ]
334+ jsImport modul = setup Nothing path ++ [ include ]
329 path = split modul
336 path = split modul
330 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
337 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
@@ -336,32 +343,6 @@ generate unsafeModule =
336 Nothing -> tail . init $ List.inits path
343 Nothing -> tail . init $ List.inits path
337 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
344 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
339− addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
341− importEvent (js,base,elm,_) =
342− [ VarDeclStmt () [ varDecl elm $ obj "Signal.constant" <| evalState (expression base) 0 ]
344− obj "document.addEventListener" `call`
347− [ ExprStmt () $ obj "_elm.notify" `call` [dotSep [elm,"id"], obj "_e.value"] ]
351− exportEvent (js,elm,_) =
356− [ VarDeclStmt () [varDecl "_e" $ obj "document.createEvent" <| string "Event"]
358− obj "_e.initEvent" `call` [ addId js, BoolLit () True, BoolLit () True ]
359− , ExprStmt () $ AssignExpr () OpAssign (LDot () (ref "_e") "value") (ref "_v")
360− , ExprStmt () $ obj "document.dispatchEvent" <| ref "_e"
361− , ReturnStmt () (Just $ ref "_v")
365binop span op e1 e2 =
346binop span op e1 e2 =
366 case op of
347 case op of
367 "Basics.." ->
348 "Basics.." ->
@@ -388,9 +369,6 @@ binop span op e1 e2 =
388 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
369 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
389 _ -> es ++ [e]
370 _ -> es ++ [e]
394 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
372 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
395 | otherwise = dotSep parts
373 | otherwise = dotSep parts
@@ -414,8 +392,8 @@ binop span op e1 e2 =
414 specialOps = concat
392 specialOps = concat
415 [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
393 [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
416 , specialOp "|>" $ flip (<|)
394 , specialOp "|>" $ flip (<|)
417− , specialOp "==" $ \a b -> obj "_N.eq" `call` [a,b]
395+ , specialOp "==" $ \a b -> obj "_U.eq" `call` [a,b]
418− , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_N.eq" `call` [a,b])
396+ , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_U.eq" `call` [a,b])
419 , specialOp "<" $ cmp OpLT 0
397 , specialOp "<" $ cmp OpLT 0
420 , specialOp ">" $ cmp OpGT 0
398 , specialOp ">" $ cmp OpGT 0
421 , specialOp "<=" $ cmp OpLT 1
399 , specialOp "<=" $ cmp OpLT 1
@@ -423,4 +401,4 @@ binop span op e1 e2 =
423 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
401 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
426− cmp op n a b = InfixExpr () op (obj "_N.cmp" `call` [a,b]) (IntLit () n)
404+ cmp op n a b = InfixExpr () op (obj "_U.cmp" `call` [a,b]) (IntLit () n)