@@ -1,26 +1,13 @@
1module Generate.JavaScript (generate) where
1module Generate.JavaScript (generate) where
3−import Control.Applicative ((<$>),(<*>))
4−import Control.Arrow (first, second, (***))
5import Control.Monad.State as State
3import Control.Monad.State as State
6−import qualified Data.List as List
7−import qualified Data.Map as Map
8import Language.ECMAScript3.PrettyPrint as ES
4import Language.ECMAScript3.PrettyPrint as ES
9import Language.ECMAScript3.Syntax
5import Language.ECMAScript3.Syntax
10import qualified Text.PrettyPrint.Leijen as PP
6import qualified Text.PrettyPrint.Leijen as PP
12−import qualified AST.Expression.General as Expr
13−import AST.Expression.Optimized as Opt
14−import qualified AST.Literal as L
15import qualified AST.Module as Module
8import qualified AST.Module as Module
16−import qualified AST.Module.Name as ModuleName
17−import qualified AST.Variable as Var
18−import Generate.JavaScript.Helpers as Help
9+import qualified Generate.JavaScript.Expression as JS
19−import qualified Generate.JavaScript.BuiltIn as BuiltIn
20−import qualified Generate.JavaScript.Literal as Literal
21−import qualified Generate.JavaScript.Port as Port
22import qualified Generate.JavaScript.Variable as Var
10import qualified Generate.JavaScript.Variable as Var
23−import qualified Optimize.Patterns.DecisionTree as DT
26generate :: Module.Optimized -> String
13generate :: Module.Optimized -> String
@@ -33,515 +20,6 @@ generate module_ =
33 Var.define "_op" (ObjectLit () [])
20 Var.define "_op" (ObjectLit () [])
36− State.evalState (mapM generateDef definitions) 0
23+ State.evalState (mapM JS.generateDef definitions) 0
38− PP.displayS (PP.renderPretty 0.4 120 (ES.prettyPrint (setup:stmts))) ""
25+ PP.displayS (PP.renderPretty 0.4 160 (ES.prettyPrint (setup:stmts))) ""
44− = JsExpr (Expression ())
45− | JsBlock [Statement ()]
48−jsExpr :: Expression () -> State Int Code
53−jsBlock :: [Statement ()] -> State Int Code
58−isBlock :: Code -> Bool
65−toStatementList :: Code -> [Statement ()]
66−toStatementList code =
74−toStatement :: Code -> Statement ()
85−toExpr :: Code -> Expression ()
92− function [] stmts `call` []
97−generateDef :: Opt.Def -> State Int (Statement ())
99− do (home, name, jsBody) <-
101− Opt.TailDef (Opt.Facts home _) name argNames body ->
102− (,,) home name <$> generateTailFunction name argNames body
104− Opt.Def (Opt.Facts home _) name body ->
105− (,,) home name <$> generateJsExpr body
107− return (Var.define name jsBody)
112−generateJsExpr :: Opt.Expr -> State Int (Expression ())
113−generateJsExpr optExpr =
114− toExpr <$> generateCode optExpr
117−generateCode :: Opt.Expr -> State Int Code
121− jsExpr $ Var.canonical var
124− jsExpr (Literal.literal lit)
127− do lo' <- generateJsExpr lo
128− hi' <- generateJsExpr hi
129− jsExpr $ BuiltIn.range lo' hi'
131− Access record field ->
132− do record' <- generateJsExpr record
133− jsExpr $ DotRef () record' (var (Var.safe field))
135− Update record fields ->
137− fieldToJs (field, value) =
138− do jsValue <- generateJsExpr value
139− return (Var.safe field, jsValue)
141− do jsRecord <- generateJsExpr record
142− jsFields <- mapM fieldToJs fields
143− jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
147− forM fields $ \(field, e) ->
148− (,) (Var.safe field) <$> generateJsExpr e
151− List.foldl' combine Map.empty fields'
153− jsExpr $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
155− combine record (field, value) =
156− Map.insertWith (++) field [value] record
159− ObjectLit () . map (prop *** ArrayLit ()) $
160− Map.toList (Map.filter (not . null) (Map.map tail fs))
163− map (first prop) (Map.toList (Map.map head fs))
165− Binop op leftExpr rightExpr ->
166− binop op leftExpr rightExpr
168− Function args body ->
169− generateFunction args body
174− aN = "A" ++ show arity
176− do jsFunc <- generateJsExpr func
177− jsArgs <- mapM generateJsExpr args
179− if 2 <= arity && arity <= 9 then
180− ref aN `call` (jsFunc:jsArgs)
182− foldl1 (<|) (jsFunc:jsArgs)
184− TailCall name argNames args ->
186− reassign name tempName =
187− ExprStmt () (AssignExpr () OpAssign (LVar () name) (ref tempName))
189− do args' <- mapM generateJsExpr args
190− tempNames <- mapM (\_ -> Var.fresh) args
192− VarDeclStmt () (zipWith varDecl tempNames args')
193− : zipWith reassign argNames tempNames
194− ++ [ContinueStmt () (Just (Id () name))]
197− do stmts <- mapM generateDef defs
198− code <- generateCode body
199− jsBlock (stmts ++ toStatementList code)
201− If branches finally ->
202− generateIf branches finally
204− Case root decisionTree branches ->
205− JsBlock <$> generateCase root decisionTree branches
207− ExplicitList elements ->
208− do jsElements <- mapM generateJsExpr elements
209− jsExpr $ BuiltIn.list jsElements
212− do jsMembers <- mapM generateJsExpr members
213− jsExpr $ ObjectLit () (ctor : fields jsMembers)
215− ctor = (prop "ctor", string tag)
217− zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
219− DataAccess dataExpr index ->
220− do jsDataExpr <- generateJsExpr dataExpr
221− jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
223− GLShader _uid src _tipe ->
224− jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
228− Expr.In name portType ->
229− jsExpr (Port.inbound name portType)
231− Expr.Out name expr portType ->
232− do expr' <- generateJsExpr expr
233− jsExpr (Port.outbound name expr' portType)
235− Expr.Task name expr portType ->
236− do expr' <- generateJsExpr expr
237− jsExpr (Port.task name expr' portType)
239− Crash region maybeCaseCrashValue ->
240− jsExpr $ BuiltIn.crash region maybeCaseCrashValue
245−generateFunction :: [String] -> Opt.Expr -> State Int Code
246−generateFunction args body =
247− do code <- generateCode body
248− jsExpr (generateFunctionWithArity args code)
251−generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
252−generateTailFunction name args body =
253− do code <- generateCode body
254− return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
257− (WhileStmt () (BoolLit () True) (toStatement code))
260−generateFunctionWithArity :: [String] -> Code -> Expression ()
261−generateFunctionWithArity rawArgs code =
263− args = map Var.safe rawArgs
266− if 2 <= arity && arity <= 9 then
268− fN = "F" ++ show arity
270− ref fN <| function args (toStatementList code)
273− (lastArg:otherArgs) = reverse args
274− innerBody = function [lastArg] (toStatementList code)
276− foldl (\body arg -> function [arg] [ret body]) innerBody otherArgs
281−generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
282−generateIf givenBranches givenFinally =
284− (branches, finally) =
285− crushIfs givenBranches givenFinally
287− convertBranch (condition, expr) =
288− (,) <$> generateJsExpr condition <*> generateCode expr
290− ifExpression (condition, branch) otherwise =
291− CondExpr () condition branch otherwise
293− ifStatement (condition, branch) otherwise =
294− IfStmt () condition branch otherwise
296− do jsBranches <- mapM convertBranch branches
297− jsFinally <- generateCode finally
299− if any isBlock (jsFinally : map snd jsBranches)
301− jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
303− jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
307− :: [(Opt.Expr, Opt.Expr)]
309− -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
310−crushIfs branches finally =
311− crushIfsHelp [] branches finally
315− :: [(Opt.Expr, Opt.Expr)]
316− -> [(Opt.Expr, Opt.Expr)]
318− -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
319−crushIfsHelp visitedBranches unvisitedBranches finally =
320− case unvisitedBranches of
323− If subBranches subFinally ->
324− crushIfsHelp visitedBranches subBranches subFinally
327− (reverse visitedBranches, finally)
329− (Literal (L.Boolean True), branch) : _ ->
330− crushIfsHelp visitedBranches [] branch
332− visiting : unvisited ->
333− crushIfsHelp (visiting : visitedBranches) unvisited finally
340− -> DT.DecisionTree Opt.Jump
341− -> [(Int, Opt.Branch)]
342− -> State Int [Statement ()]
343−generateCase root decisionTree jumpBranches =
344− do decider <- generateDecisionTree root decisionTree
345− foldM (goto root) decider jumpBranches
348−goto :: String -> [Statement ()] -> (Int, Opt.Branch) -> State Int [Statement ()]
349−goto root decider (target, branch) =
353− (targetLabel root target)
354− (DoWhileStmt () (BlockStmt () decider) (BoolLit () False))
356− do stmts <- generateBranch root branch
357− return (deciderStmt : stmts)
360−targetLabel :: String -> Int -> Id ()
361−targetLabel root target =
362− Id () (root ++ "_" ++ show target)
365−generateDecisionTree :: String -> DT.DecisionTree Opt.Jump -> State Int [Statement ()]
366−generateDecisionTree root decisionTree =
367− case decisionTree of
368− DT.Match (Opt.Inline branch) ->
369− generateBranch root branch
371− DT.Match (Opt.Jump target) ->
372− return [ BreakStmt () (Just (targetLabel root target)) ]
374− DT.Decision testPath [(test, subTree)] (Just fallback) ->
376− (tests, deepestSubTree) =
377− collapseTests [(testPath, test)] fallback subTree
379− makeTest (path, test) =
380− do testExpr <- pathToTestableExpr root path test
381− return (InfixExpr () OpStrictEq testExpr (testToExpr test))
383− do testExprs <- mapM makeTest tests
384− let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
385− thenBranch <- generateDecisionTree root deepestSubTree
386− elseBranch <- generateDecisionTree root fallback
387− return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
389− DT.Decision testPath edges fallback ->
390− do testExpr <- pathToTestableExpr root testPath (fst (head edges))
391− caseClauses <- mapM (edgeToCaseClause root) edges
392− caseDefault <- fallbackToDefault root fallback
393− return [ SwitchStmt () testExpr (caseClauses ++ caseDefault) ]
397− :: [(DT.Path, DT.Test)]
398− -> DT.DecisionTree Opt.Jump
399− -> DT.DecisionTree Opt.Jump
400− -> ([(DT.Path, DT.Test)], DT.DecisionTree Opt.Jump)
401−collapseTests tests outerFallback decisionTree =
402− case decisionTree of
403− DT.Decision testPath [(test, subTree)] (Just fallback)
404− | fallback == outerFallback ->
405− collapseTests ((testPath, test) : tests) outerFallback subTree
408− (tests, decisionTree)
411−edgeToCaseClause :: String -> (DT.Test, DT.DecisionTree Opt.Jump) -> State Int (CaseClause ())
412−edgeToCaseClause root (test, subTree) =
413− CaseClause () (testToExpr test) <$> generateDecisionTree root subTree
416−pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
417−pathToTestableExpr root path exampleTest =
418− do accessExpr <- generateJsExpr (pathToExpr root path)
421− return (DotRef () accessExpr (Id () "ctor"))
427−testToExpr :: DT.Test -> Expression ()
430− DT.Constructor (Var.Canonical _ tag) ->
433− DT.Literal (L.Chr char) ->
440−fallbackToDefault :: String -> Maybe (DT.DecisionTree Opt.Jump) -> State Int [CaseClause ()]
441−fallbackToDefault root fallback =
447− do stmts <- generateDecisionTree root subTree
448− return [ CaseDefault () stmts ]
451−generateBranch :: String -> Opt.Branch -> State Int [Statement ()]
452−generateBranch root (Opt.Branch substitutions expr) =
453− do substs <- mapM (loadPath root) substitutions
455− if null substs then [] else [ VarDeclStmt () substs ]
456− code <- generateCode expr
457− return (substStmts ++ toStatementList code)
460−loadPath :: String -> (String, DT.Path) -> State Int (VarDecl ())
461−loadPath root (name, path) =
462− do jsAccessExpr <- generateJsExpr (pathToExpr root path)
463− return $ varDecl (Var.safe name) jsAccessExpr
466−pathToExpr :: String -> DT.Path -> Opt.Expr
467−pathToExpr root fullPath =
468− go (Opt.Var (Var.local root)) fullPath
472− DT.Position index subpath ->
473− go (Opt.DataAccess expr index) subpath
475− DT.Field field subpath ->
476− go (Opt.Access expr field) subpath
492−binop func left right =
493− do jsLeft <- generateJsExpr left
494− jsRight <- generateJsExpr right
495− jsExpr (makeExpr func jsLeft jsRight)
498−-- BINARY OPERATOR HELPERS
500−makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
501−makeExpr qualifiedOp@(Var.Canonical home op) =
503− simpleMake left right =
504− ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
506− if home == Var.Module (ModuleName.inCore ["Basics"]) then
507− Map.findWithDefault simpleMake op basicOps
512−basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
514− Map.fromList (infixOps ++ specialOps)
517−infixOps :: [(String, Expression () -> Expression () -> Expression ())]
521− (str, InfixExpr () op)
527− , infixOp "&&" OpLAnd
528− , infixOp "||" OpLOr
532−specialOps :: [(String, Expression () -> Expression () -> Expression ())]
534− [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
535− , (,) "==" $ \a b -> BuiltIn.eq a b
536− , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
537− , (,) "<" $ cmp OpLT 0
538− , (,) ">" $ cmp OpGT 0
539− , (,) "<=" $ cmp OpLT 1
540− , (,) ">=" $ cmp OpGT (-1)
541− , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
545−cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
547− InfixExpr () op (BuiltIn.compare a b) (IntLit () n)