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.General as Expr (Main(..))
10import AST.Expression.Optimized as Opt
11import qualified AST.Literal as L
12import qualified AST.Module.Name as ModuleName
13import qualified AST.Variable as Var
14import Generate.JavaScript.Helpers as Help
15import qualified Generate.JavaScript.BuiltIn as BuiltIn
16import qualified Generate.JavaScript.Foreign as Foreign
17import qualified Generate.JavaScript.Literal as Literal
18import qualified Generate.JavaScript.Variable as Var
19import qualified Optimize.DecisionTree as DT
27 = JsExpr (Expression ())
28 | JsBlock [Statement ()]
31jsExpr :: Expression () -> State Int Code
36jsBlock :: [Statement ()] -> State Int Code
41isBlock :: Code -> Bool
48toStatementList :: Code -> [Statement ()]
52 [ ReturnStmt () (Just expr) ]
58toStatement :: Code -> Statement ()
62 ReturnStmt () (Just expr)
71toExpr :: Code -> Expression ()
78 function [] stmts `call` []
85generateDef :: Opt.Def -> State Int [Statement ()]
87 do (home, name, jsBody) <-
89 Opt.TailDef (Opt.Facts home _) name argNames body ->
90 (,,) home name <$> generateTailFunction name argNames body
92 Opt.Def (Opt.Facts home _) name body ->
93 (,,) home name <$> generateJsExpr body
95 return (Var.define home name jsBody)
102generateJsExpr :: Opt.Expr -> State Int (Expression ())
103generateJsExpr optExpr =
104 toExpr <$> generateCode optExpr
107generateCode :: Opt.Expr -> State Int Code
111 jsExpr $ Var.canonical var
114 jsExpr (Literal.literal lit)
117 do lo' <- generateJsExpr lo
118 hi' <- generateJsExpr hi
119 jsExpr $ BuiltIn.range lo' hi'
121 Access record field ->
122 do record' <- generateJsExpr record
123 jsExpr $ DotRef () record' (var (Var.safe field))
125 Update record fields ->
127 fieldToJs (field, value) =
128 do jsValue <- generateJsExpr value
129 return (Var.safe field, jsValue)
131 do jsRecord <- generateJsExpr record
132 jsFields <- mapM fieldToJs fields
133 jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
137 toField (field, value) =
138 do jsValue <- generateJsExpr value
139 return (Var.safe field ==> jsValue)
141 do jsFields <- mapM toField fields
142 jsExpr $ ObjectLit () jsFields
144 Binop op leftExpr rightExpr ->
145 binop op leftExpr rightExpr
147 Function args body ->
148 generateFunction args body
153 aN = "A" ++ show arity
155 do jsFunc <- generateJsExpr func
156 jsArgs <- mapM generateJsExpr args
158 if 2 <= arity && arity <= 9 then
159 ref aN `call` (jsFunc:jsArgs)
161 foldl1 (<|) (jsFunc:jsArgs)
163 TailCall name argNames args ->
165 reassign name tempName =
166 ExprStmt () (AssignExpr () OpAssign (LVar () (Var.safe name)) (ref tempName))
168 do args' <- mapM generateJsExpr args
169 tempNames <- mapM (\_ -> Var.fresh) args
171 VarDeclStmt () (zipWith varDecl tempNames args')
172 : zipWith reassign argNames tempNames
173 ++ [ContinueStmt () (Just (Id () (Var.safe name)))]
176 do stmts <- mapM generateDef defs
177 code <- generateCode body
178 jsBlock (concat stmts ++ toStatementList code)
180 If branches finally ->
181 generateIf branches finally
183 Case exprName decider jumps ->
184 JsBlock <$> generateCase exprName decider jumps
186 ExplicitList elements ->
187 do jsElements <- mapM generateJsExpr elements
188 jsExpr $ BuiltIn.list jsElements
193 "ctor" ==> StringLit () tag
196 ("_" ++ show n) ==> entry
198 do jsMembers <- mapM generateJsExpr members
199 jsExpr $ ObjectLit () (ctor : zipWith toEntry jsMembers [ 0 :: Int .. ])
201 DataAccess dataExpr index ->
202 do jsDataExpr <- generateJsExpr dataExpr
203 jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
206 jsExpr $ BuiltIn.effect moduleName
209 jsExpr $ BuiltIn.effect moduleName
211 ForeignCmd name tipe ->
212 jsExpr $ BuiltIn.foreignCmd name (Foreign.encode tipe)
214 ForeignSub name tipe ->
215 do jsDecoder <- generateJsExpr (Foreign.decode tipe)
216 jsExpr $ BuiltIn.foreignSub name jsDecoder
221 generateCode (Data "vdom" [body])
224 generateCode (Data "no-flags" [body])
227 generateCode (Data "flags" [Foreign.decode tipe, body])
229 GLShader _uid src _tipe ->
230 jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
232 Crash home region maybeBranchProblem ->
233 do maybeOptBranchProblem <- traverse generateJsExpr maybeBranchProblem
234 jsExpr $ BuiltIn.crash home region maybeOptBranchProblem
241generateFunction :: [String] -> Opt.Expr -> State Int Code
242generateFunction args body =
243 do code <- generateCode body
244 jsExpr (generateFunctionWithArity args code)
247generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
248generateTailFunction name args body =
249 do code <- generateCode body
250 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
252 (Id () (Var.safe name))
253 (WhileStmt () (BoolLit () True) (toStatement code))
256generateFunctionWithArity :: [String] -> Code -> Expression ()
257generateFunctionWithArity rawArgs code =
259 args = map Var.safe rawArgs
262 if 2 <= arity && arity <= 9 then
264 fN = "F" ++ show arity
266 ref fN <| function args (toStatementList code)
269 (lastArg:otherArgs) = reverse args
270 innerBody = function [lastArg] (toStatementList code)
272 foldl (\body arg -> function [arg] [ReturnStmt () (Just body)]) innerBody otherArgs
279generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
280generateIf givenBranches givenFinally =
282 (branches, finally) =
283 crushIfs givenBranches givenFinally
285 convertBranch (condition, expr) =
286 (,) <$> generateJsExpr condition <*> generateCode expr
288 ifExpression (condition, branch) otherwise =
289 CondExpr () condition branch otherwise
291 ifStatement (condition, branch) otherwise =
292 IfStmt () condition branch otherwise
294 do jsBranches <- mapM convertBranch branches
295 jsFinally <- generateCode finally
297 if any isBlock (jsFinally : map snd jsBranches)
299 jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
301 jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
305 :: [(Opt.Expr, Opt.Expr)]
307 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
308crushIfs branches finally =
309 crushIfsHelp [] branches finally
313 :: [(Opt.Expr, Opt.Expr)]
314 -> [(Opt.Expr, Opt.Expr)]
316 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
317crushIfsHelp visitedBranches unvisitedBranches finally =
318 case unvisitedBranches of
321 If subBranches subFinally ->
322 crushIfsHelp visitedBranches subBranches subFinally
325 (reverse visitedBranches, finally)
327 (Literal (L.Boolean True), branch) : _ ->
328 crushIfsHelp visitedBranches [] branch
330 visiting : unvisited ->
331 crushIfsHelp (visiting : visitedBranches) unvisited finally
340 -> Opt.Decider Opt.Choice
342 -> State Int [Statement ()]
343generateCase exprName decider jumps =
344 do labelRoot <- Var.fresh
345 decider <- generateDecider exprName labelRoot decider
346 foldM (goto labelRoot) decider jumps
353goto :: String -> [Statement ()] -> (Int, Opt.Expr) -> State Int [Statement ()]
354goto labelRoot deciderStmts (target, branch) =
358 (toLabel labelRoot target)
359 (DoWhileStmt () (BlockStmt () deciderStmts) (BoolLit () False))
361 do code <- generateCode branch
362 return (labeledDeciderStmt : toStatementList code)
365toLabel :: String -> Int -> Id ()
367 Id () (root ++ "_" ++ show target)
371-- turn deciders into ifs and switches
377 -> Opt.Decider Opt.Choice
378 -> State Int [Statement ()]
379generateDecider exprName labelRoot decisionTree =
381 Opt.Leaf (Opt.Inline branch) ->
382 toStatementList <$> generateCode branch
384 Opt.Leaf (Opt.Jump target) ->
385 return [ BreakStmt () (Just (toLabel labelRoot target)) ]
387 Opt.Chain testChain success failure ->
389 makeTest (path, test) =
390 do testExpr <- pathToTestableExpr exprName path test
391 return (InfixExpr () OpStrictEq testExpr (testToExpr test))
393 do testExprs <- mapM makeTest testChain
394 let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
395 thenBranch <- generateDecider exprName labelRoot success
396 elseBranch <- generateDecider exprName labelRoot failure
397 return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
399 Opt.FanOut path edges fallback ->
400 do testExpr <- pathToTestableExpr exprName path (fst (head edges))
401 caseClauses <- mapM (edgeToCaseClause exprName labelRoot) edges
402 caseDefault <- CaseDefault () <$> generateDecider exprName labelRoot fallback
403 return [ SwitchStmt () testExpr (caseClauses ++ [caseDefault]) ]
409 -> (DT.Test, Opt.Decider Opt.Choice)
410 -> State Int (CaseClause ())
411edgeToCaseClause exprName labelRoot (test, subTree) =
412 CaseClause () (testToExpr test) <$> generateDecider exprName labelRoot subTree
415testToExpr :: DT.Test -> Expression ()
418 DT.Constructor (Var.Canonical _ tag) ->
421 DT.Literal (L.Chr char) ->
432pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
433pathToTestableExpr root path exampleTest =
434 do accessExpr <- generateJsExpr (pathToExpr root path)
437 return (DotRef () accessExpr (Id () "ctor"))
439 DT.Literal (L.Chr _) ->
440 return (DotRef () accessExpr (Id () "valueOf") `call` [])
446pathToExpr :: String -> DT.Path -> Opt.Expr
447pathToExpr root fullPath =
448 go (Opt.Var (Var.local root)) fullPath
452 DT.Position index subpath ->
453 go (Opt.DataAccess expr index) subpath
455 DT.Field field subpath ->
456 go (Opt.Access expr field) subpath
474binop func left right =
475 do jsLeft <- generateJsExpr left
476 jsRight <- generateJsExpr right
477 jsExpr (makeExpr func jsLeft jsRight)
481-- BINARY OPERATOR HELPERS
484makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
485makeExpr qualifiedOp@(Var.Canonical home op) =
487 simpleMake left right =
488 ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
490 if home == Var.Module (ModuleName.inCore ["Basics"]) then
491 Map.findWithDefault simpleMake op basicOps
496basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
498 Map.fromList (infixOps ++ specialOps)
501infixOps :: [(String, Expression () -> Expression () -> Expression ())]
505 (str, InfixExpr () op)
511 , infixOp "&&" OpLAnd
516specialOps :: [(String, Expression () -> Expression () -> Expression ())]
518 [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
519 , (,) "==" $ \a b -> BuiltIn.eq a b
520 , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
521 , (,) "<" $ cmp OpLT 0
522 , (,) ">" $ cmp OpGT 0
523 , (,) "<=" $ cmp OpLT 1
524 , (,) ">=" $ cmp OpGT (-1)
525 , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
529cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
531 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