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.Type as Type
14import qualified AST.Variable as Var
15import Generate.JavaScript.Helpers as Help
16import qualified Generate.JavaScript.BuiltIn as BuiltIn
17import qualified Generate.JavaScript.Foreign as Foreign
18import qualified Generate.JavaScript.Literal as Literal
19import qualified Generate.JavaScript.Variable as Var
20import qualified Optimize.DecisionTree as DT
28 = JsExpr (Expression ())
29 | JsBlock [Statement ()]
32jsExpr :: Expression () -> State Int Code
37jsBlock :: [Statement ()] -> State Int Code
42isBlock :: Code -> Bool
49toStatementList :: Code -> [Statement ()]
53 [ ReturnStmt () (Just expr) ]
59toStatement :: Code -> Statement ()
63 ReturnStmt () (Just expr)
72toExpr :: Code -> Expression ()
79 function [] stmts `call` []
86generateDef :: Opt.Def -> State Int [Statement ()]
88 do (home, name, jsBody) <-
90 Opt.TailDef (Opt.Facts home _) name argNames body ->
91 (,,) home name <$> generateTailFunction name argNames body
93 Opt.Def (Opt.Facts home _) name body ->
94 (,,) home name <$> generateJsExpr body
96 return (Var.define home name jsBody)
103generateJsExpr :: Opt.Expr -> State Int (Expression ())
104generateJsExpr optExpr =
105 toExpr <$> generateCode optExpr
108generateCode :: Opt.Expr -> State Int Code
112 jsExpr $ Var.canonical var
115 jsExpr (Literal.literal lit)
118 do lo' <- generateJsExpr lo
119 hi' <- generateJsExpr hi
120 jsExpr $ BuiltIn.range lo' hi'
122 Access record field ->
123 do record' <- generateJsExpr record
124 jsExpr $ DotRef () record' (var (Var.safe field))
126 Update record fields ->
128 fieldToJs (field, value) =
129 do jsValue <- generateJsExpr value
130 return (Var.safe field, jsValue)
132 do jsRecord <- generateJsExpr record
133 jsFields <- mapM fieldToJs fields
134 jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
138 toField (field, value) =
139 do jsValue <- generateJsExpr value
140 return (Var.safe field ==> jsValue)
142 do jsFields <- mapM toField fields
143 jsExpr $ ObjectLit () jsFields
145 Binop op leftExpr rightExpr ->
146 binop op leftExpr rightExpr
148 Function args body ->
149 generateFunction args body
154 aN = "A" ++ show arity
156 do jsFunc <- generateJsExpr func
157 jsArgs <- mapM generateJsExpr args
159 if 2 <= arity && arity <= 9 then
160 ref aN `call` (jsFunc:jsArgs)
162 foldl1 (<|) (jsFunc:jsArgs)
164 TailCall name argNames args ->
166 reassign name tempName =
167 ExprStmt () (AssignExpr () OpAssign (LVar () (Var.safe name)) (ref tempName))
169 do args' <- mapM generateJsExpr args
170 tempNames <- mapM (\_ -> Var.fresh) args
172 VarDeclStmt () (zipWith varDecl tempNames args')
173 : zipWith reassign argNames tempNames
174 ++ [ContinueStmt () (Just (Id () (Var.safe name)))]
177 do stmts <- mapM generateDef defs
178 code <- generateCode body
179 jsBlock (concat stmts ++ toStatementList code)
181 If branches finally ->
182 generateIf branches finally
184 Case exprName decider jumps ->
185 JsBlock <$> generateCase exprName decider jumps
187 ExplicitList elements ->
188 do jsElements <- mapM generateJsExpr elements
189 jsExpr $ BuiltIn.list jsElements
194 "ctor" ==> StringLit () tag
197 ("_" ++ show n) ==> entry
199 do jsMembers <- mapM generateJsExpr members
200 jsExpr $ ObjectLit () (ctor : zipWith toEntry jsMembers [ 0 :: Int .. ])
202 DataAccess dataExpr index ->
203 do jsDataExpr <- generateJsExpr dataExpr
204 jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
207 jsExpr $ BuiltIn.effect moduleName
210 jsExpr $ BuiltIn.effect moduleName
212 OutgoingPort name tipe ->
213 jsExpr $ BuiltIn.outgoingPort name (Foreign.encode tipe)
215 IncomingPort name tipe ->
216 do jsDecoder <- generateJsExpr (Foreign.decode tipe)
217 jsExpr $ BuiltIn.incomingPort name jsDecoder
220 generateProgram kind body
222 GLShader _uid src _tipe ->
223 jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
225 Crash home region maybeBranchProblem ->
226 do maybeOptBranchProblem <- traverse generateJsExpr maybeBranchProblem
227 jsExpr $ BuiltIn.crash home region maybeOptBranchProblem
234generateProgram :: Expr.Main Type.Canonical -> Opt.Expr -> State Int Code
235generateProgram kind body =
238 generateCode $ Record (("main", body) : fields)
248 gen [ ("flags", Foreign.decode tipe) ]
255generateFunction :: [String] -> Opt.Expr -> State Int Code
256generateFunction args body =
257 do code <- generateCode body
258 jsExpr (generateFunctionWithArity args code)
261generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
262generateTailFunction name args body =
263 do code <- generateCode body
264 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
266 (Id () (Var.safe name))
267 (WhileStmt () (BoolLit () True) (toStatement code))
270generateFunctionWithArity :: [String] -> Code -> Expression ()
271generateFunctionWithArity rawArgs code =
273 args = map Var.safe rawArgs
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] [ReturnStmt () (Just body)]) innerBody otherArgs
293generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
294generateIf givenBranches givenFinally =
296 (branches, finally) =
297 crushIfs givenBranches givenFinally
299 convertBranch (condition, expr) =
300 (,) <$> generateJsExpr condition <*> generateCode expr
302 ifExpression (condition, branch) otherwise =
303 CondExpr () condition branch otherwise
305 ifStatement (condition, branch) otherwise =
306 IfStmt () condition branch otherwise
308 do jsBranches <- mapM convertBranch branches
309 jsFinally <- generateCode finally
311 if any isBlock (jsFinally : map snd jsBranches)
313 jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
315 jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
319 :: [(Opt.Expr, Opt.Expr)]
321 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
322crushIfs branches finally =
323 crushIfsHelp [] branches finally
327 :: [(Opt.Expr, Opt.Expr)]
328 -> [(Opt.Expr, Opt.Expr)]
330 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
331crushIfsHelp visitedBranches unvisitedBranches finally =
332 case unvisitedBranches of
335 If subBranches subFinally ->
336 crushIfsHelp visitedBranches subBranches subFinally
339 (reverse visitedBranches, finally)
341 (Literal (L.Boolean True), branch) : _ ->
342 crushIfsHelp visitedBranches [] branch
344 visiting : unvisited ->
345 crushIfsHelp (visiting : visitedBranches) unvisited finally
354 -> Opt.Decider Opt.Choice
356 -> State Int [Statement ()]
357generateCase exprName decider jumps =
358 do labelRoot <- Var.fresh
359 decider <- generateDecider exprName labelRoot decider
360 foldM (goto labelRoot) decider jumps
367goto :: String -> [Statement ()] -> (Int, Opt.Expr) -> State Int [Statement ()]
368goto labelRoot deciderStmts (target, branch) =
372 (toLabel labelRoot target)
373 (DoWhileStmt () (BlockStmt () deciderStmts) (BoolLit () False))
375 do code <- generateCode branch
376 return (labeledDeciderStmt : toStatementList code)
379toLabel :: String -> Int -> Id ()
381 Id () (root ++ "_" ++ show target)
385-- turn deciders into ifs and switches
391 -> Opt.Decider Opt.Choice
392 -> State Int [Statement ()]
393generateDecider exprName labelRoot decisionTree =
395 Opt.Leaf (Opt.Inline branch) ->
396 toStatementList <$> generateCode branch
398 Opt.Leaf (Opt.Jump target) ->
399 return [ BreakStmt () (Just (toLabel labelRoot target)) ]
401 Opt.Chain testChain success failure ->
403 makeTest (path, test) =
404 do testExpr <- pathToTestableExpr exprName path test
405 return (InfixExpr () OpStrictEq testExpr (testToExpr test))
407 do testExprs <- mapM makeTest testChain
408 let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
409 thenBranch <- generateDecider exprName labelRoot success
410 elseBranch <- generateDecider exprName labelRoot failure
411 return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
413 Opt.FanOut path edges fallback ->
414 do testExpr <- pathToTestableExpr exprName path (fst (head edges))
415 caseClauses <- mapM (edgeToCaseClause exprName labelRoot) edges
416 caseDefault <- CaseDefault () <$> generateDecider exprName labelRoot fallback
417 return [ SwitchStmt () testExpr (caseClauses ++ [caseDefault]) ]
423 -> (DT.Test, Opt.Decider Opt.Choice)
424 -> State Int (CaseClause ())
425edgeToCaseClause exprName labelRoot (test, subTree) =
426 CaseClause () (testToExpr test) <$> generateDecider exprName labelRoot subTree
429testToExpr :: DT.Test -> Expression ()
432 DT.Constructor (Var.Canonical _ tag) ->
435 DT.Literal (L.Chr char) ->
446pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
447pathToTestableExpr root path exampleTest =
448 do accessExpr <- generateJsExpr (pathToExpr root path)
451 return (DotRef () accessExpr (Id () "ctor"))
453 DT.Literal (L.Chr _) ->
454 return (DotRef () accessExpr (Id () "valueOf") `call` [])
460pathToExpr :: String -> DT.Path -> Opt.Expr
461pathToExpr root fullPath =
462 go (Opt.Var (Var.local root)) fullPath
466 DT.Position index subpath ->
467 go (Opt.DataAccess expr index) subpath
469 DT.Field field subpath ->
470 go (Opt.Access expr field) subpath
488binop func left right =
489 do jsLeft <- generateJsExpr left
490 jsRight <- generateJsExpr right
491 jsExpr (makeExpr func jsLeft jsRight)
495-- BINARY OPERATOR HELPERS
498makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
499makeExpr qualifiedOp@(Var.Canonical home op) =
501 simpleMake left right =
502 ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
504 if home == Var.Module (ModuleName.inCore ["Basics"]) then
505 Map.findWithDefault simpleMake op basicOps
510basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
512 Map.fromList (infixOps ++ specialOps)
515infixOps :: [(String, Expression () -> Expression () -> Expression ())]
519 (str, InfixExpr () op)
525 , infixOp "&&" OpLAnd
530specialOps :: [(String, Expression () -> Expression () -> Expression ())]
532 [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
533 , (,) "==" $ \a b -> BuiltIn.eq a b
534 , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
535 , (,) "<" $ cmp OpLT 0
536 , (,) ">" $ cmp OpGT 0
537 , (,) "<=" $ cmp OpLT 1
538 , (,) ">=" $ cmp OpGT (-1)
539 , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
543cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
545 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