@@ -27,6 +27,8 @@ import Language.PureScript.CodeGen.JS.AST
27import Language.PureScript.CodeGen.Common (identToJs)
27import Language.PureScript.CodeGen.Common (identToJs)
28import Language.PureScript.Names
28import Language.PureScript.Names
30+import qualified Language.PureScript.Constants as C
30magicDo :: Options -> JS -> JS
32magicDo :: Options -> JS -> JS
31magicDo opts | optionsMagicDo opts = inlineST . magicDo'
33magicDo opts | optionsMagicDo opts = inlineST . magicDo'
32 | otherwise = id
34 | otherwise = id
@@ -63,10 +65,10 @@ magicDo' = everywhere (mkT undo) . everywhere' (mkT convert)
63 convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock [JSReturn ret])]) | isBind bind =
65 convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock [JSReturn ret])]) | isBind bind =
64 JSFunction (Just fnName) [] $ JSBlock [ JSVariableIntroduction arg (Just (JSApp m [])), JSReturn (JSApp ret []) ]
66 JSFunction (Just fnName) [] $ JSBlock [ JSVariableIntroduction arg (Just (JSApp m [])), JSReturn (JSApp ret []) ]
65 -- Desugar untilE
67 -- Desugar untilE
66− convert (JSApp (JSApp f [arg]) []) | isEffFunc "untilE" f =
68+ convert (JSApp (JSApp f [arg]) []) | isEffFunc C.untilE f =
67 JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSUnary Not (JSApp arg [])) (JSBlock []), JSReturn (JSObjectLiteral []) ])) []
69 JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSUnary Not (JSApp arg [])) (JSBlock []), JSReturn (JSObjectLiteral []) ])) []
68 -- Desugar whileE
70 -- Desugar whileE
69− convert (JSApp (JSApp (JSApp f [arg1]) [arg2]) []) | isEffFunc "whileE" f =
71+ convert (JSApp (JSApp (JSApp f [arg1]) [arg2]) []) | isEffFunc C.whileE f =
70 JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSApp arg1 []) (JSBlock [ JSApp arg2 [] ]), JSReturn (JSObjectLiteral []) ])) []
72 JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSApp arg1 []) (JSBlock [ JSApp arg2 [] ]), JSReturn (JSObjectLiteral []) ])) []
71 convert other = other
73 convert other = other
72 -- Check if an expression represents a monomorphic call to >>= for the Eff monad
74 -- Check if an expression represents a monomorphic call to >>= for the Eff monad
@@ -76,21 +78,31 @@ magicDo' = everywhere (mkT undo) . everywhere' (mkT convert)
76 isReturn (JSApp retPoly [effDict]) | isRetPoly retPoly && isEffDict effDict = True
78 isReturn (JSApp retPoly [effDict]) | isRetPoly retPoly && isEffDict effDict = True
77 isReturn _ = False
79 isReturn _ = False
78 -- Check if an expression represents the polymorphic >>= function
80 -- Check if an expression represents the polymorphic >>= function
79− isBindPoly (JSAccessor prop (JSAccessor "Prelude" (JSVar "_ps"))) | prop == identToJs (Op ">>=") = True
81+ isBindPoly (JSAccessor prop (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
83+ prop == identToJs (Op (C.>>=)) = True
80− isBindPoly (JSIndexer (JSStringLiteral ">>=") (JSAccessor "Prelude" (JSVar "_ps"))) = True
84+ isBindPoly (JSIndexer (JSStringLiteral bind) (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
86+ bind == (C.>>=) = True
81 isBindPoly _ = False
87 isBindPoly _ = False
82 -- Check if an expression represents the polymorphic return function
88 -- Check if an expression represents the polymorphic return function
83− isRetPoly (JSAccessor "$return" (JSAccessor "Prelude" (JSVar "_ps"))) = True
89+ isRetPoly (JSAccessor returnEscaped (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
91+ returnEscaped == C.returnEscaped = True
84− isRetPoly (JSIndexer (JSStringLiteral "return") (JSAccessor "Prelude" (JSVar "_ps"))) = True
92+ isRetPoly (JSIndexer (JSStringLiteral return') (JSAccessor prelude (JSVar _ps))) | prelude == C.prelude &&
94+ return' == C.return = True
85 isRetPoly _ = False
95 isRetPoly _ = False
86 -- Check if an expression represents a function in the Ef module
96 -- Check if an expression represents a function in the Ef module
87− isEffFunc name (JSAccessor name' (JSAccessor "Control_Monad_Eff" (JSVar "_ps"))) | name == name' = True
97+ isEffFunc name (JSAccessor name' (JSAccessor eff (JSVar _ps))) | eff == C.eff &&
88 isEffFunc _ _ = False
100 isEffFunc _ _ = False
89− -- The name of the type class dictionary for the Monad Eff instance
90− effDictName = "monadEff"
91 -- Check if an expression represents the Monad Eff dictionary
101 -- Check if an expression represents the Monad Eff dictionary
92− isEffDict (JSApp (JSVar ident) [JSObjectLiteral []]) | ident == effDictName = True
102+ isEffDict (JSApp (JSVar ident) [JSObjectLiteral []]) | ident == C.monadEffDictionary = True
93− isEffDict (JSApp (JSAccessor prop (JSAccessor "Control_Monad_Eff" (JSVar "_ps"))) [JSObjectLiteral []]) | prop == effDictName = True
103+ isEffDict (JSApp (JSAccessor prop (JSAccessor eff (JSVar _ps))) [JSObjectLiteral []]) | eff == C.eff &&
105+ prop == C.monadEffDictionary = True
94 isEffDict _ = False
106 isEffDict _ = False
95 -- Remove __do function applications which remain after desugaring
107 -- Remove __do function applications which remain after desugaring
96 undo :: JS -> JS
108 undo :: JS -> JS
@@ -106,7 +118,7 @@ inlineST = everywhere (mkT convertBlock)
106 -- Look for runST blocks and inline the STRefs there.
118 -- Look for runST blocks and inline the STRefs there.
107 -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
119 -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
108 -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
120 -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
109− convertBlock (JSApp f [arg]) | isSTFunc "runST" f || isSTFunc "runSTArray" f =
121+ convertBlock (JSApp f [arg]) | isSTFunc C.runST f || isSTFunc C.runSTArray f =
110 let refs = nub . findSTRefsIn $ arg
122 let refs = nub . findSTRefsIn $ arg
111 usages = findAllSTUsagesIn arg
123 usages = findAllSTUsagesIn arg
112 allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
124 allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
@@ -116,32 +128,34 @@ inlineST = everywhere (mkT convertBlock)
116 -- Convert a block in a safe way, preserving object wrappers of references,
128 -- Convert a block in a safe way, preserving object wrappers of references,
117 -- or in a more aggressive way, turning wrappers into local variables depending on the
129 -- or in a more aggressive way, turning wrappers into local variables depending on the
118 -- agg(ressive) parameter.
130 -- agg(ressive) parameter.
119− convert agg (JSApp (JSApp f [arg]) []) | isSTFunc "newSTRef" f =
131+ convert agg (JSApp (JSApp f [arg]) []) | isSTFunc C.newSTRef f =
120− if agg then arg else JSObjectLiteral [("value", arg)]
132+ if agg then arg else JSObjectLiteral [(C.stRefValue, arg)]
121− convert agg (JSApp (JSApp f [ref]) []) | isSTFunc "readSTRef" f =
133+ convert agg (JSApp (JSApp f [ref]) []) | isSTFunc C.readSTRef f =
122− if agg then ref else JSAccessor "value" ref
134+ if agg then ref else JSAccessor C.stRefValue ref
123− convert agg (JSApp (JSApp (JSApp f [ref]) [arg]) []) | isSTFunc "writeSTRef" f =
135+ convert agg (JSApp (JSApp (JSApp f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
124− if agg then JSAssignment ref arg else JSAssignment (JSAccessor "value" ref) arg
136+ if agg then JSAssignment ref arg else JSAssignment (JSAccessor C.stRefValue ref) arg
125− convert agg (JSApp (JSApp (JSApp f [ref]) [func]) []) | isSTFunc "modifySTRef" f =
137+ convert agg (JSApp (JSApp (JSApp f [ref]) [func]) []) | isSTFunc C.modifySTRef f =
126− if agg then JSAssignment ref (JSApp func [ref]) else JSAssignment (JSAccessor "value" ref) (JSApp func [JSAccessor "value" ref])
138+ if agg then JSAssignment ref (JSApp func [ref]) else JSAssignment (JSAccessor C.stRefValue ref) (JSApp func [JSAccessor C.stRefValue ref])
127− convert _ (JSApp (JSApp (JSApp f [arr]) [i]) []) | isSTFunc "peekSTArray" f =
139+ convert _ (JSApp (JSApp (JSApp f [arr]) [i]) []) | isSTFunc C.peekSTArray f =
128 JSIndexer i arr
140 JSIndexer i arr
129− convert _ (JSApp (JSApp (JSApp (JSApp f [arr]) [i]) [val]) []) | isSTFunc "pokeSTArray" f =
141+ convert _ (JSApp (JSApp (JSApp (JSApp f [arr]) [i]) [val]) []) | isSTFunc C.pokeSTArray f =
130 JSAssignment (JSIndexer i arr) val
142 JSAssignment (JSIndexer i arr) val
131 convert _ other = other
143 convert _ other = other
132 -- Check if an expression represents a function in the ST module
144 -- Check if an expression represents a function in the ST module
133− isSTFunc name (JSAccessor name' (JSAccessor "Control_Monad_ST" (JSVar "_ps"))) | name == name' = True
145+ isSTFunc name (JSAccessor name' (JSAccessor st (JSVar _ps))) | st == C.st &&
147+ name == name' = True
134 isSTFunc _ _ = False
148 isSTFunc _ _ = False
135 -- Find all ST Refs initialized in this block
149 -- Find all ST Refs initialized in this block
136 findSTRefsIn = everything (++) (mkQ [] isSTRef)
150 findSTRefsIn = everything (++) (mkQ [] isSTRef)
138− isSTRef (JSVariableIntroduction ident (Just (JSApp (JSApp f [_]) []))) | isSTFunc "newSTRef" f = [ident]
152+ isSTRef (JSVariableIntroduction ident (Just (JSApp (JSApp f [_]) []))) | isSTFunc C.newSTRef f = [ident]
139 isSTRef _ = []
153 isSTRef _ = []
140 -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
154 -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
141 findAllSTUsagesIn = everything (++) (mkQ [] isSTUsage)
155 findAllSTUsagesIn = everything (++) (mkQ [] isSTUsage)
143− isSTUsage (JSApp (JSApp f [ref]) []) | isSTFunc "readSTRef" f = [ref]
157+ isSTUsage (JSApp (JSApp f [ref]) []) | isSTFunc C.readSTRef f = [ref]
144− isSTUsage (JSApp (JSApp (JSApp f [ref]) [_]) []) | isSTFunc "writeSTRef" f || isSTFunc "modifySTRef" f = [ref]
158+ isSTUsage (JSApp (JSApp (JSApp f [ref]) [_]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]
145 isSTUsage _ = []
159 isSTUsage _ = []
146 -- Find all uses of a variable
160 -- Find all uses of a variable
147 appearingIn ref = everything (++) (mkQ [] isVar)
161 appearingIn ref = everything (++) (mkQ [] isVar)