@@ -1,10 +1,13 @@
1+{-# LANGUAGE OverloadedStrings #-}
12module Generate.JavaScript.Expression (generateDef) where
23
34import Control.Arrow (second)
45import Control.Monad.State (State, foldM)
56import qualified Data.List as List
67import qualified Data.Map as Map
7−import Language.ECMAScript3.Syntax
8+import Data.Monoid ((<>))
9+import qualified Data.Text as Text
10+import Data.Text (Text)
811
912import qualified AST.Expression.Canonical as Can
1013import AST.Expression.Optimized as Opt
@@ -12,6 +15,7 @@ import qualified AST.Literal as L
1215import qualified AST.Module.Name as ModuleName
1316import qualified AST.Variable as Var
1417import Generate.JavaScript.Helpers as Help
18+import qualified Generate.JavaScript.Builder as JS
1519import qualified Generate.JavaScript.BuiltIn as BuiltIn
1620import qualified Generate.JavaScript.Foreign as Foreign
1721import qualified Generate.JavaScript.Literal as Literal
@@ -24,16 +28,16 @@ import qualified Optimize.DecisionTree as DT
2428
2529
2630data Code
27− = JsExpr (Expression ())
28− | JsBlock [Statement ()]
31+ = JsExpr JS.Expr
32+ | JsBlock [JS.Stmt]
2933
3034
31−jsExpr :: Expression () -> State Int Code
35+jsExpr :: JS.Expr -> State Int Code
3236jsExpr exp =
3337 return (JsExpr exp)
3438
3539
36−jsBlock :: [Statement ()] -> State Int Code
40+jsBlock :: [JS.Stmt] -> State Int Code
3741jsBlock exp =
3842 return (JsBlock exp)
3943
@@ -45,44 +49,44 @@ isBlock code =
4549 JsExpr _ -> False
4650
4751
48−toStatementList :: Code -> [Statement ()]
52+toStatementList :: Code -> [JS.Stmt]
4953toStatementList code =
5054 case code of
5155 JsExpr expr ->
52− [ ReturnStmt () (Just expr) ]
56+ [ JS.Return (Just expr) ]
5357
5458 JsBlock stmts ->
5559 stmts
5660
5761
58−toStatement :: Code -> Statement ()
62+toStatement :: Code -> JS.Stmt
5963toStatement code =
6064 case code of
6165 JsExpr expr ->
62− ReturnStmt () (Just expr)
66+ JS.Return (Just expr)
6367
6468 JsBlock [stmt] ->
6569 stmt
6670
6771 JsBlock stmts ->
68− BlockStmt () stmts
72+ JS.Block stmts
6973
7074
71−toExpr :: Code -> Expression ()
75+toExpr :: Code -> JS.Expr
7276toExpr code =
7377 case code of
7478 JsExpr expr ->
75− expr
79+ expr
7680
7781 JsBlock stmts ->
78− function [] stmts `call` []
82+ JS.Call (function [] stmts) []
7983
8084
8185
8286-- DEFINITIONS
8387
8488
85−generateDef :: Opt.Def -> State Int [Statement ()]
89+generateDef :: Opt.Def -> State Int [JS.Stmt]
8690generateDef def =
8791 do (home, name, jsBody) <-
8892 case def of
@@ -99,7 +103,7 @@ generateDef def =
99103-- EXPRESSIONS
100104
101105
102−generateJsExpr :: Opt.Expr -> State Int (Expression ())
106+generateJsExpr :: Opt.Expr -> State Int JS.Expr
103107generateJsExpr optExpr =
104108 toExpr <$> generateCode optExpr
105109
@@ -114,8 +118,8 @@ generateCode expr =
114118 jsExpr (Literal.literal lit)
115119
116120 Access record field ->
117− do record' <- generateJsExpr record
118− jsExpr $ DotRef () record' (var (Var.safe field))
121+ do jsRecord <- generateJsExpr record
122+ jsExpr $ JS.DotRef jsRecord (JS.Id (Var.safe field))
119123
120124 Update record fields ->
121125 let
@@ -134,7 +138,7 @@ generateCode expr =
134138 return (Var.safe field ==> jsValue)
135139 in
136140 do jsFields <- mapM toField fields
137− jsExpr $ ObjectLit () jsFields
141+ jsExpr $ JS.Object jsFields
138142
139143 Binop op leftExpr rightExpr ->
140144 binop op leftExpr rightExpr
@@ -148,14 +152,15 @@ generateCode expr =
148152 TailCall name argNames args ->
149153 let
150154 reassign name tempName =
151− ExprStmt () (AssignExpr () OpAssign (LVar () (Var.safe name)) (ref tempName))
155+ JS.ExprStmt $
156+ JS.Assign JS.OpAssign (JS.LVar (Var.safe name)) (ref tempName)
152157 in
153158 do args' <- mapM generateJsExpr args
154159 tempNames <- mapM (\_ -> Var.fresh) args
155160 jsBlock $
156− VarDeclStmt () (zipWith varDecl tempNames args')
161+ JS.VarDeclStmt (zipWith varDecl tempNames args')
157162 : zipWith reassign argNames tempNames
158− ++ [ContinueStmt () (Just (Id () (Var.safe name)))]
163+ ++ [JS.Continue (Just (JS.Id (Var.safe name)))]
159164
160165 Let defs body ->
161166 do stmts <- mapM generateDef defs
@@ -175,17 +180,17 @@ generateCode expr =
175180 Ctor tag members ->
176181 let
177182 ctor =
178− "ctor" ==> StringLit () tag
183+ "ctor" ==> JS.String tag
179184
180185 toEntry entry n =
181− ("_" ++ show n) ==> entry
186+ ("_" <> Text.pack (show n)) ==> entry
182187 in
183188 do jsMembers <- mapM generateJsExpr members
184− jsExpr $ ObjectLit () (ctor : zipWith toEntry jsMembers [ 0 :: Int .. ])
189+ jsExpr $ JS.Object (ctor : zipWith toEntry jsMembers [ 0 :: Int .. ])
185190
186191 CtorAccess dataExpr index ->
187192 do jsDataExpr <- generateJsExpr dataExpr
188− jsExpr $ DotRef () jsDataExpr (var ("_" ++ show index))
193+ jsExpr $ JS.DotRef jsDataExpr (JS.Id ("_" <> Text.pack (show index)))
189194
190195 Cmd moduleName ->
191196 jsExpr $ BuiltIn.effect moduleName
@@ -204,7 +209,7 @@ generateCode expr =
204209 generateProgram kind body
205210
206211 GLShader _uid src _tipe ->
207− jsExpr $ ObjectLit () [(PropString () "src", Literal.literal (L.Str src))]
212+ jsExpr $ JS.Object [(JS.StringProp "src", Literal.literal (L.Str src))]
208213
209214 Crash home region maybeBranchProblem ->
210215 do maybeOptBranchProblem <- traverse generateJsExpr maybeBranchProblem
@@ -224,7 +229,7 @@ generateProgram kind body =
224229
225230 Can.NoFlags ->
226231 do almostProgram <- generateJsExpr body
227− jsExpr (almostProgram `call` [])
232+ jsExpr (JS.Call almostProgram [])
228233
229234 Can.Flags tipe ->
230235 do almostProgram <- generateJsExpr body
@@ -236,22 +241,22 @@ generateProgram kind body =
236241-- FUNCTIONS
237242
238243
239−generateFunction :: [String] -> Opt.Expr -> State Int Code
244+generateFunction :: [Text] -> Opt.Expr -> State Int Code
240245generateFunction args body =
241246 do code <- generateCode body
242247 jsExpr (generateFunctionWithArity args code)
243248
244249
245−generateTailFunction :: String -> [String] -> Opt.Expr -> State Int (Expression ())
250+generateTailFunction :: Text -> [Text] -> Opt.Expr -> State Int JS.Expr
246251generateTailFunction name args body =
247252 do code <- generateCode body
248253 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
249− LabelledStmt ()
250− (Id () (Var.safe name))
251− (WhileStmt () (BoolLit () True) (toStatement code))
254+ JS.Labelled
255+ (JS.Id (Var.safe name))
256+ (JS.While (JS.Bool True) (toStatement code))
252257
253258
254−generateFunctionWithArity :: [String] -> Code -> Expression ()
259+generateFunctionWithArity :: [Text] -> Code -> JS.Expr
255260generateFunctionWithArity rawArgs code =
256261 let
257262 args = map Var.safe rawArgs
@@ -259,7 +264,7 @@ generateFunctionWithArity rawArgs code =
259264 in
260265 if 2 <= arity && arity <= 9 then
261266 let
262− fN = "F" ++ show arity
267+ fN = "F" <> Text.pack (show arity)
263268 in
264269 ref fN <| function args (toStatementList code)
265270 else
@@ -267,7 +272,7 @@ generateFunctionWithArity rawArgs code =
267272 (lastArg:otherArgs) = reverse args
268273 innerBody = function [lastArg] (toStatementList code)
269274 in
270− foldl (\body arg -> function [arg] [ReturnStmt () (Just body)]) innerBody otherArgs
275+ foldl (\body arg -> function [arg] [JS.Return (Just body)]) innerBody otherArgs
271276
272277
273278
@@ -281,7 +286,7 @@ generateCall func args =
281286 case getUnaryOp var of
282287 Just op ->
283288 do jsArg <- generateJsExpr arg
284− jsExpr $ PrefixExpr () op jsArg
289+ jsExpr $ JS.Prefix op jsArg
285290
286291 Nothing ->
287292 generateCallHelp func args
@@ -291,7 +296,7 @@ generateCall func args =
291296 Just (op, left, right) ->
292297 do jsLeft <- generateJsExpr left
293298 jsRight <- generateJsExpr right
294− jsExpr $ InfixExpr () op jsLeft jsRight
299+ jsExpr $ JS.Infix op jsLeft jsRight
295300
296301 Nothing ->
297302 generateCallHelp func args
@@ -304,58 +309,58 @@ generateCallHelp :: Opt.Expr -> [Opt.Expr] -> State Int Code
304309generateCallHelp func args =
305310 let
306311 arity = length args
307− aN = "A" ++ show arity
312+ aN = "A" <> Text.pack (show arity)
308313 in
309314 do jsFunc <- generateJsExpr func
310315 jsArgs <- mapM generateJsExpr args
311316 jsExpr $
312317 if 2 <= arity && arity <= 9 then
313− ref aN `call` (jsFunc:jsArgs)
318+ JS.Call (ref aN) (jsFunc:jsArgs)
314319 else
315320 foldl1 (<|) (jsFunc:jsArgs)
316321
317322
318−getUnaryOp :: Var.Canonical -> Maybe PrefixOp
323+getUnaryOp :: Var.Canonical -> Maybe JS.PrefixOp
319324getUnaryOp var =
320325 if var == bitwiseComplement then
321− Just PrefixBNot
326+ Just JS.PrefixBNot
322327
323328 else if var == basicsNot then
324− Just PrefixLNot
329+ Just JS.PrefixLNot
325330
326331 else
327332 Nothing
328333
329334
330−getBinaryOp :: Var.Canonical -> Opt.Expr -> Opt.Expr -> Maybe (InfixOp, Opt.Expr, Opt.Expr)
335+getBinaryOp :: Var.Canonical -> Opt.Expr -> Opt.Expr -> Maybe (JS.InfixOp, Opt.Expr, Opt.Expr)
331336getBinaryOp (Var.Canonical home name) left right =
332337 if home /= bitwise then
333338 Nothing
334339
335340 else
336341 case name of
337− "and" -> Just ( OpBAnd, left, right )
338− "or" -> Just ( OpBOr, left, right )
339− "xor" -> Just ( OpBXor, left, right )
340− "shiftLeftBy" -> Just ( OpLShift, right, left )
341− "shiftRightBy" -> Just ( OpSpRShift, right, left )
342− "shiftRightZfBy" -> Just ( OpZfRShift, right, left )
342+ "and" -> Just ( JS.OpBAnd, left, right )
343+ "or" -> Just ( JS.OpBOr, left, right )
344+ "xor" -> Just ( JS.OpBXor, left, right )
345+ "shiftLeftBy" -> Just ( JS.OpLShift, right, left )
346+ "shiftRightBy" -> Just ( JS.OpSpRShift, right, left )
347+ "shiftRightZfBy" -> Just ( JS.OpZfRShift, right, left )
343348 _ -> Nothing
344349
345350
346351bitwiseComplement :: Var.Canonical
347352bitwiseComplement =
348− Var.inCore ["Bitwise"] "complement"
353+ Var.inCore "Bitwise" "complement"
349354
350355
351356basicsNot :: Var.Canonical
352357basicsNot =
353− Var.inCore ["Basics"] "not"
358+ Var.inCore "Basics" "not"
354359
355360
356361bitwise :: Var.Home
357362bitwise =
358− Var.Module (ModuleName.inCore ["Bitwise"])
363+ Var.Module (ModuleName.inCore "Bitwise")
359364
360365
361366
@@ -372,10 +377,10 @@ generateIf givenBranches givenFinally =
372377 (,) <$> generateJsExpr condition <*> generateCode expr
373378
374379 ifExpression (condition, branch) otherwise =
375− CondExpr () condition branch otherwise
380+ JS.If condition branch otherwise
376381
377382 ifStatement (condition, branch) otherwise =
378− IfStmt () condition branch otherwise
383+ JS.IfStmt condition branch otherwise
379384 in
380385 do jsBranches <- mapM convertBranch branches
381386 jsFinally <- generateCode finally
@@ -421,11 +426,7 @@ crushIfsHelp visitedBranches unvisitedBranches finally =
421426-- CASE EXPRESSIONS
422427
423428
424−generateCase
425− :: String
426− -> Opt.Decider Opt.Choice
427− -> [(Int, Opt.Expr)]
428− -> State Int [Statement ()]
429+generateCase :: Text -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> State Int [JS.Stmt]
429430generateCase exprName decider jumps =
430431 do labelRoot <- Var.fresh
431432 decider <- generateDecider exprName labelRoot decider
@@ -436,76 +437,68 @@ generateCase exprName decider jumps =
436437-- handle any jumps
437438
438439
439−goto :: String -> [Statement ()] -> (Int, Opt.Expr) -> State Int [Statement ()]
440+goto :: Text -> [JS.Stmt] -> (Int, Opt.Expr) -> State Int [JS.Stmt]
440441goto labelRoot deciderStmts (target, branch) =
441442 let
442443 labeledDeciderStmt =
443− LabelledStmt ()
444+ JS.Labelled
444445 (toLabel labelRoot target)
445− (DoWhileStmt () (BlockStmt () deciderStmts) (BoolLit () False))
446+ (JS.DoWhile (JS.Block deciderStmts) (JS.Bool False))
446447 in
447448 do code <- generateCode branch
448449 return (labeledDeciderStmt : toStatementList code)
449450
450451
451−toLabel :: String -> Int -> Id ()
452+toLabel :: Text -> Int -> JS.Id
452453toLabel root target =
453− Id () (root ++ "_" ++ show target)
454+ JS.Id (root <> "_" <> Text.pack (show target))
454455
455456
456457
457458-- turn deciders into ifs and switches
458459
459460
460−generateDecider
461− :: String
462− -> String
463− -> Opt.Decider Opt.Choice
464− -> State Int [Statement ()]
461+generateDecider :: Text -> Text -> Opt.Decider Opt.Choice -> State Int [JS.Stmt]
465462generateDecider exprName labelRoot decisionTree =
466463 case decisionTree of
467464 Opt.Leaf (Opt.Inline branch) ->
468465 toStatementList <$> generateCode branch
469466
470467 Opt.Leaf (Opt.Jump target) ->
471− return [ BreakStmt () (Just (toLabel labelRoot target)) ]
468+ return [ JS.Break (Just (toLabel labelRoot target)) ]
472469
473470 Opt.Chain testChain success failure ->
474471 let
475472 makeTest (path, test) =
476473 do testExpr <- pathToTestableExpr exprName path test
477− return (InfixExpr () OpStrictEq testExpr (testToExpr test))
474+ return (JS.Infix JS.OpStrictEq testExpr (testToExpr test))
478475 in
479476 do testExprs <- mapM makeTest testChain
480− let cond = List.foldl1' (InfixExpr () OpLAnd) testExprs
477+ let cond = List.foldl1' (JS.Infix JS.OpLAnd) testExprs
481478 thenBranch <- generateDecider exprName labelRoot success
482479 elseBranch <- generateDecider exprName labelRoot failure
483− return [ IfStmt () cond (BlockStmt () thenBranch) (BlockStmt () elseBranch) ]
480+ return [ JS.IfStmt cond (JS.Block thenBranch) (JS.Block elseBranch) ]
484481
485482 Opt.FanOut path edges fallback ->
486483 do testExpr <- pathToTestableExpr exprName path (fst (head edges))
487− caseClauses <- mapM (edgeToCaseClause exprName labelRoot) edges
488− caseDefault <- CaseDefault () <$> generateDecider exprName labelRoot fallback
489− return [ SwitchStmt () testExpr (caseClauses ++ [caseDefault]) ]
484+ caseClauses <- mapM (edgeToCase exprName labelRoot) edges
485+ caseDefault <- JS.Default <$> generateDecider exprName labelRoot fallback
486+ return [ JS.Switch testExpr (caseClauses ++ [caseDefault]) ]
490487
491488
492−edgeToCaseClause
493− :: String
494− -> String
495− -> (DT.Test, Opt.Decider Opt.Choice)
496− -> State Int (CaseClause ())
497−edgeToCaseClause exprName labelRoot (test, subTree) =
498− CaseClause () (testToExpr test) <$> generateDecider exprName labelRoot subTree
489+edgeToCase :: Text -> Text -> (DT.Test, Opt.Decider Opt.Choice) -> State Int JS.Case
490+edgeToCase exprName labelRoot (test, subTree) =
491+ JS.Case (testToExpr test) <$> generateDecider exprName labelRoot subTree
499492
500493
501−testToExpr :: DT.Test -> Expression ()
494+testToExpr :: DT.Test -> JS.Expr
502495testToExpr test =
503496 case test of
504497 DT.Constructor (Var.Canonical _ tag) ->
505− StringLit () tag
498+ JS.String tag
506499
507500 DT.Literal (L.Chr char) ->
508− StringLit () [char]
501+ JS.String (Text.singleton char)
509502
510503 DT.Literal lit ->
511504 Literal.literal lit
@@ -515,21 +508,21 @@ testToExpr test =
515508-- work with paths
516509
517510
518−pathToTestableExpr :: String -> DT.Path -> DT.Test -> State Int (Expression ())
511+pathToTestableExpr :: Text -> DT.Path -> DT.Test -> State Int JS.Expr
519512pathToTestableExpr root path exampleTest =
520513 do accessExpr <- generateJsExpr (pathToExpr root path)
521514 case exampleTest of
522515 DT.Constructor _ ->
523− return (DotRef () accessExpr (Id () "ctor"))
516+ return $ JS.DotRef accessExpr (JS.Id "ctor")
524517
525518 DT.Literal (L.Chr _) ->
526− return (DotRef () accessExpr (Id () "valueOf") `call` [])
519+ return $ JS.Call (JS.DotRef accessExpr (JS.Id "valueOf")) []
527520
528521 DT.Literal _ ->
529522 return accessExpr
530523
531524
532−pathToExpr :: String -> DT.Path -> Opt.Expr
525+pathToExpr :: Text -> DT.Path -> Opt.Expr
533526pathToExpr root fullPath =
534527 go (Opt.Var (Var.local root)) fullPath
535528 where
@@ -567,11 +560,11 @@ binop func left right =
567560-- BINARY OPERATOR HELPERS
568561
569562
570−binopHelp :: Var.Canonical -> Expression () -> Expression () -> Expression ()
563+binopHelp :: Var.Canonical -> JS.Expr -> JS.Expr -> JS.Expr
571564binopHelp qualifiedOp@(Var.Canonical home op) leftExpr rightExpr =
572565 let
573566 simpleMake left right =
574− ref "A2" `call` [ Var.canonical qualifiedOp, left, right ]
567+ JS.Call (ref "A2") [ Var.canonical qualifiedOp, left, right ]
575568 in
576569 if home == basicsModule then
577570 (Map.findWithDefault simpleMake op basicOps) leftExpr rightExpr
@@ -585,52 +578,52 @@ binopHelp qualifiedOp@(Var.Canonical home op) leftExpr rightExpr =
585578
586579listModule :: Var.Home
587580listModule =
588− Var.Module (ModuleName.inCore ["List"])
581+ Var.Module (ModuleName.inCore "List")
589582
590583
591584listModuleInternals :: Var.Home
592585listModuleInternals =
593− Var.TopLevel (ModuleName.inCore ["List"])
586+ Var.TopLevel (ModuleName.inCore "List")
594587
595588
596589basicsModule :: Var.Home
597590basicsModule =
598− Var.Module (ModuleName.inCore ["Basics"])
591+ Var.Module (ModuleName.inCore "Basics")
599592
600593
601−basicOps :: Map.Map String (Expression () -> Expression () -> Expression ())
594+basicOps :: Map.Map Text (JS.Expr -> JS.Expr -> JS.Expr)
602595basicOps =
603596 Map.fromList (infixOps ++ specialOps)
604597
605598
606−infixOps :: [(String, Expression () -> Expression () -> Expression ())]
599+infixOps :: [(Text, JS.Expr -> JS.Expr -> JS.Expr)]
607600infixOps =
608601 let
609602 infixOp str op =
610− (str, InfixExpr () op)
603+ (str, JS.Infix op)
611604 in
612− [ infixOp "+" OpAdd
613− , infixOp "-" OpSub
614− , infixOp "*" OpMul
615− , infixOp "/" OpDiv
616− , infixOp "&&" OpLAnd
617− , infixOp "||" OpLOr
605+ [ infixOp "+" JS.OpAdd
606+ , infixOp "-" JS.OpSub
607+ , infixOp "*" JS.OpMul
608+ , infixOp "/" JS.OpDiv
609+ , infixOp "&&" JS.OpLAnd
610+ , infixOp "||" JS.OpLOr
618611 ]
619612
620613
621−specialOps :: [(String, Expression () -> Expression () -> Expression ())]
614+specialOps :: [(Text, JS.Expr -> JS.Expr -> JS.Expr)]
622615specialOps =
623− [ (,) "^" $ \a b -> obj ["Math","pow"] `call` [a,b]
616+ [ (,) "^" $ \a b -> JS.Call (obj ["Math","pow"]) [a,b]
624617 , (,) "==" $ \a b -> BuiltIn.eq a b
625− , (,) "/=" $ \a b -> PrefixExpr () PrefixLNot (BuiltIn.eq a b)
626− , (,) "<" $ cmp OpLT 0
627− , (,) ">" $ cmp OpGT 0
628− , (,) "<=" $ cmp OpLT 1
629− , (,) ">=" $ cmp OpGT (-1)
630− , (,) "//" $ \a b -> InfixExpr () OpBOr (InfixExpr () OpDiv a b) (IntLit () 0)
618+ , (,) "/=" $ \a b -> JS.Prefix JS.PrefixLNot (BuiltIn.eq a b)
619+ , (,) "<" $ cmp JS.OpLT 0
620+ , (,) ">" $ cmp JS.OpGT 0
621+ , (,) "<=" $ cmp JS.OpLT 1
622+ , (,) ">=" $ cmp JS.OpGT (-1)
623+ , (,) "//" $ \a b -> JS.Infix JS.OpBOr (JS.Infix JS.OpDiv a b) (JS.Int 0)
631624 ]
632625
633626
634−cmp :: InfixOp -> Int -> Expression () -> Expression () -> Expression ()
627+cmp :: JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> JS.Expr
635628cmp op n a b =
636− InfixExpr () op (BuiltIn.cmp a b) (IntLit () n)
629+ JS.Infix op (BuiltIn.cmp a b) (JS.Int n)