1module Generate.JavaScript (generate) where
3import Control.Applicative ((<$>),(<*>))
4import Control.Arrow (first, second, (***))
5import Control.Monad.State as State
6import qualified Data.List as List
7import qualified Data.Map as Map
8import Language.ECMAScript3.PrettyPrint as ES
9import Language.ECMAScript3.Syntax
10import qualified Text.PrettyPrint.Leijen as PP
12import qualified AST.Expression.General as Expr
13import AST.Expression.Optimized as Opt
15import qualified AST.Module as Module
16import qualified AST.Module.Name as ModuleName
17import qualified AST.Variable as Var
18import Generate.JavaScript.Helpers as Help
19import qualified Generate.JavaScript.BuiltIn as BuiltIn
20import qualified Generate.JavaScript.Literal as Literal
21import qualified Generate.JavaScript.Port as Port
22import qualified Generate.JavaScript.Variable as Var
23import qualified Optimize.Cases as PM
26generate :: Module.Optimized -> String
30 State.evalState (mapM generateDef definitions) 0
32 PP.displayS (PP.renderPretty 0.4 120 (ES.prettyPrint stmts)) ""
38 = JsExpr (Expression ())
39 | JsBlock [Statement ()]
42jsExpr :: Expression () -> State Int Code
47jsBlock :: [Statement ()] -> State Int Code
52isBlock :: Code -> Bool
59toStatementList :: Code -> [Statement ()]
68toStatement :: Code -> Statement ()
79toExpr :: Code -> Expression ()
86 function [] stmts `call` []
91generateDef :: Opt.Def -> State Int (Statement ())
93 do (home, name, jsBody) <-
95 Opt.TailDef (Opt.Facts home _) name argNames body ->
96 (,,) home name <$> generateTailFunction name argNames body
98 Opt.Def (Opt.Facts home _) name body ->
99 (,,) home name <$> generateJsExpr body
101 return (VarDeclStmt () [ varDecl (Var.defName home name) jsBody ])
106generateJsExpr :: Opt.Expr -> State Int (Expression ())
107generateJsExpr optExpr =
108 toExpr <$> generateCode optExpr
111generateCode :: Opt.Expr -> State Int Code
115 jsExpr $ Var.canonical var
118 jsExpr (Literal.literal lit)
121 do lo' <- generateJsExpr lo
122 hi' <- generateJsExpr hi
123 jsExpr $ BuiltIn.range lo' hi'
125 Access record field ->
126 do record' <- generateJsExpr record
127 jsExpr $ DotRef () record' (var (Var.safe field))
129 Update record fields ->
131 fieldToJs (field, value) =
132 do jsValue <- generateJsExpr value
133 return (Var.safe field, jsValue)
135 do jsRecord <- generateJsExpr record
136 jsFields <- mapM fieldToJs fields
137 jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
141 forM fields $ \(field, e) ->
142 (,) (Var.safe field) <$> generateJsExpr e
145 List.foldl' combine Map.empty fields'
147 jsExpr $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
149 combine record (field, value) =
150 Map.insertWith (++) field [value] record
153 ObjectLit () . map (prop *** ArrayLit ()) $
154 Map.toList (Map.filter (not . null) (Map.map tail fs))
157 map (first prop) (Map.toList (Map.map head fs))
159 Binop op leftExpr rightExpr ->
160 binop op leftExpr rightExpr
162 Function args body ->
163 generateFunction args body
168 aN = "A" ++ show arity
170 do jsFunc <- generateJsExpr func
171 jsArgs <- mapM generateJsExpr args
173 if 2 <= arity && arity <= 9 then
174 ref aN `call` (jsFunc:jsArgs)
176 foldl1 (<|) (jsFunc:jsArgs)
178 TailCall name argNames args ->
180 reassign name tempName =
181 ExprStmt () (AssignExpr () OpAssign (LVar () name) (ref tempName))
183 do args' <- mapM generateJsExpr args
184 tempNames <- mapM (\_ -> Var.fresh) args
186 VarDeclStmt () (zipWith varDecl tempNames args')
187 : zipWith reassign argNames tempNames
188 ++ [ContinueStmt () (Just (Id () name))]
191 do stmts <- mapM generateDef defs
192 code <- generateCode body
193 jsBlock (stmts ++ toStatementList code)
195 If branches finally ->
196 generateIf branches finally
198 Case expr decisionTree branches ->
199 generateCase expr decisionTree branches
201 ExplicitList elements ->
202 do jsElements <- mapM generateJsExpr elements
203 jsExpr $ BuiltIn.list jsElements
206 do jsMembers <- mapM generateJsExpr members
207 jsExpr $ ObjectLit () (ctor : fields jsMembers)
209 ctor = (prop "ctor", string tag)
211 zipWith (\n e -> (prop ("_" ++ show n), e)) [ 0 :: Int .. ]
213 DataAccess dataExpr index ->
214 do jsDataExpr <- generateJsExpr dataExpr
215 jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
217 GLShader _uid src _tipe ->
218 jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (Str src))]
222 Expr.In name portType ->
223 jsExpr (Port.inbound name portType)
225 Expr.Out name expr portType ->
226 do expr' <- generateJsExpr expr
227 jsExpr (Port.outbound name expr' portType)
229 Expr.Task name expr portType ->
230 do expr' <- generateJsExpr expr
231 jsExpr (Port.task name expr' portType)
239generateFunction :: [String] -> Opt.Expr -> State Int Code
240generateFunction args body =
241 do code <- generateCode body
242 jsExpr (generateFunctionWithArity args code)
245generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
246generateTailFunction name args body =
247 do code <- generateCode body
248 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
251 (WhileStmt () (BoolLit () True) (toStatement code))
254generateFunctionWithArity :: [String] -> Code -> Expression ()
255generateFunctionWithArity args code =
259 if 2 <= arity && arity <= 9 then
261 fN = "F" ++ show arity
263 ref fN <| function args (toStatementList code)
266 (lastArg:otherArgs) = reverse args
267 innerBody = function [lastArg] (toStatementList code)
269 foldl (\body arg -> function [arg] [ret body]) innerBody otherArgs
274generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
275generateIf givenBranches givenFinally =
277 (branches, finally) =
278 crushIfs givenBranches givenFinally
280 convertBranch (condition, expr) =
281 (,) <$> generateJsExpr condition <*> generateCode expr
283 ifExpression (condition, branch) otherwise =
284 CondExpr () condition branch otherwise
286 ifStatement (condition, branch) otherwise =
287 IfStmt () condition branch otherwise
289 do jsBranches <- mapM convertBranch branches
290 jsFinally <- generateCode finally
292 if any isBlock (jsFinally : map snd jsBranches)
294 jsBlock [ foldr ifStatement (toStatement jsFinally) (map (second toStatement) jsBranches) ]
296 jsExpr (foldr ifExpression (toExpr jsFinally) (map (second toExpr) jsBranches))
300 :: [(Opt.Expr, Opt.Expr)]
302 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
303crushIfs branches finally =
304 crushIfsHelp [] branches finally
308 :: [(Opt.Expr, Opt.Expr)]
309 -> [(Opt.Expr, Opt.Expr)]
311 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
312crushIfsHelp visitedBranches unvisitedBranches finally =
313 case unvisitedBranches of
316 If subBranches subFinally ->
317 crushIfsHelp visitedBranches subBranches subFinally
320 (reverse visitedBranches, finally)
322 (Literal (Boolean True), branch) : _ ->
323 crushIfsHelp visitedBranches [] branch
325 visiting : unvisited ->
326 crushIfsHelp (visiting : visitedBranches) unvisited finally
333 -> PM.DecisionTree Int
334 -> Map.Map Int Opt.Expr
336generateCase expr decisionTree branches =
337 error "TODO" expr decisionTree branches
347binop func left right =
348 do jsLeft <- generateJsExpr left
349 jsRight <- generateJsExpr right
350 jsExpr (makeExpr func jsLeft jsRight)
353-- BINARY OPERATOR HELPERS
355makeExpr :: Var.Canonical -> (Expression () -> Expression () -> Expression ())
356makeExpr qualifiedOp@(Var.Canonical home op) =
358 simpleMake left right =
359 ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
361 if home == Var.Module (ModuleName.inCore ["Basics"]) then
362 Map.findWithDefault simpleMake op basicOps
367basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
369 Map.fromList (infixOps ++ specialOps)
372infixOps :: [(String, Expression () -> Expression () -> Expression ())]
376 (str, InfixExpr () op)
382 , infixOp "&&" OpLAnd
387specialOps :: [(String, Expression () -> Expression () -> Expression ())]
389 [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
390 , (,) "==" $ \a b -> BuiltIn.eq a b
391 , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
392 , (,) "<" $ cmp OpLT 0
393 , (,) ">" $ cmp OpGT 0
394 , (,) "<=" $ cmp OpLT 1
395 , (,) ">=" $ cmp OpGT (-1)
396 , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
400cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
402 InfixExpr () op (BuiltIn.compare 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