@@ -5,7 +5,7 @@ module Generate.JavaScript.Expression
55 where
66
77import Control.Arrow (second)
8−import Control.Monad.State (State, foldM)
8+import Control.Monad (foldM)
99import qualified Data.List as List
1010import qualified Data.Map as Map
1111import Data.Monoid ((<>))
@@ -23,6 +23,7 @@ import qualified Generate.JavaScript.BuiltIn as BuiltIn
2323import qualified Generate.JavaScript.Foreign as Foreign
2424import qualified Generate.JavaScript.Literal as Literal
2525import qualified Generate.JavaScript.Variable as Var
26+import Generate.JavaScript.Variable (Generator)
2627import qualified Optimize.DecisionTree as DT
2728
2829
@@ -30,9 +31,11 @@ import qualified Optimize.DecisionTree as DT
3031-- GENERATE DECLARATION
3132
3233
33−generateDecl :: ModuleName.Canonical -> Text -> Opt.Def -> State Int [JS.Stmt]
34+generateDecl :: ModuleName.Canonical -> Text -> Opt.Def -> Generator JS.Stmt
3435generateDecl home name def =
35− Var.defineGlobal home name <$> generateDef name def
36+ do jsName <- Var.getGlobalName (V.Global home name)
37+ jsBody <- generateDef name def
38+ return $ JS.VarDeclStmt [ Help.varDecl jsName jsBody ]
3639
3740
3841
@@ -44,12 +47,12 @@ data Code
4447 | JsBlock [JS.Stmt]
4548
4649
47−jsExpr :: JS.Expr -> State Int Code
50+jsExpr :: JS.Expr -> Generator Code
4851jsExpr exp =
4952 return (JsExpr exp)
5053
5154
52−jsBlock :: [JS.Stmt] -> State Int Code
55+jsBlock :: [JS.Stmt] -> Generator Code
5356jsBlock exp =
5457 return (JsBlock exp)
5558
@@ -98,22 +101,22 @@ toExpr code =
98101-- EXPRESSIONS
99102
100103
101−generateJsExpr :: Opt.Expr -> State Int JS.Expr
104+generateJsExpr :: Opt.Expr -> Generator JS.Expr
102105generateJsExpr optExpr =
103106 toExpr <$> generateCode optExpr
104107
105108
106−generateCode :: Opt.Expr -> State Int Code
109+generateCode :: Opt.Expr -> Generator Code
107110generateCode expr =
108111 case expr of
109112 VarLocal name ->
110113 jsExpr $ Var.local name
111114
112115 VarGlobal name ->
113− jsExpr $ Var.global name
116+ JsExpr <$> Var.global name
114117
115118 Literal lit ->
116− jsExpr (Literal.literal lit)
119+ JsExpr <$> Literal.literal lit
117120
118121 Access record field ->
119122 do jsRecord <- generateJsExpr record
@@ -127,7 +130,7 @@ generateCode expr =
127130 in
128131 do jsRecord <- generateJsExpr record
129132 jsFields <- mapM fieldToJs fields
130− jsExpr $ BuiltIn.recordUpdate jsRecord jsFields
133+ JsExpr <$> BuiltIn.recordUpdate jsRecord jsFields
131134
132135 Record fields ->
133136 let
@@ -173,7 +176,7 @@ generateCode expr =
173176
174177 List elements ->
175178 do jsElements <- mapM generateJsExpr elements
176− jsExpr $ BuiltIn.list jsElements
179+ JsExpr <$> BuiltIn.list jsElements
177180
178181 Ctor tag members ->
179182 let
@@ -191,39 +194,41 @@ generateCode expr =
191194 jsExpr $ JS.DotRef jsDataExpr (JS.Id ("_" <> Text.pack (show index)))
192195
193196 Cmd moduleName _ ->
194− jsExpr $ BuiltIn.effect moduleName
197+ JsExpr <$> BuiltIn.effect moduleName
195198
196199 Sub moduleName _ ->
197− jsExpr $ BuiltIn.effect moduleName
200+ JsExpr <$> BuiltIn.effect moduleName
198201
199202 OutgoingPort name tipe ->
200− jsExpr $ BuiltIn.outgoingPort name (Foreign.encode tipe)
203+ JsExpr <$> BuiltIn.outgoingPort name (Foreign.encode tipe)
201204
202205 IncomingPort name tipe ->
203206 do jsDecoder <- generateJsExpr (Foreign.decode tipe)
204− jsExpr $ BuiltIn.incomingPort name jsDecoder
207+ JsExpr <$> BuiltIn.incomingPort name jsDecoder
205208
206209 Program kind body ->
207210 generateProgram kind body
208211
209212 GLShader src ->
210− jsExpr $ JS.Object [(JS.StringProp "src", Literal.literal (L.Str src))]
213+ do string <- Literal.literal (L.Str src)
214+ jsExpr $ JS.Object [(JS.StringProp "src", string)]
211215
212216 Crash home region maybeBranchProblem ->
213217 do maybeOptBranchProblem <- traverse generateJsExpr maybeBranchProblem
214− jsExpr $ BuiltIn.crash home region maybeOptBranchProblem
218+ JsExpr <$> BuiltIn.crash home region maybeOptBranchProblem
215219
216220
217221
218222-- PROGRAMS
219223
220224
221−generateProgram :: Can.Main -> Opt.Expr -> State Int Code
225+generateProgram :: Can.Main -> Opt.Expr -> Generator Code
222226generateProgram kind body =
223227 case kind of
224228 Can.VDom ->
225229 do html <- generateJsExpr body
226− jsExpr (Var.staticProgram <| html)
230+ func <- BuiltIn.staticProgram
231+ jsExpr (func <| html)
227232
228233 Can.NoFlags ->
229234 do almostProgram <- generateJsExpr body
@@ -239,13 +244,13 @@ generateProgram kind body =
239244-- DEFINITIONS
240245
241246
242−generateLetDef :: (Text, Opt.Def) -> State Int JS.Stmt
247+generateLetDef :: (Text, Opt.Def) -> Generator JS.Stmt
243248generateLetDef (name, def) =
244249 do jsBody <- generateDef name def
245250 return $ JS.VarDeclStmt [ Help.varDecl name jsBody ]
246251
247252
248−generateDef :: Text -> Opt.Def -> State Int JS.Expr
253+generateDef :: Text -> Opt.Def -> Generator JS.Expr
249254generateDef name def =
250255 case def of
251256 Opt.TailDef argNames body ->
@@ -255,7 +260,7 @@ generateDef name def =
255260 generateJsExpr body
256261
257262
258−generateTailFunction :: Text -> [Text] -> Opt.Expr -> State Int JS.Expr
263+generateTailFunction :: Text -> [Text] -> Opt.Expr -> Generator JS.Expr
259264generateTailFunction name args body =
260265 do code <- generateCode body
261266 return $ generateFunctionWithArity args $ JsBlock $ (:[]) $
@@ -268,7 +273,7 @@ generateTailFunction name args body =
268273-- FUNCTIONS
269274
270275
271−generateFunction :: [Text] -> Opt.Expr -> State Int Code
276+generateFunction :: [Text] -> Opt.Expr -> Generator Code
272277generateFunction args body =
273278 do code <- generateCode body
274279 jsExpr (generateFunctionWithArity args code)
@@ -297,7 +302,7 @@ generateFunctionWithArity rawArgs code =
297302-- GENERATE CALL
298303
299304
300−generateCall :: Opt.Expr -> [Opt.Expr] -> State Int Code
305+generateCall :: Opt.Expr -> [Opt.Expr] -> Generator Code
301306generateCall func args =
302307 case (func, args) of
303308 (Opt.VarGlobal (V.Global home name), [arg]) ->
@@ -320,13 +325,13 @@ generateCall func args =
320325 generateCallHelp func args
321326
322327
323−genPrefix :: JS.PrefixOp -> Opt.Expr -> State Int Code
328+genPrefix :: JS.PrefixOp -> Opt.Expr -> Generator Code
324329genPrefix op arg =
325330 do jsArg <- generateJsExpr arg
326331 jsExpr (JS.Prefix op jsArg)
327332
328333
329−genInfix :: JS.InfixOp -> Opt.Expr -> Opt.Expr -> State Int Code
334+genInfix :: JS.InfixOp -> Opt.Expr -> Opt.Expr -> Generator Code
330335genInfix op left right =
331336 do jsLeft <- generateJsExpr left
332337 jsRight <- generateJsExpr right
@@ -343,7 +348,7 @@ bitwise =
343348 ModuleName.inCore "Bitwise"
344349
345350
346−generateCallHelp :: Opt.Expr -> [Opt.Expr] -> State Int Code
351+generateCallHelp :: Opt.Expr -> [Opt.Expr] -> Generator Code
347352generateCallHelp func args =
348353 let
349354 arity = length args
@@ -362,7 +367,7 @@ generateCallHelp func args =
362367-- GENERATE IFS
363368
364369
365−generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> State Int Code
370+generateIf :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> Generator Code
366371generateIf givenBranches givenFinally =
367372 let
368373 (branches, finally) =
@@ -421,7 +426,7 @@ crushIfsHelp visitedBranches unvisitedBranches finally =
421426-- CASE EXPRESSIONS
422427
423428
424−generateCase :: Text -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> State Int [JS.Stmt]
429+generateCase :: Text -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> Generator [JS.Stmt]
425430generateCase exprName decider jumps =
426431 do labelRoot <- Var.fresh
427432 decider <- generateDecider exprName labelRoot decider
@@ -432,7 +437,7 @@ generateCase exprName decider jumps =
432437-- handle any jumps
433438
434439
435−goto :: Text -> [JS.Stmt] -> (Int, Opt.Expr) -> State Int [JS.Stmt]
440+goto :: Text -> [JS.Stmt] -> (Int, Opt.Expr) -> Generator [JS.Stmt]
436441goto labelRoot deciderStmts (target, branch) =
437442 let
438443 labeledDeciderStmt =
@@ -453,7 +458,7 @@ toLabel root target =
453458-- turn deciders into ifs and switches
454459
455460
456−generateDecider :: Text -> Text -> Opt.Decider Opt.Choice -> State Int [JS.Stmt]
461+generateDecider :: Text -> Text -> Opt.Decider Opt.Choice -> Generator [JS.Stmt]
457462generateDecider exprName labelRoot decisionTree =
458463 case decisionTree of
459464 Opt.Leaf (Opt.Inline branch) ->
@@ -466,7 +471,7 @@ generateDecider exprName labelRoot decisionTree =
466471 let
467472 makeTest (path, test) =
468473 do testExpr <- pathToTestableExpr exprName path test
469− return (JS.Infix JS.OpStrictEq testExpr (testToExpr test))
474+ JS.Infix JS.OpStrictEq testExpr <$> testToExpr test
470475 in
471476 do testExprs <- mapM makeTest testChain
472477 let cond = List.foldl1' (JS.Infix JS.OpLAnd) testExprs
@@ -481,29 +486,31 @@ generateDecider exprName labelRoot decisionTree =
481486 return [ JS.Switch testExpr (caseClauses ++ [caseDefault]) ]
482487
483488
484−edgeToCase :: Text -> Text -> (DT.Test, Opt.Decider Opt.Choice) -> State Int JS.Case
489+edgeToCase :: Text -> Text -> (DT.Test, Opt.Decider Opt.Choice) -> Generator JS.Case
485490edgeToCase exprName labelRoot (test, subTree) =
486− JS.Case (testToExpr test) <$> generateDecider exprName labelRoot subTree
491+ JS.Case
492+ <$> testToExpr test
493+ <*> generateDecider exprName labelRoot subTree
487494
488495
489−testToExpr :: DT.Test -> JS.Expr
496+testToExpr :: DT.Test -> Generator JS.Expr
490497testToExpr test =
491498 case test of
492499 DT.Constructor (V.Canonical _ tag) ->
493− JS.String tag
500+ return $ JS.String tag
494501
495502 DT.Literal (L.Chr char) ->
496− JS.String char
503+ return $ JS.String char
497504
498505 DT.Literal lit ->
499− Literal.literal lit
506+ Literal.literal lit
500507
501508
502509
503510-- work with paths
504511
505512
506−pathToTestableExpr :: Text -> DT.Path -> DT.Test -> State Int JS.Expr
513+pathToTestableExpr :: Text -> DT.Path -> DT.Test -> Generator JS.Expr
507514pathToTestableExpr root path exampleTest =
508515 do accessExpr <- generateJsExpr (pathToExpr root path)
509516 case exampleTest of
@@ -540,31 +547,32 @@ pathToExpr root fullPath =
540547-- BINARY OPERATORS
541548
542549
543−generateBinop :: V.Global -> Opt.Expr -> Opt.Expr -> State Int Code
550+generateBinop :: V.Global -> Opt.Expr -> Opt.Expr -> Generator Code
544551generateBinop op left right =
545552 do jsLeft <- generateJsExpr left
546553 jsRight <- generateJsExpr right
547− jsExpr (generateBinopHelp op jsLeft jsRight)
554+ JsExpr <$> generateBinopHelp op jsLeft jsRight
548555
549556
550557
551558-- BINARY OPERATOR HELPERS
552559
553560
554−generateBinopHelp :: V.Global -> JS.Expr -> JS.Expr -> JS.Expr
555−generateBinopHelp var@(V.Global home op) leftExpr rightExpr =
561+generateBinopHelp :: V.Global -> JS.Expr -> JS.Expr -> Generator JS.Expr
562+generateBinopHelp var@(V.Global home op) jsLeft jsRight =
556563 let
557564 simpleMake left right =
558− JS.Call (ref "A2") [ Var.global var, left, right ]
565+ do func <- Var.global var
566+ return $ JS.Call (ref "A2") [ func, left, right ]
559567 in
560568 if home == basics then
561− (Map.findWithDefault simpleMake op basicOps) leftExpr rightExpr
569+ (Map.findWithDefault simpleMake op basicsOps) jsLeft jsRight
562570
563571 else if op == "::" && home == list then
564− BuiltIn.cons leftExpr rightExpr
572+ BuiltIn.cons jsLeft jsRight
565573
566574 else
567− simpleMake leftExpr rightExpr
575+ simpleMake jsLeft jsRight
568576
569577
570578list :: ModuleName.Canonical
@@ -572,39 +580,43 @@ list =
572580 ModuleName.inCore "List"
573581
574582
575−basicOps :: Map.Map Text (JS.Expr -> JS.Expr -> JS.Expr)
576−basicOps =
577− Map.fromList (infixOps ++ specialOps)
583+basicsOps :: Map.Map Text (JS.Expr -> JS.Expr -> Generator JS.Expr)
584+basicsOps =
585+ Map.fromList (basicsOpsNormal ++ basicsOpsSpecial)
578586
579587
580−infixOps :: [(Text, JS.Expr -> JS.Expr -> JS.Expr)]
581−infixOps =
582− let
583− infixOp str op =
584− (str, JS.Infix op)
585− in
586− [ infixOp "+" JS.OpAdd
587− , infixOp "-" JS.OpSub
588− , infixOp "*" JS.OpMul
589− , infixOp "/" JS.OpDiv
590− , infixOp "&&" JS.OpLAnd
591− , infixOp "||" JS.OpLOr
592− ]
593−
594−
595−specialOps :: [(Text, JS.Expr -> JS.Expr -> JS.Expr)]
596−specialOps =
597− [ (,) "^" $ \a b -> JS.Call (obj ["Math","pow"]) [a,b]
598− , (,) "==" $ \a b -> BuiltIn.eq a b
599− , (,) "/=" $ \a b -> JS.Prefix JS.PrefixLNot (BuiltIn.eq a b)
600− , (,) "<" $ cmp JS.OpLT 0
601− , (,) ">" $ cmp JS.OpGT 0
602− , (,) "<=" $ cmp JS.OpLT 1
603− , (,) ">=" $ cmp JS.OpGT (-1)
604− , (,) "//" $ \a b -> JS.Infix JS.OpBOr (JS.Infix JS.OpDiv a b) (JS.Int 0)
588+basicsOpsNormal :: [(Text, JS.Expr -> JS.Expr -> Generator JS.Expr)]
589+basicsOpsNormal =
590+ let
591+ (=*>) str op =
592+ ( str, \left right -> return (JS.Infix op left right) )
593+ in
594+ [ "+" =*> JS.OpAdd
595+ , "-" =*> JS.OpSub
596+ , "*" =*> JS.OpMul
597+ , "/" =*> JS.OpDiv
598+ , "&&" =*> JS.OpLAnd
599+ , "||" =*> JS.OpLOr
600+ ]
601+
602+
603+basicsOpsSpecial :: [(Text, JS.Expr -> JS.Expr -> Generator JS.Expr)]
604+basicsOpsSpecial =
605+ let
606+ (=*>) = (,)
607+ in
608+ [ "^" =*> \a b -> return $ JS.Call (obj ["Math","pow"]) [a,b]
609+ , "==" =*> BuiltIn.eq
610+ , "/=" =*> \a b -> JS.Prefix JS.PrefixLNot <$> BuiltIn.eq a b
611+ , "<" =*> cmp JS.OpLT 0
612+ , ">" =*> cmp JS.OpGT 0
613+ , "<=" =*> cmp JS.OpLT 1
614+ , ">=" =*> cmp JS.OpGT (-1)
615+ , "//" =*> \a b -> return $ JS.Infix JS.OpBOr (JS.Infix JS.OpDiv a b) (JS.Int 0)
605616 ]
606617
607618
608−cmp :: JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> JS.Expr
619+cmp :: JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> Generator JS.Expr
609620cmp op n a b =
610− JS.Infix op (BuiltIn.cmp a b) (JS.Int n)
621+ do ordering <- BuiltIn.cmp a b
622+ return $ JS.Infix op ordering (JS.Int n)