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
25 = JsExpr (Expression ())
26 | JsBlock [Statement ()]
29jsExpr :: Expression () -> State Int Code
34jsBlock :: [Statement ()] -> State Int Code
39isBlock :: Code -> Bool
46toStatementList :: Code -> [Statement ()]
50 [ ReturnStmt () (Just expr) ]
56toStatement :: Code -> Statement ()
60 ReturnStmt () (Just expr)
69toExpr :: Code -> Expression ()
76 function [] stmts `call` []
83generateDef :: Opt.Def -> State Int [Statement ()]
85 do (home, name, jsBody) <-
87 Opt.TailDef (Opt.Facts home _) name argNames body ->
88 (,,) home name <$> generateTailFunction name argNames body
90 Opt.Def (Opt.Facts home _) name body ->
91 (,,) home name <$> generateJsExpr body
93 return (Var.define home name jsBody)
100generateJsExpr :: Opt.Expr -> State Int (Expression ())
101generateJsExpr optExpr =
102 toExpr <$> generateCode optExpr
105generateCode :: Opt.Expr -> State Int Code
109 jsExpr $ Var.canonical var
112 jsExpr (Literal.literal lit)
115 do lo' <- generateJsExpr lo
116 hi' <- generateJsExpr hi
117 jsExpr $ BuiltIn.range lo' hi'
119 Access record field ->
120 do record' <- generateJsExpr record
121 jsExpr $ DotRef () record' (var (Var.safe field))
123 Update record fields ->
125 fieldToJs (field, value) =
126 do jsValue <- generateJsExpr value
127 return (Var.safe field, jsValue)
129 do jsRecord <- generateJsExpr record
130 jsFields <- mapM fieldToJs fields
131 jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
135 toField (field, value) =
136 do jsValue <- generateJsExpr value
137 return (prop (Var.safe field), jsValue)
139 do jsFields <- mapM toField fields
140 jsExpr $ ObjectLit () jsFields
142 Binop op leftExpr rightExpr ->
143 binop op leftExpr rightExpr
145 Function args body ->
146 generateFunction args body
151 aN = "A" ++ show arity
153 do jsFunc <- generateJsExpr func
154 jsArgs <- mapM generateJsExpr args
156 if 2 <= arity && arity <= 9 then
157 ref aN `call` (jsFunc:jsArgs)
159 foldl1 (<|) (jsFunc:jsArgs)
161 TailCall name argNames args ->
163 reassign name tempName =
164 ExprStmt () (AssignExpr () OpAssign (LVar () (Var.safe name)) (ref tempName))
166 do args' <- mapM generateJsExpr args
167 tempNames <- mapM (\_ -> Var.fresh) args
169 VarDeclStmt () (zipWith varDecl tempNames args')
170 : zipWith reassign argNames tempNames
171 ++ [ContinueStmt () (Just (Id () (Var.safe name)))]
174 do stmts <- mapM generateDef defs
175 code <- generateCode body
176 jsBlock (concat stmts ++ toStatementList code)
178 If branches finally ->
179 generateIf branches finally
181 Case exprName decider jumps ->
182 JsBlock <$> generateCase exprName decider jumps
184 ExplicitList elements ->
185 do jsElements <- mapM generateJsExpr elements
186 jsExpr $ BuiltIn.list jsElements
189 do jsMembers <- mapM generateJsExpr members
190 jsExpr $ ObjectLit () (ctor : fields jsMembers)
192 ctor = (prop "ctor", StringLit () tag)
194 zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
196 DataAccess dataExpr index ->
197 do jsDataExpr <- generateJsExpr dataExpr
198 jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
201 jsExpr $ BuiltIn.cmd moduleName
204 jsExpr $ BuiltIn.sub moduleName
206 GLShader _uid src _tipe ->
207 jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
209 Crash home region maybeBranchProblem ->
210 do maybeOptBranchProblem <- traverse generateJsExpr maybeBranchProblem
211 jsExpr $ BuiltIn.crash home region maybeOptBranchProblem
218generateFunction :: [String] -> Opt.Expr -> State Int Code
219generateFunction args body =
220 do code <- generateCode body
221 jsExpr (generateFunctionWithArity args code)
224generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
225generateTailFunction name args body =
226 do code <- generateCode body
227 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
229 (Id () (Var.safe name))
230 (WhileStmt () (BoolLit () True) (toStatement code))
233generateFunctionWithArity :: [String] -> Code -> Expression ()
234generateFunctionWithArity rawArgs code =
236 args = map Var.safe rawArgs
239 if 2 <= arity && arity <= 9 then
241 fN = "F" ++ show arity
243 ref fN <| function args (toStatementList code)
246 (lastArg:otherArgs) = reverse args
247 innerBody = function [lastArg] (toStatementList code)
249 foldl (\body arg -> function [arg] [ReturnStmt () (Just body)]) innerBody otherArgs
256generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
257generateIf givenBranches givenFinally =
259 (branches, finally) =
260 crushIfs givenBranches givenFinally
262 convertBranch (condition, expr) =
263 (,) <$> generateJsExpr condition <*> generateCode expr
265 ifExpression (condition, branch) otherwise =
266 CondExpr () condition branch otherwise
268 ifStatement (condition, branch) otherwise =
269 IfStmt () condition branch otherwise
271 do jsBranches <- mapM convertBranch branches
272 jsFinally <- generateCode finally
274 if any isBlock (jsFinally : map snd jsBranches)
276 jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
278 jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
282 :: [(Opt.Expr, Opt.Expr)]
284 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
285crushIfs branches finally =
286 crushIfsHelp [] branches finally
290 :: [(Opt.Expr, Opt.Expr)]
291 -> [(Opt.Expr, Opt.Expr)]
293 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
294crushIfsHelp visitedBranches unvisitedBranches finally =
295 case unvisitedBranches of
298 If subBranches subFinally ->
299 crushIfsHelp visitedBranches subBranches subFinally
302 (reverse visitedBranches, finally)
304 (Literal (L.Boolean True), branch) : _ ->
305 crushIfsHelp visitedBranches [] branch
307 visiting : unvisited ->
308 crushIfsHelp (visiting : visitedBranches) unvisited finally
317 -> Opt.Decider Opt.Choice
319 -> State Int [Statement ()]
320generateCase exprName decider jumps =
321 do labelRoot <- Var.fresh
322 decider <- generateDecider exprName labelRoot decider
323 foldM (goto labelRoot) decider jumps
330goto :: String -> [Statement ()] -> (Int, Opt.Expr) -> State Int [Statement ()]
331goto labelRoot deciderStmts (target, branch) =
335 (toLabel labelRoot target)
336 (DoWhileStmt () (BlockStmt () deciderStmts) (BoolLit () False))
338 do code <- generateCode branch
339 return (labeledDeciderStmt : toStatementList code)
342toLabel :: String -> Int -> Id ()
344 Id () (root ++ "_" ++ show target)
348-- turn deciders into ifs and switches
354 -> Opt.Decider Opt.Choice
355 -> State Int [Statement ()]
356generateDecider exprName labelRoot decisionTree =
358 Opt.Leaf (Opt.Inline branch) ->
359 toStatementList <$> generateCode branch
361 Opt.Leaf (Opt.Jump target) ->
362 return [ BreakStmt () (Just (toLabel labelRoot target)) ]
364 Opt.Chain testChain success failure ->
366 makeTest (path, test) =
367 do testExpr <- pathToTestableExpr exprName path test
368 return (InfixExpr () OpStrictEq testExpr (testToExpr test))
370 do testExprs <- mapM makeTest testChain
371 let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
372 thenBranch <- generateDecider exprName labelRoot success
373 elseBranch <- generateDecider exprName labelRoot failure
374 return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
376 Opt.FanOut path edges fallback ->
377 do testExpr <- pathToTestableExpr exprName path (fst (head edges))
378 caseClauses <- mapM (edgeToCaseClause exprName labelRoot) edges
379 caseDefault <- CaseDefault () <$> generateDecider exprName labelRoot fallback
380 return [ SwitchStmt () testExpr (caseClauses ++ [caseDefault]) ]
386 -> (DT.Test, Opt.Decider Opt.Choice)
387 -> State Int (CaseClause ())
388edgeToCaseClause exprName labelRoot (test, subTree) =
389 CaseClause () (testToExpr test) <$> generateDecider exprName labelRoot subTree
392testToExpr :: DT.Test -> Expression ()
395 DT.Constructor (Var.Canonical _ tag) ->
398 DT.Literal (L.Chr char) ->
409pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
410pathToTestableExpr root path exampleTest =
411 do accessExpr <- generateJsExpr (pathToExpr root path)
414 return (DotRef () accessExpr (Id () "ctor"))
416 DT.Literal (L.Chr _) ->
417 return (DotRef () accessExpr (Id () "valueOf") `call` [])
423pathToExpr :: String -> DT.Path -> Opt.Expr
424pathToExpr root fullPath =
425 go (Opt.Var (Var.local root)) fullPath
429 DT.Position index subpath ->
430 go (Opt.DataAccess expr index) subpath
432 DT.Field field subpath ->
433 go (Opt.Access expr field) subpath
451binop func left right =
452 do jsLeft <- generateJsExpr left
453 jsRight <- generateJsExpr right
454 jsExpr (makeExpr func jsLeft jsRight)
458-- BINARY OPERATOR HELPERS
461makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
462makeExpr qualifiedOp@(Var.Canonical home op) =
464 simpleMake left right =
465 ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
467 if home == Var.Module (ModuleName.inCore ["Basics"]) then
468 Map.findWithDefault simpleMake op basicOps
473basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
475 Map.fromList (infixOps ++ specialOps)
478infixOps :: [(String, Expression () -> Expression () -> Expression ())]
482 (str, InfixExpr () op)
488 , infixOp "&&" OpLAnd
493specialOps :: [(String, Expression () -> Expression () -> Expression ())]
495 [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
496 , (,) "==" $ \a b -> BuiltIn.eq a b
497 , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
498 , (,) "<" $ cmp OpLT 0
499 , (,) ">" $ cmp OpGT 0
500 , (,) "<=" $ cmp OpLT 1
501 , (,) ">=" $ cmp OpGT (-1)
502 , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
506cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
508 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