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 qualified AST.Expression.General as Expr
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.Literal as Literal
17import qualified Generate.JavaScript.Port as Port
18import qualified Generate.JavaScript.Variable as Var
19import qualified Optimize.Patterns.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` []
81generateDef :: Opt.Def -> State Int (Statement ())
83 do (home, name, jsBody) <-
85 Opt.TailDef (Opt.Facts home _) name argNames body ->
86 (,,) home name <$> generateTailFunction name argNames body
88 Opt.Def (Opt.Facts home _) name body ->
89 (,,) home name <$> generateJsExpr body
91 return (Var.define name jsBody)
96generateJsExpr :: Opt.Expr -> State Int (Expression ())
97generateJsExpr optExpr =
98 toExpr <$> generateCode optExpr
101generateCode :: Opt.Expr -> State Int Code
105 jsExpr $ Var.canonical var
108 jsExpr (Literal.literal lit)
111 do lo' <- generateJsExpr lo
112 hi' <- generateJsExpr hi
113 jsExpr $ BuiltIn.range lo' hi'
115 Access record field ->
116 do record' <- generateJsExpr record
117 jsExpr $ DotRef () record' (var (Var.safe field))
119 Update record fields ->
121 fieldToJs (field, value) =
122 do jsValue <- generateJsExpr value
123 return (Var.safe field, jsValue)
125 do jsRecord <- generateJsExpr record
126 jsFields <- mapM fieldToJs fields
127 jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
131 toField (field, value) =
132 do jsValue <- generateJsExpr value
133 return (prop (Var.safe field), jsValue)
135 do jsFields <- mapM toField fields
136 jsExpr $ ObjectLit () jsFields
138 Binop op leftExpr rightExpr ->
139 binop op leftExpr rightExpr
141 Function args body ->
142 generateFunction args body
147 aN = "A" ++ show arity
149 do jsFunc <- generateJsExpr func
150 jsArgs <- mapM generateJsExpr args
152 if 2 <= arity && arity <= 9 then
153 ref aN `call` (jsFunc:jsArgs)
155 foldl1 (<|) (jsFunc:jsArgs)
157 TailCall name argNames args ->
159 reassign name tempName =
160 ExprStmt () (AssignExpr () OpAssign (LVar () name) (ref tempName))
162 do args' <- mapM generateJsExpr args
163 tempNames <- mapM (\_ -> Var.fresh) args
165 VarDeclStmt () (zipWith varDecl tempNames args')
166 : zipWith reassign argNames tempNames
167 ++ [ContinueStmt () (Just (Id () name))]
170 do stmts <- mapM generateDef defs
171 code <- generateCode body
172 jsBlock (stmts ++ toStatementList code)
174 If branches finally ->
175 generateIf branches finally
177 Case exprName decider jumps ->
178 JsBlock <$> generateCase exprName decider jumps
180 ExplicitList elements ->
181 do jsElements <- mapM generateJsExpr elements
182 jsExpr $ BuiltIn.list jsElements
185 do jsMembers <- mapM generateJsExpr members
186 jsExpr $ ObjectLit () (ctor : fields jsMembers)
188 ctor = (prop "ctor", StringLit () tag)
190 zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
192 DataAccess dataExpr index ->
193 do jsDataExpr <- generateJsExpr dataExpr
194 jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
196 GLShader _uid src _tipe ->
197 jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
201 Expr.In name portType ->
202 jsExpr (Port.inbound name portType)
204 Expr.Out name expr portType ->
205 do expr' <- generateJsExpr expr
206 jsExpr (Port.outbound name expr' portType)
208 Expr.Task name expr portType ->
209 do expr' <- generateJsExpr expr
210 jsExpr (Port.task name expr' portType)
212 Crash region maybeCaseCrashValue ->
213 jsExpr $ BuiltIn.crash region maybeCaseCrashValue
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 $ (:[]) $
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
254generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
255generateIf givenBranches givenFinally =
257 (branches, finally) =
258 crushIfs givenBranches givenFinally
260 convertBranch (condition, expr) =
261 (,) <$> generateJsExpr condition <*> generateCode expr
263 ifExpression (condition, branch) otherwise =
264 CondExpr () condition branch otherwise
266 ifStatement (condition, branch) otherwise =
267 IfStmt () condition branch otherwise
269 do jsBranches <- mapM convertBranch branches
270 jsFinally <- generateCode finally
272 if any isBlock (jsFinally : map snd jsBranches)
274 jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
276 jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
280 :: [(Opt.Expr, Opt.Expr)]
282 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
283crushIfs branches finally =
284 crushIfsHelp [] branches finally
288 :: [(Opt.Expr, Opt.Expr)]
289 -> [(Opt.Expr, Opt.Expr)]
291 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
292crushIfsHelp visitedBranches unvisitedBranches finally =
293 case unvisitedBranches of
296 If subBranches subFinally ->
297 crushIfsHelp visitedBranches subBranches subFinally
300 (reverse visitedBranches, finally)
302 (Literal (L.Boolean True), branch) : _ ->
303 crushIfsHelp visitedBranches [] branch
305 visiting : unvisited ->
306 crushIfsHelp (visiting : visitedBranches) unvisited finally
313 -> Opt.Decider Opt.Choice
315 -> State Int [Statement ()]
316generateCase exprName decider jumps =
317 do labelRoot <- Var.fresh
318 decider <- generateDecider exprName labelRoot decider
319 foldM (goto labelRoot) decider jumps
324goto :: String -> [Statement ()] -> (Int, Opt.Expr) -> State Int [Statement ()]
325goto labelRoot deciderStmts (target, branch) =
329 (toLabel labelRoot target)
330 (DoWhileStmt () (BlockStmt () deciderStmts) (BoolLit () False))
332 do code <- generateCode branch
333 return (labeledDeciderStmt : toStatementList code)
336toLabel :: String -> Int -> Id ()
338 Id () (root ++ "_" ++ show target)
341-- turn deciders into ifs and switches
346 -> Opt.Decider Opt.Choice
347 -> State Int [Statement ()]
348generateDecider exprName labelRoot decisionTree =
350 Opt.Leaf (Opt.Inline branch) ->
351 toStatementList <$> generateCode branch
353 Opt.Leaf (Opt.Jump target) ->
354 return [ BreakStmt () (Just (toLabel labelRoot target)) ]
356 Opt.Chain testChain success failure ->
358 makeTest (path, test) =
359 do testExpr <- pathToTestableExpr exprName path test
360 return (InfixExpr () OpStrictEq testExpr (testToExpr test))
362 do testExprs <- mapM makeTest testChain
363 let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
364 thenBranch <- generateDecider exprName labelRoot success
365 elseBranch <- generateDecider exprName labelRoot failure
366 return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
368 Opt.FanOut path edges fallback ->
369 do testExpr <- pathToTestableExpr exprName path (fst (head edges))
370 caseClauses <- mapM (edgeToCaseClause exprName labelRoot) edges
371 caseDefault <- CaseDefault () <$> generateDecider exprName labelRoot fallback
372 return [ SwitchStmt () testExpr (caseClauses ++ [caseDefault]) ]
378 -> (DT.Test, Opt.Decider Opt.Choice)
379 -> State Int (CaseClause ())
380edgeToCaseClause exprName labelRoot (test, subTree) =
381 CaseClause () (testToExpr test) <$> generateDecider exprName labelRoot subTree
384testToExpr :: DT.Test -> Expression ()
387 DT.Constructor (Var.Canonical _ tag) ->
390 DT.Literal (L.Chr char) ->
399pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
400pathToTestableExpr root path exampleTest =
401 do accessExpr <- generateJsExpr (pathToExpr root path)
404 return (DotRef () accessExpr (Id () "ctor"))
410pathToExpr :: String -> DT.Path -> Opt.Expr
411pathToExpr root fullPath =
412 go (Opt.Var (Var.local root)) fullPath
416 DT.Position index subpath ->
417 go (Opt.DataAccess expr index) subpath
419 DT.Field field subpath ->
420 go (Opt.Access expr field) subpath
436binop func left right =
437 do jsLeft <- generateJsExpr left
438 jsRight <- generateJsExpr right
439 jsExpr (makeExpr func jsLeft jsRight)
442-- BINARY OPERATOR HELPERS
444makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
445makeExpr qualifiedOp@(Var.Canonical home op) =
447 simpleMake left right =
448 ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
450 if home == Var.Module (ModuleName.inCore ["Basics"]) then
451 Map.findWithDefault simpleMake op basicOps
456basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
458 Map.fromList (infixOps ++ specialOps)
461infixOps :: [(String, Expression () -> Expression () -> Expression ())]
465 (str, InfixExpr () op)
471 , infixOp "&&" OpLAnd
476specialOps :: [(String, Expression () -> Expression () -> Expression ())]
478 [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
479 , (,) "==" $ \a b -> BuiltIn.eq a b
480 , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
481 , (,) "<" $ cmp OpLT 0
482 , (,) ">" $ cmp OpGT 0
483 , (,) "<=" $ cmp OpLT 1
484 , (,) ">=" $ cmp OpGT (-1)
485 , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
489cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
491 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