@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -W #-}
12module Generate.JavaScript (generate) where
23
34import Control.Arrow (first,(***))
@@ -7,67 +8,49 @@ import qualified Data.List as List
78import qualified Data.Map as Map
89import qualified Data.Set as Set
910
11+import Generate.JavaScript.Helpers
1012import qualified Generate.Cases as Case
13+import qualified Generate.JavaScript.Ports as Port
1114import qualified Generate.Markdown as MD
1215import qualified SourceSyntax.Helpers as Help
1316import SourceSyntax.Literal
14−import SourceSyntax.Pattern
17+import SourceSyntax.Pattern as Pattern
1518import SourceSyntax.Location
1619import SourceSyntax.Expression
1720import SourceSyntax.Module
18−import qualified Transform.SortDefinitions as SD
1921import Language.ECMAScript3.Syntax
2022import Language.ECMAScript3.PrettyPrint
2123import qualified Transform.SafeNames as MakeSafe
2224
23−split :: String -> [String]
24−split = go []
25− where
26− go vars str =
27− case break (=='.') str of
28− (x,'.':rest) | Help.isOp x -> vars ++ [x ++ '.' : rest]
29− | otherwise -> go (vars ++ [x]) rest
30− (x,[]) -> vars ++ [x]
31−
32−var name = Id () 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 ()
40−
41−dotSep (x:xs) = foldl (DotRef ()) (ref x) (map var xs)
42−obj = dotSep . split
43−
4425varDecl :: String -> Expression () -> VarDecl ()
4526varDecl x expr =
4627 VarDecl () (var x) (Just expr)
4728
29+include :: String -> String -> VarDecl ()
4830include alias moduleName =
4931 varDecl alias (obj (moduleName ++ ".make") <| ref "_elm")
5032
33+internalImports :: String -> Statement ()
5134internalImports name =
5235 VarDeclStmt ()
53− [ varDecl "N" (obj "Elm.Native")
54− , include "_N" "N.Utils"
55− , include "_L" "N.List"
56− , include "_E" "N.Error"
57− , include "_J" "N.JavaScript"
36+ [ varDecl "_N" (obj "Elm.Native")
37+ , include "_U" "_N.Utils"
38+ , include "_L" "_N.List"
39+ , include "_E" "_N.Error"
40+ , include "_J" "_N.JavaScript"
5841 , varDecl "$moduleName" (string name)
5942 ]
6043
6144literal :: Literal -> Expression ()
6245literal lit =
6346 case lit of
64− Chr c -> obj "_N.chr" <| string [c]
47+ Chr c -> obj "_U.chr" <| string [c]
6548 Str s -> string s
6649 IntNum n -> IntLit () n
6750 FloatNum n -> NumLit () n
6851 Boolean b -> BoolLit () b
6952
70−expression :: LExpr () () -> State Int (Expression ())
53+expression :: LExpr -> State Int (Expression ())
7154expression (L span expr) =
7255 case expr of
7356 Var x -> return $ ref x
@@ -84,19 +67,19 @@ expression (L span expr) =
8467
8568 Remove e x ->
8669 do e' <- expression e
87− return $ obj "_N.remove" `call` [string x, e']
70+ return $ obj "_U.remove" `call` [string x, e']
8871
8972 Insert e x v ->
9073 do v' <- expression v
9174 e' <- expression e
92− return $ obj "_N.insert" `call` [string x, v', e']
75+ return $ obj "_U.insert" `call` [string x, v', e']
9376
9477 Modify e fs ->
9578 do e' <- expression e
9679 fs' <- forM fs $ \(f,v) -> do
9780 v' <- expression v
9881 return $ ArrayLit () [string f, v']
99− return $ obj "_N.replace" `call` [ArrayLit () fs', e']
82+ return $ obj "_U.replace" `call` [ArrayLit () fs', e']
10083
10184 Record fields ->
10285 do fields' <- forM fields $ \(f,e) -> do
@@ -148,10 +131,10 @@ expression (L span expr) =
148131 _ -> (func, args)
149132
150133 Let defs e ->
151− do let (defs',e') = SD.flattenLets defs e
134+ do let (defs',e') = flattenLets defs e
152135 stmts <- concat <$> mapM definition defs'
153136 exp <- expression e'
154− return $ function [] (stmts ++ [ ReturnStmt () (Just exp) ]) `call` []
137+ return $ function [] (stmts ++ [ ret exp ]) `call` []
155138
156139 MultiIf branches ->
157140 do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
@@ -192,56 +175,59 @@ expression (L span expr) =
192175 pad = "<div style=\"height:0;width:0;\"> </div>"
193176 md = pad ++ MD.toHtml doc ++ pad
194177
195−definition :: Def () () -> State Int [Statement ()]
196−definition def =
197− case def of
198− TypeAnnotation _ _ -> return []
199−
200− Def pattern expr@(L span _) -> do
201− expr' <- expression expr
202− let assign x = varDecl x expr'
203− case pattern of
204− PVar x
205− | Help.isOp x ->
206− let op = LBracket () (ref "_op") (string x) in
207− return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
208− | otherwise ->
209− return [ VarDeclStmt () [ assign x ] ]
210−
211− PRecord fields ->
212− let setField f = varDecl f (dotSep ["$",f]) in
213− return [ VarDeclStmt () (assign "$" : map setField fields) ]
214−
215− PData name patterns | vars /= Nothing ->
216− case vars of
217− Just vs -> return [ VarDeclStmt () (setup (zipWith decl vs [0..])) ]
218− where
219− vars = getVars patterns
220− getVars patterns =
221− case patterns of
222− PVar x : rest -> (x:) `fmap` getVars rest
223− [] -> Just []
224− _ -> Nothing
225−
226− decl x n = varDecl x (dotSep ["$","_" ++ show n])
227− setup vars
228− | Help.isTuple name = assign "$" : vars
229− | otherwise = assign "$raw" : safeAssign : vars
230−
231− safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
232− if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
233− exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
234−
235− _ ->
236− do defs' <- concat <$> mapM toDef vars
237− return (VarDeclStmt () [assign "$"] : defs')
238− where
239− vars = Set.toList $ SD.boundVars pattern
240− mkVar = L span . Var
241− toDef y = definition $
242− Def (PVar y) (L span $ Case (mkVar "$") [(pattern, mkVar y)])
243−
244−match :: (Show a) => a -> Case.Match () () -> State Int [Statement ()]
178+ PortIn name tipe ->
179+ return $ obj "Native.Ports.portIn" `call` [ string name, Port.incoming tipe ]
180+
181+ PortOut name tipe value ->
182+ do value' <- expression value
183+ return $ obj "Native.Ports.portOut" `call`
184+ [ string name, Port.outgoing tipe, value' ]
185+
186+definition :: Def -> State Int [Statement ()]
187+definition (Definition pattern expr@(L span _) _) = do
188+ expr' <- expression expr
189+ let assign x = varDecl x expr'
190+ case pattern of
191+ PVar x
192+ | Help.isOp x ->
193+ let op = LBracket () (ref "_op") (string x) in
194+ return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
195+ | otherwise ->
196+ return [ VarDeclStmt () [ assign x ] ]
197+
198+ PRecord fields ->
199+ let setField f = varDecl f (dotSep ["$",f]) in
200+ return [ VarDeclStmt () (assign "$" : map setField fields) ]
201+
202+ PData name patterns | vars /= Nothing ->
203+ return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
204+ where
205+ vars = getVars patterns
206+ getVars patterns =
207+ case patterns of
208+ PVar x : rest -> (x:) `fmap` getVars rest
209+ [] -> Just []
210+ _ -> Nothing
211+
212+ decl x n = varDecl x (dotSep ["$","_" ++ show n])
213+ setup vars
214+ | Help.isTuple name = assign "$" : vars
215+ | otherwise = assign "$raw" : safeAssign : vars
216+
217+ safeAssign = varDecl "$" (CondExpr () if' (obj "$raw") exception)
218+ if' = InfixExpr () OpStrictEq (obj "$raw.ctor") (string name)
219+ exception = obj "_E.Case" `call` [ref "$moduleName", string (show span)]
220+
221+ _ ->
222+ do defs' <- concat <$> mapM toDef vars
223+ return (VarDeclStmt () [assign "$"] : defs')
224+ where
225+ vars = Set.toList $ Pattern.boundVars pattern
226+ mkVar = L span . Var
227+ toDef y = let expr = L span $ Case (mkVar "$") [(pattern, mkVar y)]
228+ in definition $ Definition (PVar y) expr Nothing
229+
230+match :: SrcSpan -> Case.Match -> State Int [Statement ()]
245231match span mtch =
246232 case mtch of
247233 Case.Match name clauses mtch' ->
@@ -263,7 +249,7 @@ match span mtch =
263249 Case.Break -> return [BreakStmt () Nothing]
264250 Case.Other e ->
265251 do e' <- expression e
266− return [ ReturnStmt () (Just e') ]
252+ return [ ret e' ]
267253 Case.Seq ms -> concat <$> mapM (match span) (dropEnd [] ms)
268254 where
269255 dropEnd acc [] = acc
@@ -272,6 +258,7 @@ match span mtch =
272258 Case.Other _ -> acc ++ [m]
273259 _ -> dropEnd (acc ++ [m]) ms
274260
261+clause :: SrcSpan -> String -> Case.Clause -> State Int (Bool, CaseClause ())
275262clause span variable (Case.Clause value vars mtch) =
276263 (,) isChar . CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
277264 where
@@ -286,8 +273,13 @@ clause span variable (Case.Clause value vars mtch) =
286273 [] -> name
287274 is -> drop (last is + 1) name
288275
276+flattenLets :: [Def] -> LExpr -> ([Def], LExpr)
277+flattenLets defs lexpr@(L _ expr) =
278+ case expr of
279+ Let ds body -> flattenLets (defs ++ ds) body
280+ _ -> (defs, lexpr)
289281
290−generate :: MetadataModule () () -> String
282+generate :: MetadataModule -> String
291283generate unsafeModule =
292284 show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
293285 [ assign ("Elm" : names modul ++ ["make"]) (function ["_elm"] programStmts) ]
@@ -295,17 +287,16 @@ generate unsafeModule =
295287 modul = MakeSafe.metadataModule unsafeModule
296288 thisModule = dotSep ("_elm" : names modul ++ ["values"])
297289 programStmts =
298− concat [ setup (Just "_elm") (names modul ++ ["values"])
299− , [ IfSingleStmt () thisModule (ReturnStmt () (Just thisModule)) ]
300− , [ internalImports (List.intercalate "." (names modul)) ]
301− , concatMap jsImport (imports modul)
302− , concatMap importEvent (foreignImports modul)
303− , [ assign ["_op"] (ObjectLit () []) ]
304− , concat $ evalState (mapM definition . fst . SD.flattenLets [] $ program modul) 0
305− , map exportEvent $ foreignExports modul
306− , [ jsExports ]
307− , [ ReturnStmt () (Just thisModule) ]
308− ]
290+ concat
291+ [ setup (Just "_elm") (names modul ++ ["values"])
292+ , [ IfSingleStmt () thisModule (ret thisModule) ]
293+ , [ internalImports (List.intercalate "." (names modul)) ]
294+ , concatMap jsImport . Set.toList . Set.fromList . map fst $ imports modul
295+ , [ assign ["_op"] (ObjectLit () []) ]
296+ , concat $ evalState (mapM definition . fst . flattenLets [] $ program modul) 0
297+ , [ jsExports ]
298+ , [ ret thisModule ]
299+ ]
309300
310301 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
311302 where
@@ -318,7 +309,7 @@ generate unsafeModule =
318309 _ -> ExprStmt () $
319310 AssignExpr () OpAssign (LDot () (dotSep (init path)) (last path)) expr
320311
321− jsImport (modul,_) = setup Nothing path ++ [ include ]
312+ jsImport modul = setup Nothing path ++ [ include ]
322313 where
323314 path = split modul
324315 include = assign path $ dotSep ("Elm" : path ++ ["make"]) <| ref "_elm"
@@ -330,32 +321,7 @@ generate unsafeModule =
330321 Nothing -> tail . init $ List.inits path
331322 Just nmspc -> drop 2 . init . List.inits $ nmspc : path
332323
333− addId js = InfixExpr () OpAdd (string (js++"_")) (obj "_elm.id")
334−
335− importEvent (js,base,elm,_) =
336− [ VarDeclStmt () [ varDecl elm $ obj "Signal.constant" <| evalState (expression base) 0 ]
337− , ExprStmt () $
338− obj "document.addEventListener" `call`
339− [ addId js
340− , function ["_e"]
341− [ ExprStmt () $ obj "_elm.notify" `call` [dotSep [elm,"id"], obj "_e.value"] ]
342− ]
343− ]
344−
345− exportEvent (js,elm,_) =
346− ExprStmt () $
347− ref "A2" `call`
348− [ obj "Signal.lift"
349− , function ["_v"]
350− [ VarDeclStmt () [varDecl "_e" $ obj "document.createEvent" <| string "Event"]
351− , ExprStmt () $
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")
356− ]
357− , ref elm ]
358−
324+binop :: SrcSpan -> String -> LExpr -> LExpr -> State Int (Expression ())
359325binop span op e1 e2 =
360326 case op of
361327 "Basics.." ->
@@ -382,9 +348,6 @@ binop span op e1 e2 =
382348 L _ (Binop op e1 e2) | op == "Basics.." -> collect (es ++ [e1]) e2
383349 _ -> es ++ [e]
384350
385− js1 = expression e1
386− js2 = expression e2
387−
388351 func | Help.isOp operator = BracketRef () (dotSep (init parts ++ ["_op"])) (string operator)
389352 | otherwise = dotSep parts
390353 where
@@ -408,8 +371,8 @@ binop span op e1 e2 =
408371 specialOps = concat
409372 [ specialOp "^" $ \a b -> obj "Math.pow" `call` [a,b]
410373 , specialOp "|>" $ flip (<|)
411− , specialOp "==" $ \a b -> obj "_N.eq" `call` [a,b]
412− , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_N.eq" `call` [a,b])
374+ , specialOp "==" $ \a b -> obj "_U.eq" `call` [a,b]
375+ , specialOp "/=" $ \a b -> PrefixExpr () PrefixLNot (obj "_U.eq" `call` [a,b])
413376 , specialOp "<" $ cmp OpLT 0
414377 , specialOp ">" $ cmp OpGT 0
415378 , specialOp "<=" $ cmp OpLT 1
@@ -417,4 +380,4 @@ binop span op e1 e2 =
417380 , specialOp "div" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
418381 ]
419382
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)