@@ -1,17 +1,18 @@
1module Generate.JavaScript (generate) where
1module Generate.JavaScript (generate) where
3import Control.Applicative ((<$>),(<*>))
3import Control.Applicative ((<$>),(<*>))
4−import Control.Arrow (first,(***))
4+import Control.Arrow (first, second, (***))
5import Control.Monad.State
5import Control.Monad.State
6import qualified Data.List as List
6import qualified Data.List as List
7import qualified Data.Map as Map
7import qualified Data.Map as Map
8+import qualified Data.Maybe as Maybe
8import qualified Data.Set as Set
9import qualified Data.Set as Set
9import Language.ECMAScript3.PrettyPrint
10import Language.ECMAScript3.PrettyPrint
10import Language.ECMAScript3.Syntax
11import Language.ECMAScript3.Syntax
12import AST.Module
13import AST.Module
13−import AST.Expression.General
14+import AST.Expression.General as Expr
14−import qualified AST.Expression.Canonical as Canonical
15+import qualified AST.Expression.Optimized as Opt
15import qualified AST.Helpers as Help
16import qualified AST.Helpers as Help
16import AST.Literal
17import AST.Literal
17import qualified AST.Module as Module
18import qualified AST.Module as Module
@@ -19,19 +20,22 @@ import qualified AST.Pattern as P
19import qualified AST.Variable as Var
20import qualified AST.Variable as Var
20import Elm.Utils ((|>))
21import Elm.Utils ((|>))
21import Generate.JavaScript.Helpers as Help
22import Generate.JavaScript.Helpers as Help
22−import qualified Generate.Cases as Case
23+import qualified Generate.JavaScript.Crash as Crash
23import qualified Generate.JavaScript.Port as Port
24import qualified Generate.JavaScript.Port as Port
24import qualified Generate.JavaScript.Variable as Var
25import qualified Generate.JavaScript.Variable as Var
26+import qualified Optimize.Cases as Case
25import qualified Reporting.Annotation as A
27import qualified Reporting.Annotation as A
26−import qualified Reporting.Region as R
28+import qualified Reporting.Crash as Crash
29internalImports :: Module.Name -> [VarDecl ()]
33internalImports :: Module.Name -> [VarDecl ()]
30internalImports name =
34internalImports name =
31 [ varDecl "_N" (obj ["Elm","Native"])
35 [ varDecl "_N" (obj ["Elm","Native"])
32 , include "_U" "Utils"
36 , include "_U" "Utils"
33 , include "_L" "List"
37 , include "_L" "List"
34− , varDecl Help.localModuleName (string (Module.nameToString name))
38+ , varDecl Crash.localModuleName (string (Module.nameToString name))
37 include :: String -> String -> VarDecl ()
41 include :: String -> String -> VarDecl ()
@@ -59,51 +63,131 @@ literal lit =
59 Boolean b -> BoolLit () b
63 Boolean b -> BoolLit () b
69+ = JsExpr (Expression ())
70+ | JsBlock [Statement ()]
73+jsExpr :: Expression () -> State Int Code
78+jsBlock :: [Statement ()] -> State Int Code
83+isBlock :: Code -> Bool
90+toStatementList :: Code -> [Statement ()]
91+toStatementList code =
99+toStatement :: Code -> Statement ()
110+toExpr :: Code -> Expression ()
116+ function [] stmts `call` []
121+type TailCallContext =
122+ Maybe (String, [String], Label)
62−expression :: Canonical.Expr -> State Int (Expression ())
131+toJsExpr :: Opt.Expr -> State Int (Expression ())
63−expression (A.A region expr) =
132+toJsExpr =
133+ exprToJsExpr Nothing
136+toCode :: Opt.Expr -> State Int Code
141+exprToJsExpr :: TailCallContext -> Opt.Expr -> State Int (Expression ())
142+exprToJsExpr tcc canonicalExpr =
143+ toExpr <$> exprToCode tcc canonicalExpr
146+exprToCode :: TailCallContext -> Opt.Expr -> State Int Code
147+exprToCode tcc annotatedExpr@(A.A _ expr) =
64 case expr of
148 case expr of
65 Var var ->
149 Var var ->
66− return $ Var.canonical var
150+ jsExpr $ Var.canonical var
68 Literal lit ->
152 Literal lit ->
69− return $ literal lit
153+ jsExpr $ literal lit
71 Range lo hi ->
155 Range lo hi ->
72− do lo' <- expression lo
156+ do lo' <- toJsExpr lo
73− hi' <- expression hi
157+ hi' <- toJsExpr hi
74− return $ _List "range" `call` [lo',hi']
158+ jsExpr $ _List "range" `call` [lo',hi']
76− Access e field ->
160+ Access record field ->
77− do e' <- expression e
161+ do record' <- toJsExpr record
78− return $ DotRef () e' (var (Var.varName field))
162+ jsExpr $ DotRef () record' (var (Var.varName field))
80− Remove e field ->
164+ Remove record field ->
81− do e' <- expression e
165+ do record' <- toJsExpr record
82− return $ _Utils "remove" `call` [ string (Var.varName field), e' ]
166+ jsExpr $ _Utils "remove" `call` [ string (Var.varName field), record' ]
84− Insert e field value ->
168+ Insert record field value ->
85− do value' <- expression value
169+ do value' <- toJsExpr value
86− e' <- expression e
170+ record' <- toJsExpr record
87− return $ _Utils "insert" `call` [ string (Var.varName field), value', e' ]
171+ jsExpr $ _Utils "insert" `call` [ string (Var.varName field), value', record' ]
89− Modify e fields ->
173+ Modify record fields ->
90− do e' <- expression e
174+ do record' <- toJsExpr record
91 fields' <-
175 fields' <-
92 forM fields $ \(field, value) ->
176 forM fields $ \(field, value) ->
93− do value' <- expression value
177+ do value' <- toJsExpr value
94 return $ ArrayLit () [ string (Var.varName field), value' ]
178 return $ ArrayLit () [ string (Var.varName field), value' ]
96− return $ _Utils "replace" `call` [ArrayLit () fields', e']
180+ jsExpr $ _Utils "replace" `call` [ArrayLit () fields', record']
98 Record fields ->
182 Record fields ->
99 do fields' <-
183 do fields' <-
100 forM fields $ \(field, e) ->
184 forM fields $ \(field, e) ->
101− (,) (Var.varName field) <$> expression e
185+ (,) (Var.varName field) <$> toJsExpr e
103 let fieldMap =
187 let fieldMap =
104 List.foldl' combine Map.empty fields'
188 List.foldl' combine Map.empty fields'
106− return $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
190+ jsExpr $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
108 combine record (field, value) =
192 combine record (field, value) =
109 Map.insertWith (++) field [value] record
193 Map.insertWith (++) field [value] record
@@ -115,201 +199,370 @@ expression (A.A region expr) =
115 visible fs =
199 visible fs =
116 map (first prop) (Map.toList (Map.map head fs))
200 map (first prop) (Map.toList (Map.map head fs))
118− Binop op e1 e2 ->
202+ Binop op leftExpr rightExpr ->
119− binop region op e1 e2
203+ binop op leftExpr rightExpr
121− Lambda pattern rawBody@(A.A ann _) ->
205+ Lambda _ _ ->
122− do (args, body) <- foldM depattern ([], innerBody) (reverse patterns)
206+ generateFunction (Expr.collectLambdas annotatedExpr)
123− body' <- expression body
207+
125− case length args < 2 || length args > 9 of
126− True -> foldr (==>) body' (map (:[]) args)
127− False -> ref ("F" ++ show (length args)) <| (args ==> body')
129− depattern (args, body) pattern =
132− return (args ++ [ Var.varName x ], body)
135− do arg <- Case.newVar
138− , A.A ann (Case (A.A ann (localVar arg)) [(pattern, body)])
141− (patterns, innerBody) =
142− collect [pattern] rawBody
144− collect patterns lexpr@(A.A _ expr) =
146− Lambda p e -> collect (p:patterns) e
147− _ -> (patterns, lexpr)
149− App e1 e2 ->
208+ App _ _ ->
150− do func' <- expression func
209+ generateApplication tcc annotatedExpr
151− args' <- mapM expression args
210+
154− [arg] -> func' <| arg
155− _ | length args' <= 9 -> ref aN `call` (func':args')
156− | otherwise -> foldl1 (<|) (func':args')
158− aN = "A" ++ show (length args)
159− (func, args) = getArgs e1 [e2]
162− (A.A _ (App f arg)) -> getArgs f (arg : args)
165− Let defs e ->
211+ Let defs body ->
166− do let (defs',e') = flattenLets defs e
212+ generateLet tcc defs body
167− stmts <- concat <$> mapM definition defs'
213+
168− exp <- expression e'
169− return $ function [] (stmts ++ [ ret exp ]) `call` []
171− MultiIf branches ->
214+ MultiIf branches finally ->
172− do branches' <- forM branches $ \(b,e) -> (,) <$> expression b <*> expression e
174− case last branches of
175− (A.A _ (Var (Var.Canonical (Var.Module ["Basics"]) "otherwise")), _) ->
177− (A.A _ (Literal (Boolean True)), _) ->
180− ifs branches' (throw "badIf" region)
182− safeIfs branches = ifs (init branches) (snd (last branches))
183− ifs branches finally = foldr iff finally branches
215+ generateIf tcc branches finally
184− iff (if', then') else' = CondExpr () if' then' else'
216+
185−
217+ Case expr branches ->
186− Case e cases ->
218+ generateCase tcc expr branches
187− do (tempVar,initialMatch) <- Case.toMatch cases
219+
188− (revisedMatch, stmt) <-
190− A.A _ (Var (Var.Canonical Var.Local x)) ->
191− return (Case.matchSubst [(tempVar, Var.varName x)] initialMatch, [])
193− do e' <- expression e
194− return (initialMatch, [VarDeclStmt () [varDecl tempVar e']])
195− match' <- match region revisedMatch
196− return (function [] (stmt ++ match') `call` [])
198− ExplicitList es ->
220+ ExplicitList elements ->
199− do es' <- mapM expression es
221+ do jsElements <- mapM toJsExpr elements
200− return $ _List "fromArray" <| ArrayLit () es'
222+ jsExpr $ _List "fromArray" <| ArrayLit () jsElements
202− Data name es ->
224+ Data tag members ->
203− do es' <- mapM expression es
225+ do jsMembers <- mapM toJsExpr members
204− return $ ObjectLit () (ctor : fields es')
226+ jsExpr $ ObjectLit () (ctor : fields jsMembers)
206− ctor = (prop "ctor", string name)
228+ ctor = (prop "ctor", string tag)
208 zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
230 zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
210 GLShader _uid src _tipe ->
232 GLShader _uid src _tipe ->
211− return $ ObjectLit () [(PropString () "src", literal (Str src))]
233+ jsExpr $ ObjectLit () [(PropString () "src", literal (Str src))]
213 Port impl ->
235 Port impl ->
214 case impl of
236 case impl of
215 In name portType ->
237 In name portType ->
216− return (Port.inbound name portType)
238+ jsExpr (Port.inbound name portType)
218 Out name expr portType ->
240 Out name expr portType ->
219− do expr' <- expression expr
241+ do expr' <- toJsExpr expr
220− return (Port.outbound name expr' portType)
242+ jsExpr (Port.outbound name expr' portType)
222 Task name expr portType ->
244 Task name expr portType ->
223− do expr' <- expression expr
245+ do expr' <- toJsExpr expr
224− return (Port.task name expr' portType)
246+ jsExpr (Port.task name expr' portType)
226−
248+ Crash details ->
227−definition :: Canonical.Def -> State Int [Statement ()]
249+ jsExpr $ Crash.crash details
228−definition (Canonical.Definition annPattern expr@(A.A region _) _) =
250+
229− do expr' <- expression expr
251+
230− let assign x = varDecl x expr'
252+-- FUNCTIONS
231− let (A.A patternRegion pattern) = annPattern
253+
232− case pattern of
254+generateFunction :: ([P.Optimized], Opt.Expr) -> State Int Code
233− P.Var x
255+generateFunction (args, initialBody) =
234− | Help.isOp x ->
256+ do (argVars, patternDefs) <- destructuredArgs args
235− let op = LBracket () (ref "_op") (string x) in
257+ code <- generateLet Nothing patternDefs initialBody
258+ jsExpr (generateFunctionWithArity argVars code)
261+generateTailFunction :: String -> ([P.Optimized], Opt.Expr) -> State Int (Expression ())
262+generateTailFunction name (args, initialBody) =
263+ do (argVars, patternDefs) <- destructuredArgs args
264+ label <- Id () <$> Case.newVar
265+ code <- generateLet (Just (name, argVars, label)) patternDefs initialBody
267+ JsBlock [ LabelledStmt () label (WhileStmt () (BoolLit () True) (toStatement code)) ]
268+ return (generateFunctionWithArity argVars whileLoop)
271+generateFunctionWithArity :: [String] -> Code -> Expression ()
272+generateFunctionWithArity args code =
276+ if 2 <= arity && arity <= 9 then
278+ fN = "F" ++ show arity
280+ ref fN <| function args (toStatementList code)
283+ (lastArg:otherArgs) = reverse args
284+ innerBody = function [lastArg] (toStatementList code)
286+ foldl (\body arg -> function [arg] [ret body]) innerBody otherArgs
289+destructuredArgs :: [P.Optimized] -> State Int ([String], [Opt.Def])
290+destructuredArgs args =
291+ do (argVars, maybePatternDefs) <- unzip <$> mapM destructPattern args
292+ return (argVars, Maybe.catMaybes maybePatternDefs)
295+destructPattern :: P.Optimized -> State Int (String, Maybe Opt.Def)
296+destructPattern pattern@(A.A ann pat) =
299+ return (Var.varName x, Nothing)
302+ do arg <- Case.newVar
305+ , Just $ Opt.Definition Opt.dummyFacts pattern (A.A ann (localVar arg))
311+generateApplication :: TailCallContext -> Opt.Expr -> State Int Code
312+generateApplication tcc expr =
315+ Expr.collectApps expr
320+ reassign name tempName =
236− return [ ExprStmt () $ AssignExpr () OpAssign op expr' ]
321+ ExprStmt () (AssignExpr () OpAssign (LVar () name) (ref tempName))
238− | otherwise ->
323+ aN =
239− return [ VarDeclStmt () [ assign (Var.varName x) ] ]
324+ "A" ++ show arity
241− P.Record fields ->
326+ case isTailCall tcc func arity of
242− let setField f = varDecl f (obj ["$",f]) in
327+ Just (argNames, label) ->
243− return [ VarDeclStmt () (assign "$" : map setField fields) ]
328+ do args' <- mapM toJsExpr args
244−
329+ tempNames <- mapM (\_ -> Case.newVar) args
245− P.Data (Var.Canonical _ name) patterns | vars /= Nothing ->
330+ jsBlock $
246− return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
331+ VarDeclStmt () (zipWith varDecl tempNames args')
247− where
332+ : zipWith reassign argNames tempNames
248− vars = getVars patterns
333+ ++ [ContinueStmt () (Just label)]
251− A.A _ (P.Var x) : rest ->
252− (Var.varName x :) `fmap` getVars rest
258− decl x n = varDecl x (obj ["$","_" ++ show n])
260− | Help.isTuple name = assign "$" : vars
261− | otherwise = assign "_raw" : safeAssign : vars
263− safeAssign = varDecl "$" (CondExpr () if' (ref "_raw") exception)
264− if' = InfixExpr () OpStrictEq (obj ["_raw","ctor"]) (string name)
265− exception = Help.throw "badCase" region
336+ do func' <- toJsExpr func
337+ args' <- mapM toJsExpr args
339+ if 2 <= arity && arity <= 9 then
340+ ref aN `call` (func':args')
342+ foldl1 (<|) (func':args')
345+isTailCall :: TailCallContext -> Opt.Expr -> Int -> Maybe ([String], Label)
346+isTailCall tcc (A.A _ func) arity =
348+ (Var (Var.Canonical Var.Local name), Just (tcName, tcArgs, tcLabel)) ->
349+ if name == tcName && length tcArgs == arity then
350+ Just (tcArgs, tcLabel)
365+generateLet tcc givenDefs givenBody =
366+ do let (defs, body) = flattenLets givenDefs givenBody
367+ stmts <- concat <$> mapM defToStatements defs
368+ code <- exprToCode tcc body
369+ jsBlock (stmts ++ toStatementList code)
374+generateIf :: TailCallContext -> [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
375+generateIf tcc givenBranches givenFinally =
377+ (branches, finally) =
378+ crushIfs givenBranches givenFinally
380+ convertBranch (condition, expr) =
381+ (,) <$> toJsExpr condition <*> exprToCode tcc expr
383+ ifExpression (condition, branch) otherwise =
384+ CondExpr () condition branch otherwise
386+ ifStatement (condition, branch) otherwise =
387+ IfStmt () condition branch otherwise
389+ do jsBranches <- mapM convertBranch branches
390+ jsFinally <- exprToCode tcc finally
392+ if any isBlock (jsFinally : map snd jsBranches)
394+ jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
396+ jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
400+ :: [(Opt.Expr, Opt.Expr)]
402+ -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
403+crushIfs branches finally =
404+ crushIfsHelp [] branches finally
408+ :: [(Opt.Expr, Opt.Expr)]
409+ -> [(Opt.Expr, Opt.Expr)]
411+ -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
412+crushIfsHelp visitedBranches unvisitedBranches finally =
413+ case unvisitedBranches of
416+ A.A _ (MultiIf subBranches subFinally) ->
417+ crushIfsHelp visitedBranches subBranches subFinally
420+ (reverse visitedBranches, finally)
422+ (A.A _ (Literal (Boolean True)), branch) : _ ->
423+ crushIfsHelp visitedBranches [] branch
425+ (A.A _ (Var (Var.Canonical (Var.Module ["Basics"]) "otherwise")), branch) : _ ->
426+ crushIfsHelp visitedBranches [] branch
428+ visiting : unvisited ->
429+ crushIfsHelp (visiting : visitedBranches) unvisited finally
435+defToStatements :: Opt.Def -> State Int [Statement ()]
436+defToStatements def@(Opt.Definition facts pattern expr) =
437+ case Opt.tailRecursionDetails facts of
439+ do func <- generateTailFunction name (Expr.collectLambdas expr)
440+ return [ VarDeclStmt () [ varDecl name func ] ]
443+ defToStatementsHelp facts pattern =<< toJsExpr expr
450+ -> State Int [Statement ()]
451+defToStatementsHelp facts annPattern@(A.A _ pattern) jsExpr =
460+ op = LBracket () (ref "_op") (string x)
462+ return [ ExprStmt () $ AssignExpr () OpAssign op jsExpr ]
464+ return [ VarDeclStmt () [ define (Var.varName x) ] ]
469+ varDecl name (obj ["$",name])
471+ return [ VarDeclStmt () (define "$" : map setField fields) ]
473+ P.Data (Var.Canonical _ name) patterns | vars /= Nothing ->
474+ return [ VarDeclStmt () (setup (zipWith decl (maybe [] id vars) [0..])) ]
476+ vars = getVars patterns
479+ A.A _ (P.Var x) : rest ->
480+ (Var.varName x :) `fmap` getVars rest
486+ decl x n = varDecl x (obj ["$","_" ++ show n])
488+ | Help.isTuple name = define "$" : vars
489+ | otherwise = define "_raw" : safeAssign : vars
491+ safeAssign = varDecl "$" (CondExpr () if' (ref "_raw") exception)
492+ if' = InfixExpr () OpStrictEq (obj ["_raw","ctor"]) (string name)
493+ exception = Crash.crash (Crash.IncompletePatternMatch (error "TODO"))
268− do defs' <- concat <$> mapM toDef vars
496+ do defs' <- concat <$> mapM toDef vars
269− return (VarDeclStmt () [assign "_"] : defs')
497+ return (VarDeclStmt () [define "_"] : defs')
271− vars = P.boundVarList annPattern
499+ vars = P.boundVarList annPattern
272− mkVar = A.A region . localVar
500+ mkVar = A.A () . localVar
273− toDef y =
501+ toDef y =
274− let expr = A.A region $ Case (mkVar "_") [(annPattern, mkVar y)]
502+ let expr = A.A () $ Case (mkVar "_") [(annPattern, mkVar y)]
275− pat = A.A patternRegion (P.Var y)
503+ pat = A.A () (P.Var y)
277− definition (Canonical.Definition pat expr Nothing)
505+ defToStatements (Opt.Definition facts pat expr)
510+generateCase :: TailCallContext -> Opt.Expr -> [(P.Optimized, Opt.Expr)] -> State Int Code
511+generateCase tcc expr branches =
512+ do (tempVar, initialMatch) <-
513+ Case.toMatch branches
515+ (revisedMatch, stmt) <-
517+ A.A _ (Var (Var.Canonical Var.Local x)) ->
518+ return (Case.matchSubst [(tempVar, Var.varName x)] initialMatch, [])
520+ do expr' <- toJsExpr expr
521+ return (initialMatch, [VarDeclStmt () [varDecl tempVar expr']])
523+ match' <- match tcc revisedMatch
525+ jsBlock (stmt ++ match')
280−match :: R.Region -> Case.Match -> State Int [Statement ()]
528+match :: TailCallContext -> Case.Match -> State Int [Statement ()]
281−match region mtch =
529+match tcc mtch =
282 case mtch of
530 case mtch of
283 Case.Match name clauses mtch' ->
531 Case.Match name clauses mtch' ->
284− do (isChars, clauses') <- unzip <$> mapM (clause region name) clauses
532+ do (isChars, clauses') <- unzip <$> mapM (clause tcc name) clauses
285− mtch'' <- match region mtch'
533+ mtch'' <- match tcc mtch'
286 return (SwitchStmt () (format isChars (access name)) clauses' : mtch'')
534 return (SwitchStmt () (format isChars (access name)) clauses' : mtch'')
288 isLiteral p =
536 isLiteral p =
289 case p of
537 case p of
290− Case.Clause (Right _) _ _ -> True
538+ Case.Clause (Right _) _ _ ->
291− _ -> False
541+ False
293− access name
543+ access name =
294− | any isLiteral clauses = obj [name]
544+ if any isLiteral clauses then
295− | otherwise = obj (Help.splitDots name ++ ["ctor"])
547+ obj (Help.splitDots name ++ ["ctor"])
297− format isChars e
549+ format isChars expr =
298− | or isChars = InfixExpr () OpAdd e (string "")
551+ InfixExpr () OpAdd expr (string "")
299− | otherwise = e
552+ else
301 Case.Fail ->
555 Case.Fail ->
302− return [ ExprStmt () (Help.throw "badCase" region) ]
556+ return [ ExprStmt () (Crash.crash (Crash.IncompletePatternMatch (error "TODO"))) ]
304 Case.Break ->
558 Case.Break ->
305 return [BreakStmt () Nothing]
559 return [BreakStmt () Nothing]
307− Case.Other e ->
561+ Case.Other expr ->
308− do e' <- expression e
562+ toStatementList <$> exprToCode tcc expr
311 Case.Seq ms ->
564 Case.Seq ms ->
312− concat <$> mapM (match region) (dropEnd [] ms)
565+ concat <$> mapM (match tcc) (dropEnd [] ms)
314 dropEnd acc [] = acc
567 dropEnd acc [] = acc
315 dropEnd acc (m:ms) =
568 dropEnd acc (m:ms) =
@@ -318,9 +571,10 @@ match region mtch =
318 _ -> dropEnd (acc ++ [m]) ms
571 _ -> dropEnd (acc ++ [m]) ms
321−clause :: R.Region -> String -> Case.Clause -> State Int (Bool, CaseClause ())
574+clause :: TailCallContext -> String -> Case.Clause -> State Int (Bool, CaseClause ())
322−clause region variable (Case.Clause value vars mtch) =
575+clause tcc variable (Case.Clause value vars mtch) =
323− (,) isChar . CaseClause () pattern <$> match region (Case.matchSubst (zip vars vars') mtch)
576+ do statemens <- match tcc (Case.matchSubst (zip vars vars') mtch)
577+ return ((,) isChar (CaseClause () pattern statemens))
326 map (\n -> variable ++ "._" ++ show n) [0..]
580 map (\n -> variable ++ "._" ++ show n) [0..]
@@ -337,14 +591,14 @@ clause region variable (Case.Clause value vars mtch) =
337 string name
591 string name
340−flattenLets :: [Canonical.Def] -> Canonical.Expr -> ([Canonical.Def], Canonical.Expr)
594+flattenLets :: [Opt.Def] -> Opt.Expr -> ([Opt.Def], Opt.Expr)
341flattenLets defs lexpr@(A.A _ expr) =
595flattenLets defs lexpr@(A.A _ expr) =
342 case expr of
596 case expr of
343 Let ds body -> flattenLets (defs ++ ds) body
597 Let ds body -> flattenLets (defs ++ ds) body
344 _ -> (defs, lexpr)
598 _ -> (defs, lexpr)
347−generate :: CanonicalModule -> String
601+generate :: Module.Optimized -> String
348generate modul =
602generate modul =
349 show . prettyPrint $ setup "Elm" (names ++ ["make"]) ++
603 show . prettyPrint $ setup "Elm" (names ++ ["make"]) ++
350 [ assign ("Elm" : names ++ ["make"]) (function [localRuntime] programStmts) ]
604 [ assign ("Elm" : names ++ ["make"]) (function [localRuntime] programStmts) ]
@@ -393,7 +647,7 @@ generate modul =
393 Module.program (Module.body modul)
647 Module.program (Module.body modul)
394 |> flattenLets []
648 |> flattenLets []
396− |> mapM definition
650+ |> mapM defToStatements
398 setup namespace path =
652 setup namespace path =
399 map create paths
653 map create paths
@@ -430,63 +684,104 @@ generate modul =
430 AssignExpr () OpAssign (LDot () (obj (init path)) (last path)) expr
684 AssignExpr () OpAssign (LDot () (obj (init path)) (last path)) expr
435− -> Var.Canonical
690+ :: Var.Canonical
436− -> Canonical.Expr
691+ -> Opt.Expr
437− -> Canonical.Expr
692+ -> Opt.Expr
438− -> State Int (Expression ())
693+ -> State Int Code
439−binop region func@(Var.Canonical home op) e1 e2 =
694+binop func left right
441− (Var.Module ["Basics"], ">>") ->
442− do es <- mapM expression (collectLeftAssoc [e2] e1)
443− return $ ["$"] ==> List.foldl' (\e f -> f <| e) (ref "$") es
445− (Var.Module ["Basics"], "<<") ->
446− do es <- mapM expression (e1 : collectRightAssoc [] e2)
447− return $ ["$"] ==> foldr (<|) (ref "$") es
449− (Var.Module ["Basics"], "<|") ->
450− do e2' <- expression e2
451− es <- mapM expression (collectRightAssoc [] e1)
452− return $ foldr (<|) e2' es
454− (Var.BuiltIn, "::") ->
695+ | func == Var.Canonical Var.BuiltIn "::" =
455− expression (A.A region (Data "::" [e1,e2]))
696+ toCode (A.A () (Data "::" [left,right]))
457− (Var.Module ["Basics"], _) ->
458− do e1' <- expression e1
459− e2' <- expression e2
460− case Map.lookup op basicOps of
465− return (ref "A2" `call` [ Var.canonical func, e1', e2' ])
467− _ ->
698+ | func == forwardCompose =
468− do e1' <- expression e1
699+ compose (collectLeftAssoc forwardCompose left right)
469− e2' <- expression e2
470− return (ref "A2" `call` [ Var.canonical func, e1', e2' ])
472− where
701+ | func == backwardCompose =
473− collectRightAssoc es e =
702+ compose (collectRightAssoc backwardCompose left right)
475− A.A _ (Binop (Var.Canonical (Var.Module ["Basics"]) "<<") e1 e2) ->
704+ | func == forwardApply =
476− collectRightAssoc (es ++ [e1]) e2
705+ pipe (collectLeftAssoc forwardApply left right)
478−
707+ | func == backwardApply =
479− collectLeftAssoc es e =
708+ pipe (collectRightAssoc backwardApply left right)
711+ do jsLeft <- toJsExpr left
712+ jsRight <- toJsExpr right
713+ jsExpr (makeExpr func jsLeft jsRight)
716+-- CONTROL FLOW OPERATOR HELPERS
718+apply :: Expression () -> Expression () -> Expression ()
723+compose :: [Opt.Expr] -> State Int Code
725+ do jsFunctions <- mapM toJsExpr functions
726+ jsExpr $ ["$"] ==> List.foldl' apply (ref "$") jsFunctions
729+pipe :: [Opt.Expr] -> State Int Code
731+ do (value:functions) <- mapM toJsExpr expressions
732+ jsExpr $ List.foldl' apply value functions
735+forwardCompose :: Var.Canonical
740+backwardCompose :: Var.Canonical
745+forwardApply :: Var.Canonical
750+backwardApply :: Var.Canonical
755+inBasics :: String -> Var.Canonical
757+ Var.Canonical (Var.Module ["Basics"]) name
760+-- BINARY OPERATOR HELPERS
762+makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
763+makeExpr qualifiedOp@(Var.Canonical home op) =
765+ simpleMake left right =
766+ ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
481− A.A _ (Binop (Var.Canonical (Var.Module ["Basics"]) ">>") e1 e2) ->
768+ if home == Var.Module ["Basics"] then
482− collectLeftAssoc (e2 : es) e1
769+ Map.findWithDefault simpleMake op basicOps
483− _ -> e : es
770+ else
774+basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
485− basicOps =
775+basicOps =
486− Map.fromList (infixOps ++ specialOps)
776+ Map.fromList (infixOps ++ specialOps)
779+infixOps :: [(String, Expression () -> Expression () -> Expression ())]
489− let infixOp str op = (str, InfixExpr () op) in
783+ (str, InfixExpr () op)
490 [ infixOp "+" OpAdd
785 [ infixOp "+" OpAdd
491 , infixOp "-" OpSub
786 , infixOp "-" OpSub
492 , infixOp "*" OpMul
787 , infixOp "*" OpMul
@@ -495,17 +790,56 @@ binop region func@(Var.Canonical home op) e1 e2 =
495 , infixOp "||" OpLOr
790 , infixOp "||" OpLOr
499− [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
500− , (,) "|>" $ flip (<|)
501− , (,) "==" $ \a b -> _Utils "eq" `call` [a,b]
502− , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (_Utils "eq" `call` [a,b])
503− , (,) "<" $ cmp OpLT 0
504− , (,) ">" $ cmp OpGT 0
505− , (,) "<=" $ cmp OpLT 1
506− , (,) ">=" $ cmp OpGT (-1)
507− , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
794+specialOps :: [(String, Expression () -> Expression () -> Expression ())]
796+ [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
797+ , (,) "|>" $ flip (<|)
798+ , (,) "==" $ \a b -> _Utils "eq" `call` [a,b]
799+ , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (_Utils "eq" `call` [a,b])
800+ , (,) "<" $ cmp OpLT 0
801+ , (,) ">" $ cmp OpGT 0
802+ , (,) "<=" $ cmp OpLT 1
803+ , (,) ">=" $ cmp OpGT (-1)
804+ , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
808+cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
510− cmp op n a b =
809+cmp op n a b =
511− InfixExpr () op (_Utils "cmp" `call` [a,b]) (IntLit () n)
810+ InfixExpr () op (_Utils "cmp" `call` [a,b]) (IntLit () n)
813+-- BINARY OPERATOR COLLECTORS
815+-- (h << g << f) becomes [f, g, h] which is the order you want for doing stuff
816+collectRightAssoc :: Var.Canonical -> Opt.Expr -> Opt.Expr -> [Opt.Expr]
817+collectRightAssoc desiredOp left right =
818+ collectRightAssocHelp desiredOp [left] right
821+collectRightAssocHelp :: Var.Canonical -> [Opt.Expr] -> Opt.Expr -> [Opt.Expr]
822+collectRightAssocHelp desiredOp exprList expr =
824+ A.A _ (Binop op left right) | op == desiredOp ->
825+ collectRightAssocHelp desiredOp (left : exprList) right
831+-- (f >> g >> h) becomes [f, g, h] which is the order you want for doing stuff
832+collectLeftAssoc :: Var.Canonical -> Opt.Expr -> Opt.Expr -> [Opt.Expr]
833+collectLeftAssoc desiredOp left right =
834+ collectLeftAssocHelp desiredOp [right] left
837+collectLeftAssocHelp :: Var.Canonical -> [Opt.Expr] -> Opt.Expr -> [Opt.Expr]
838+collectLeftAssocHelp desiredOp exprList expr =
840+ A.A _ (Binop op left right) | op == desiredOp ->
841+ collectLeftAssocHelp desiredOp (right : exprList) left