1module Generate.JavaScript.Expression (generateDef) where
3import Control.Arrow (second)
4import Control.Monad.State (State, foldM)
5import qualified Data.List as List
6import qualified Data.Map as Map
7import Language.ECMAScript3.Syntax
9import AST.Expression.Optimized as Opt
10import qualified AST.Literal as L
11import qualified AST.Module.Name as ModuleName
12import qualified AST.Variable as Var
13import Generate.JavaScript.Helpers as Help
14import qualified Generate.JavaScript.BuiltIn as BuiltIn
15import qualified Generate.JavaScript.Literal as Literal
16import qualified Generate.JavaScript.Variable as Var
17import qualified Optimize.DecisionTree as DT
23 = JsExpr (Expression ())
24 | JsBlock [Statement ()]
27jsExpr :: Expression () -> State Int Code
32jsBlock :: [Statement ()] -> State Int Code
37isBlock :: Code -> Bool
44toStatementList :: Code -> [Statement ()]
48 [ ReturnStmt () (Just expr) ]
54toStatement :: Code -> Statement ()
58 ReturnStmt () (Just expr)
67toExpr :: Code -> Expression ()
74 function [] stmts `call` []
79generateDef :: Opt.Def -> State Int (Statement ())
81 do (home, name, jsBody) <-
83 Opt.TailDef (Opt.Facts home _) name argNames body ->
84 (,,) home name <$> generateTailFunction name argNames body
86 Opt.Def (Opt.Facts home _) name body ->
87 (,,) home name <$> generateJsExpr body
89 return (Var.define name jsBody)
94generateJsExpr :: Opt.Expr -> State Int (Expression ())
95generateJsExpr optExpr =
96 toExpr <$> generateCode optExpr
99generateCode :: Opt.Expr -> State Int Code
103 jsExpr $ Var.canonical var
106 jsExpr (Literal.literal lit)
109 do lo' <- generateJsExpr lo
110 hi' <- generateJsExpr hi
111 jsExpr $ BuiltIn.range lo' hi'
113 Access record field ->
114 do record' <- generateJsExpr record
115 jsExpr $ DotRef () record' (var (Var.safe field))
117 Update record fields ->
119 fieldToJs (field, value) =
120 do jsValue <- generateJsExpr value
121 return (Var.safe field, jsValue)
123 do jsRecord <- generateJsExpr record
124 jsFields <- mapM fieldToJs fields
125 jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
129 toField (field, value) =
130 do jsValue <- generateJsExpr value
131 return (prop (Var.safe field), jsValue)
133 do jsFields <- mapM toField fields
134 jsExpr $ ObjectLit () jsFields
136 Binop op leftExpr rightExpr ->
137 binop op leftExpr rightExpr
139 Function args body ->
140 generateFunction args body
145 aN = "A" ++ show arity
147 do jsFunc <- generateJsExpr func
148 jsArgs <- mapM generateJsExpr args
150 if 2 <= arity && arity <= 9 then
151 ref aN `call` (jsFunc:jsArgs)
153 foldl1 (<|) (jsFunc:jsArgs)
155 TailCall name argNames args ->
157 reassign name tempName =
158 ExprStmt () (AssignExpr () OpAssign (LVar () (Var.safe name)) (ref tempName))
160 do args' <- mapM generateJsExpr args
161 tempNames <- mapM (\_ -> Var.fresh) args
163 VarDeclStmt () (zipWith varDecl tempNames args')
164 : zipWith reassign argNames tempNames
165 ++ [ContinueStmt () (Just (Id () (Var.safe name)))]
168 do stmts <- mapM generateDef defs
169 code <- generateCode body
170 jsBlock (stmts ++ toStatementList code)
172 If branches finally ->
173 generateIf branches finally
175 Case exprName decider jumps ->
176 JsBlock <$> generateCase exprName decider jumps
178 ExplicitList elements ->
179 do jsElements <- mapM generateJsExpr elements
180 jsExpr $ BuiltIn.list jsElements
183 do jsMembers <- mapM generateJsExpr members
184 jsExpr $ ObjectLit () (ctor : fields jsMembers)
186 ctor = (prop "ctor", StringLit () tag)
188 zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
190 DataAccess dataExpr index ->
191 do jsDataExpr <- generateJsExpr dataExpr
192 jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
194 GLShader _uid src _tipe ->
195 jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
197 Crash home region maybeBranchProblem ->
198 do maybeOptBranchProblem <- traverse generateJsExpr maybeBranchProblem
199 jsExpr $ BuiltIn.crash home region maybeOptBranchProblem
204generateFunction :: [String] -> Opt.Expr -> State Int Code
205generateFunction args body =
206 do code <- generateCode body
207 jsExpr (generateFunctionWithArity args code)
210generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
211generateTailFunction name args body =
212 do code <- generateCode body
213 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
215 (Id () (Var.safe name))
216 (WhileStmt () (BoolLit () True) (toStatement code))
219generateFunctionWithArity :: [String] -> Code -> Expression ()
220generateFunctionWithArity rawArgs code =
222 args = map Var.safe rawArgs
225 if 2 <= arity && arity <= 9 then
227 fN = "F" ++ show arity
229 ref fN <| function args (toStatementList code)
232 (lastArg:otherArgs) = reverse args
233 innerBody = function [lastArg] (toStatementList code)
235 foldl (\body arg -> function [arg] [ReturnStmt () (Just body)]) innerBody otherArgs
240generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
241generateIf givenBranches givenFinally =
243 (branches, finally) =
244 crushIfs givenBranches givenFinally
246 convertBranch (condition, expr) =
247 (,) <$> generateJsExpr condition <*> generateCode expr
249 ifExpression (condition, branch) otherwise =
250 CondExpr () condition branch otherwise
252 ifStatement (condition, branch) otherwise =
253 IfStmt () condition branch otherwise
255 do jsBranches <- mapM convertBranch branches
256 jsFinally <- generateCode finally
258 if any isBlock (jsFinally : map snd jsBranches)
260 jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
262 jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
266 :: [(Opt.Expr, Opt.Expr)]
268 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
269crushIfs branches finally =
270 crushIfsHelp [] branches finally
274 :: [(Opt.Expr, Opt.Expr)]
275 -> [(Opt.Expr, Opt.Expr)]
277 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
278crushIfsHelp visitedBranches unvisitedBranches finally =
279 case unvisitedBranches of
282 If subBranches subFinally ->
283 crushIfsHelp visitedBranches subBranches subFinally
286 (reverse visitedBranches, finally)
288 (Literal (L.Boolean True), branch) : _ ->
289 crushIfsHelp visitedBranches [] branch
291 visiting : unvisited ->
292 crushIfsHelp (visiting : visitedBranches) unvisited finally
299 -> Opt.Decider Opt.Choice
301 -> State Int [Statement ()]
302generateCase exprName decider jumps =
303 do labelRoot <- Var.fresh
304 decider <- generateDecider exprName labelRoot decider
305 foldM (goto labelRoot) decider jumps
310goto :: String -> [Statement ()] -> (Int, Opt.Expr) -> State Int [Statement ()]
311goto labelRoot deciderStmts (target, branch) =
315 (toLabel labelRoot target)
316 (DoWhileStmt () (BlockStmt () deciderStmts) (BoolLit () False))
318 do code <- generateCode branch
319 return (labeledDeciderStmt : toStatementList code)
322toLabel :: String -> Int -> Id ()
324 Id () (root ++ "_" ++ show target)
327-- turn deciders into ifs and switches
332 -> Opt.Decider Opt.Choice
333 -> State Int [Statement ()]
334generateDecider exprName labelRoot decisionTree =
336 Opt.Leaf (Opt.Inline branch) ->
337 toStatementList <$> generateCode branch
339 Opt.Leaf (Opt.Jump target) ->
340 return [ BreakStmt () (Just (toLabel labelRoot target)) ]
342 Opt.Chain testChain success failure ->
344 makeTest (path, test) =
345 do testExpr <- pathToTestableExpr exprName path test
346 return (InfixExpr () OpStrictEq testExpr (testToExpr test))
348 do testExprs <- mapM makeTest testChain
349 let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
350 thenBranch <- generateDecider exprName labelRoot success
351 elseBranch <- generateDecider exprName labelRoot failure
352 return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
354 Opt.FanOut path edges fallback ->
355 do testExpr <- pathToTestableExpr exprName path (fst (head edges))
356 caseClauses <- mapM (edgeToCaseClause exprName labelRoot) edges
357 caseDefault <- CaseDefault () <$> generateDecider exprName labelRoot fallback
358 return [ SwitchStmt () testExpr (caseClauses ++ [caseDefault]) ]
364 -> (DT.Test, Opt.Decider Opt.Choice)
365 -> State Int (CaseClause ())
366edgeToCaseClause exprName labelRoot (test, subTree) =
367 CaseClause () (testToExpr test) <$> generateDecider exprName labelRoot subTree
370testToExpr :: DT.Test -> Expression ()
373 DT.Constructor (Var.Canonical _ tag) ->
376 DT.Literal (L.Chr char) ->
385pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
386pathToTestableExpr root path exampleTest =
387 do accessExpr <- generateJsExpr (pathToExpr root path)
390 return (DotRef () accessExpr (Id () "ctor"))
392 DT.Literal (L.Chr _) ->
393 return (DotRef () accessExpr (Id () "valueOf") `call` [])
399pathToExpr :: String -> DT.Path -> Opt.Expr
400pathToExpr root fullPath =
401 go (Opt.Var (Var.local root)) fullPath
405 DT.Position index subpath ->
406 go (Opt.DataAccess expr index) subpath
408 DT.Field field subpath ->
409 go (Opt.Access expr field) subpath
425binop func left right =
426 do jsLeft <- generateJsExpr left
427 jsRight <- generateJsExpr right
428 jsExpr (makeExpr func jsLeft jsRight)
431-- BINARY OPERATOR HELPERS
433makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
434makeExpr qualifiedOp@(Var.Canonical home op) =
436 simpleMake left right =
437 ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
439 if home == Var.Module (ModuleName.inCore ["Basics"]) then
440 Map.findWithDefault simpleMake op basicOps
445basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
447 Map.fromList (infixOps ++ specialOps)
450infixOps :: [(String, Expression () -> Expression () -> Expression ())]
454 (str, InfixExpr () op)
460 , infixOp "&&" OpLAnd
465specialOps :: [(String, Expression () -> Expression () -> Expression ())]
467 [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
468 , (,) "==" $ \a b -> BuiltIn.eq a b
469 , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
470 , (,) "<" $ cmp OpLT 0
471 , (,) ">" $ cmp OpGT 0
472 , (,) "<=" $ cmp OpLT 1
473 , (,) ">=" $ cmp OpGT (-1)
474 , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
478cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
480 InfixExpr () op (BuiltIn.cmp a b) (IntLit () n)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list