@@ -6,6 +6,7 @@ module Language.PureScript.CodeGen.JS.Optimizer.Inliner
6 , inlineCommonValues
6 , inlineCommonValues
7 , inlineCommonOperators
7 , inlineCommonOperators
8 , inlineFnComposition
8 , inlineFnComposition
9 , etaConvert
10 , etaConvert
11 , evaluateIifes
12 , evaluateIifes
@@ -17,9 +18,11 @@ import Control.Monad.Supply.Class (MonadSupply, freshName)
18import Data.Maybe (fromMaybe)
19import Data.Maybe (fromMaybe)
19import Data.Monoid ((<>))
20import Data.Monoid ((<>))
21+import Data.String (IsString, fromString)
20import Data.Text (Text)
22import Data.Text (Text)
21import qualified Data.Text as T
23import qualified Data.Text as T
25+import Language.PureScript.PSString (PSString)
23import Language.PureScript.CodeGen.JS.AST
26import Language.PureScript.CodeGen.JS.AST
24import Language.PureScript.CodeGen.JS.Optimizer.Common
27import Language.PureScript.CodeGen.JS.Optimizer.Common
25import qualified Language.PureScript.Constants as C
28import qualified Language.PureScript.Constants as C
@@ -33,7 +36,6 @@ shouldInline (JSVar _ _) = True
33shouldInline (JSNumericLiteral _ _) = True
36shouldInline (JSNumericLiteral _ _) = True
34shouldInline (JSStringLiteral _ _) = True
37shouldInline (JSStringLiteral _ _) = True
35shouldInline (JSBooleanLiteral _ _) = True
38shouldInline (JSBooleanLiteral _ _) = True
36−shouldInline (JSAccessor _ _ val) = shouldInline val
37shouldInline (JSIndexer _ index val) = shouldInline index && shouldInline val
39shouldInline (JSIndexer _ index val) = shouldInline index && shouldInline val
38shouldInline _ = False
40shouldInline _ = False
@@ -65,6 +67,8 @@ evaluateIifes = everywhereOnJS convert
66 convert :: JS -> JS
68 convert :: JS -> JS
67 convert (JSApp _ (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ ret])) []) = ret
69 convert (JSApp _ (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ ret])) []) = ret
70+ convert (JSApp _ (JSFunction _ Nothing idents (JSBlock _ [JSReturn ss ret])) [])
71+ | not (any (`isReassigned` ret) idents) = replaceIdents (map (, JSVar ss C.undefined) idents) ret
68 convert js = js
72 convert js = js
70inlineVariables :: JS -> JS
74inlineVariables :: JS -> JS
@@ -82,15 +86,17 @@ inlineCommonValues = everywhereOnJS convert
83 convert :: JS -> JS
87 convert :: JS -> JS
84 convert (JSApp ss fn [dict])
88 convert (JSApp ss fn [dict])
85− | isDict' [semiringNumber, semiringInt] dict && isFn fnZero fn = JSNumericLiteral ss (Left 0)
89+ | isDict' [semiringNumber, semiringInt] dict && isDict fnZero fn = JSNumericLiteral ss (Left 0)
86− | isDict' [semiringNumber, semiringInt] dict && isFn fnOne fn = JSNumericLiteral ss (Left 1)
90+ | isDict' [semiringNumber, semiringInt] dict && isDict fnOne fn = JSNumericLiteral ss (Left 1)
87− | isDict boundedBoolean dict && isFn fnBottom fn = JSBooleanLiteral ss False
91+ | isDict boundedBoolean dict && isDict fnBottom fn = JSBooleanLiteral ss False
88− | isDict boundedBoolean dict && isFn fnTop fn = JSBooleanLiteral ss True
92+ | isDict boundedBoolean dict && isDict fnTop fn = JSBooleanLiteral ss True
93+ convert (JSApp ss (JSApp _ fn [dict]) [x])
94+ | isDict ringInt dict && isDict fnNegate fn = JSBinary ss BitwiseOr (JSUnary ss Negate x) (JSNumericLiteral ss (Left 0))
89 convert (JSApp ss (JSApp _ (JSApp _ fn [dict]) [x]) [y])
95 convert (JSApp ss (JSApp _ (JSApp _ fn [dict]) [x]) [y])
90− | isDict semiringInt dict && isFn fnAdd fn = intOp ss Add x y
96+ | isDict semiringInt dict && isDict fnAdd fn = intOp ss Add x y
91− | isDict semiringInt dict && isFn fnMultiply fn = intOp ss Multiply x y
97+ | isDict semiringInt dict && isDict fnMultiply fn = intOp ss Multiply x y
92− | isDict euclideanRingInt dict && isFn fnDivide fn = intOp ss Divide x y
98+ | isDict euclideanRingInt dict && isDict fnDivide fn = intOp ss Divide x y
93− | isDict ringInt dict && isFn fnSubtract fn = intOp ss Subtract x y
99+ | isDict ringInt dict && isDict fnSubtract fn = intOp ss Subtract x y
94 convert other = other
100 convert other = other
95 fnZero = (C.dataSemiring, C.zero)
101 fnZero = (C.dataSemiring, C.zero)
96 fnOne = (C.dataSemiring, C.one)
102 fnOne = (C.dataSemiring, C.one)
@@ -100,6 +106,7 @@ inlineCommonValues = everywhereOnJS convert
100 fnDivide = (C.dataEuclideanRing, C.div)
106 fnDivide = (C.dataEuclideanRing, C.div)
101 fnMultiply = (C.dataSemiring, C.mul)
107 fnMultiply = (C.dataSemiring, C.mul)
102 fnSubtract = (C.dataRing, C.sub)
108 fnSubtract = (C.dataRing, C.sub)
109+ fnNegate = (C.dataRing, C.negate)
103 intOp ss op x y = JSBinary ss BitwiseOr (JSBinary ss op x y) (JSNumericLiteral ss (Left 0))
110 intOp ss op x y = JSBinary ss BitwiseOr (JSBinary ss op x y) (JSNumericLiteral ss (Left 0))
105inlineCommonOperators :: JS -> JS
112inlineCommonOperators :: JS -> JS
@@ -109,8 +116,6 @@ inlineCommonOperators = applyAll $
110 , binary ringNumber opSub Subtract
117 , binary ringNumber opSub Subtract
111 , unary ringNumber opNegate Negate
118 , unary ringNumber opNegate Negate
112− , binary ringInt opSub Subtract
113− , unary ringInt opNegate Negate
115 , binary euclideanRingNumber opDiv Divide
120 , binary euclideanRingNumber opDiv Divide
116 , binary euclideanRingInt opMod Modulus
121 , binary euclideanRingInt opMod Modulus
@@ -167,29 +172,29 @@ inlineCommonOperators = applyAll $
168 [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ]
173 [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ]
170− binary :: (Text, Text) -> (Text, Text) -> BinaryOperator -> JS -> JS
175+ binary :: (Text, PSString) -> (Text, PSString) -> BinaryOperator -> JS -> JS
171 binary dict fns op = everywhereOnJS convert
176 binary dict fns op = everywhereOnJS convert
173 convert :: JS -> JS
178 convert :: JS -> JS
174− convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y]) | isDict dict dict' && isFn fns fn = JSBinary ss op x y
179+ convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y]) | isDict dict dict' && isDict fns fn = JSBinary ss op x y
175 convert other = other
180 convert other = other
176− binary' :: Text -> Text -> BinaryOperator -> JS -> JS
181+ binary' :: Text -> PSString -> BinaryOperator -> JS -> JS
177 binary' moduleName opString op = everywhereOnJS convert
182 binary' moduleName opString op = everywhereOnJS convert
179 convert :: JS -> JS
184 convert :: JS -> JS
180− convert (JSApp ss (JSApp _ fn [x]) [y]) | isFn (moduleName, opString) fn = JSBinary ss op x y
185+ convert (JSApp ss (JSApp _ fn [x]) [y]) | isDict (moduleName, opString) fn = JSBinary ss op x y
181 convert other = other
186 convert other = other
182− unary :: (Text, Text) -> (Text, Text) -> UnaryOperator -> JS -> JS
187+ unary :: (Text, PSString) -> (Text, PSString) -> UnaryOperator -> JS -> JS
183 unary dicts fns op = everywhereOnJS convert
188 unary dicts fns op = everywhereOnJS convert
185 convert :: JS -> JS
190 convert :: JS -> JS
186− convert (JSApp ss (JSApp _ fn [dict']) [x]) | isDict dicts dict' && isFn fns fn = JSUnary ss op x
191+ convert (JSApp ss (JSApp _ fn [dict']) [x]) | isDict dicts dict' && isDict fns fn = JSUnary ss op x
187 convert other = other
192 convert other = other
188− unary' :: Text -> Text -> UnaryOperator -> JS -> JS
193+ unary' :: Text -> PSString -> UnaryOperator -> JS -> JS
189 unary' moduleName fnName op = everywhereOnJS convert
194 unary' moduleName fnName op = everywhereOnJS convert
191 convert :: JS -> JS
196 convert :: JS -> JS
192− convert (JSApp ss fn [x]) | isFn (moduleName, fnName) fn = JSUnary ss op x
197+ convert (JSApp ss fn [x]) | isDict (moduleName, fnName) fn = JSUnary ss op x
193 convert other = other
198 convert other = other
194 mkFn :: Int -> JS -> JS
199 mkFn :: Int -> JS -> JS
195 mkFn 0 = everywhereOnJS convert
200 mkFn 0 = everywhereOnJS convert
@@ -213,7 +218,8 @@ inlineCommonOperators = applyAll $
214 isNFn :: Text -> Int -> JS -> Bool
219 isNFn :: Text -> Int -> JS -> Bool
215 isNFn prefix n (JSVar _ name) = name == (prefix <> T.pack (show n))
220 isNFn prefix n (JSVar _ name) = name == (prefix <> T.pack (show n))
216− isNFn prefix n (JSAccessor _ name (JSVar _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried = name == (prefix <> T.pack (show n))
221+ isNFn prefix n (JSIndexer _ (JSStringLiteral _ name) (JSVar _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried =
222+ name == fromString (T.unpack prefix <> show n)
217 isNFn _ _ _ = False
223 isNFn _ _ _ = False
219 runFn :: Int -> JS -> JS
225 runFn :: Int -> JS -> JS
@@ -234,20 +240,21 @@ inlineCommonOperators = applyAll $
234 convert (JSApp _ (JSApp _ op' [x]) [y]) | p op' = f x y
240 convert (JSApp _ (JSApp _ op' [x]) [y]) | p op' = f x y
235 convert other = other
241 convert other = other
237− isModFn :: (Text, Text) -> JS -> Bool
243+ isModFn :: (Text, PSString) -> JS -> Bool
238− isModFn (m, op) (JSAccessor _ op' (JSVar _ m')) = m == m' && op == op'
244+ isModFn (m, op) (JSIndexer _ (JSStringLiteral _ op') (JSVar _ m')) =
245+ m == m' && op == op'
239 isModFn _ _ = False
246 isModFn _ _ = False
241− isModFnWithDict :: (Text, Text) -> JS -> Bool
248+ isModFnWithDict :: (Text, PSString) -> JS -> Bool
242− isModFnWithDict (m, op) (JSApp _ (JSAccessor _ op' (JSVar _ m')) [JSVar _ _]) = m == m' && op == op'
249+ isModFnWithDict (m, op) (JSApp _ (JSIndexer _ (JSStringLiteral _ op') (JSVar _ m')) [JSVar _ _]) =
250+ m == m' && op == op'
243 isModFnWithDict _ _ = False
251 isModFnWithDict _ _ = False
245-- (f <<< g $ x) = f (g x)
253-- (f <<< g $ x) = f (g x)
246-- (f <<< g) = \x -> f (g x)
254-- (f <<< g) = \x -> f (g x)
247−inlineFnComposition :: (MonadSupply m) => JS -> m JS
255+inlineFnComposition :: forall m. MonadSupply m => JS -> m JS
248−inlineFnComposition = everywhereOnJSTopDownM convert
256+inlineFnComposition = everywhereOnJSTopDownM convert where
250− convert :: (MonadSupply m) => JS -> m JS
257+ convert :: JS -> m JS
251 convert (JSApp s1 (JSApp s2 (JSApp _ (JSApp _ fn [dict']) [x]) [y]) [z])
258 convert (JSApp s1 (JSApp s2 (JSApp _ (JSApp _ fn [dict']) [x]) [y]) [z])
252 | isFnCompose dict' fn = return $ JSApp s1 x [JSApp s2 y [z]]
259 | isFnCompose dict' fn = return $ JSApp s1 x [JSApp s2 y [z]]
253 | isFnComposeFlipped dict' fn = return $ JSApp s2 y [JSApp s1 x [z]]
260 | isFnComposeFlipped dict' fn = return $ JSApp s2 y [JSApp s1 x [z]]
@@ -260,118 +267,127 @@ inlineFnComposition = everywhereOnJSTopDownM convert
260 return $ JSFunction ss Nothing [arg] (JSBlock ss [JSReturn Nothing $ JSApp Nothing y [JSApp Nothing x [JSVar Nothing arg]]])
267 return $ JSFunction ss Nothing [arg] (JSBlock ss [JSReturn Nothing $ JSApp Nothing y [JSApp Nothing x [JSVar Nothing arg]]])
261 convert other = return other
268 convert other = return other
262 isFnCompose :: JS -> JS -> Bool
269 isFnCompose :: JS -> JS -> Bool
263− isFnCompose dict' fn = isDict semigroupoidFn dict' && isFn fnCompose fn
270+ isFnCompose dict' fn = isDict semigroupoidFn dict' && isDict fnCompose fn
264 isFnComposeFlipped :: JS -> JS -> Bool
271 isFnComposeFlipped :: JS -> JS -> Bool
265− isFnComposeFlipped dict' fn = isDict semigroupoidFn dict' && isFn fnComposeFlipped fn
272+ isFnComposeFlipped dict' fn = isDict semigroupoidFn dict' && isDict fnComposeFlipped fn
266− fnCompose :: (Text, Text)
273+ fnCompose :: forall a b. (IsString a, IsString b) => (a, b)
267 fnCompose = (C.controlSemigroupoid, C.compose)
274 fnCompose = (C.controlSemigroupoid, C.compose)
268− fnComposeFlipped :: (Text, Text)
275+ fnComposeFlipped :: forall a b. (IsString a, IsString b) => (a, b)
269 fnComposeFlipped = (C.controlSemigroupoid, C.composeFlipped)
276 fnComposeFlipped = (C.controlSemigroupoid, C.composeFlipped)
278+inlineUnsafePartial :: JS -> JS
279+inlineUnsafePartial = everywhereOnJSTopDown convert where
280+ convert (JSApp ss (JSIndexer _ (JSStringLiteral _ unsafePartial) (JSVar _ partialUnsafe)) [ comp ])
281+ | unsafePartial == C.unsafePartial && partialUnsafe == C.partialUnsafe
282+ -- Apply to undefined here, the application should be optimized away
283+ -- if it is safe to do so
284+ = JSApp ss comp [ JSVar ss C.undefined ]
285+ convert other = other
271−semiringNumber :: (Text, Text)
287+semiringNumber :: forall a b. (IsString a, IsString b) => (a, b)
272semiringNumber = (C.dataSemiring, C.semiringNumber)
288semiringNumber = (C.dataSemiring, C.semiringNumber)
274−semiringInt :: (Text, Text)
290+semiringInt :: forall a b. (IsString a, IsString b) => (a, b)
275semiringInt = (C.dataSemiring, C.semiringInt)
291semiringInt = (C.dataSemiring, C.semiringInt)
277−ringNumber :: (Text, Text)
293+ringNumber :: forall a b. (IsString a, IsString b) => (a, b)
278ringNumber = (C.dataRing, C.ringNumber)
294ringNumber = (C.dataRing, C.ringNumber)
280−ringInt :: (Text, Text)
296+ringInt :: forall a b. (IsString a, IsString b) => (a, b)
281ringInt = (C.dataRing, C.ringInt)
297ringInt = (C.dataRing, C.ringInt)
283−euclideanRingNumber :: (Text, Text)
299+euclideanRingNumber :: forall a b. (IsString a, IsString b) => (a, b)
284euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)
300euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)
286−euclideanRingInt :: (Text, Text)
302+euclideanRingInt :: forall a b. (IsString a, IsString b) => (a, b)
287euclideanRingInt = (C.dataEuclideanRing, C.euclideanRingInt)
303euclideanRingInt = (C.dataEuclideanRing, C.euclideanRingInt)
289−eqNumber :: (Text, Text)
305+eqNumber :: forall a b. (IsString a, IsString b) => (a, b)
290eqNumber = (C.dataEq, C.eqNumber)
306eqNumber = (C.dataEq, C.eqNumber)
292−eqInt :: (Text, Text)
308+eqInt :: forall a b. (IsString a, IsString b) => (a, b)
293eqInt = (C.dataEq, C.eqInt)
309eqInt = (C.dataEq, C.eqInt)
295−eqString :: (Text, Text)
311+eqString :: forall a b. (IsString a, IsString b) => (a, b)
296eqString = (C.dataEq, C.eqString)
312eqString = (C.dataEq, C.eqString)
298−eqChar :: (Text, Text)
314+eqChar :: forall a b. (IsString a, IsString b) => (a, b)
299eqChar = (C.dataEq, C.eqChar)
315eqChar = (C.dataEq, C.eqChar)
301−eqBoolean :: (Text, Text)
317+eqBoolean :: forall a b. (IsString a, IsString b) => (a, b)
302eqBoolean = (C.dataEq, C.eqBoolean)
318eqBoolean = (C.dataEq, C.eqBoolean)
304−ordBoolean :: (Text, Text)
320+ordBoolean :: forall a b. (IsString a, IsString b) => (a, b)
305ordBoolean = (C.dataOrd, C.ordBoolean)
321ordBoolean = (C.dataOrd, C.ordBoolean)
307−ordNumber :: (Text, Text)
323+ordNumber :: forall a b. (IsString a, IsString b) => (a, b)
308ordNumber = (C.dataOrd, C.ordNumber)
324ordNumber = (C.dataOrd, C.ordNumber)
310−ordInt :: (Text, Text)
326+ordInt :: forall a b. (IsString a, IsString b) => (a, b)
311ordInt = (C.dataOrd, C.ordInt)
327ordInt = (C.dataOrd, C.ordInt)
313−ordString :: (Text, Text)
329+ordString :: forall a b. (IsString a, IsString b) => (a, b)
314ordString = (C.dataOrd, C.ordString)
330ordString = (C.dataOrd, C.ordString)
316−ordChar :: (Text, Text)
332+ordChar :: forall a b. (IsString a, IsString b) => (a, b)
317ordChar = (C.dataOrd, C.ordChar)
333ordChar = (C.dataOrd, C.ordChar)
319−semigroupString :: (Text, Text)
335+semigroupString :: forall a b. (IsString a, IsString b) => (a, b)
320semigroupString = (C.dataSemigroup, C.semigroupString)
336semigroupString = (C.dataSemigroup, C.semigroupString)
322−boundedBoolean :: (Text, Text)
338+boundedBoolean :: forall a b. (IsString a, IsString b) => (a, b)
323boundedBoolean = (C.dataBounded, C.boundedBoolean)
339boundedBoolean = (C.dataBounded, C.boundedBoolean)
325−heytingAlgebraBoolean :: (Text, Text)
341+heytingAlgebraBoolean :: forall a b. (IsString a, IsString b) => (a, b)
326heytingAlgebraBoolean = (C.dataHeytingAlgebra, C.heytingAlgebraBoolean)
342heytingAlgebraBoolean = (C.dataHeytingAlgebra, C.heytingAlgebraBoolean)
328−semigroupoidFn :: (Text, Text)
344+semigroupoidFn :: forall a b. (IsString a, IsString b) => (a, b)
329semigroupoidFn = (C.controlSemigroupoid, C.semigroupoidFn)
345semigroupoidFn = (C.controlSemigroupoid, C.semigroupoidFn)
331−opAdd :: (Text, Text)
347+opAdd :: forall a b. (IsString a, IsString b) => (a, b)
332opAdd = (C.dataSemiring, C.add)
348opAdd = (C.dataSemiring, C.add)
334−opMul :: (Text, Text)
350+opMul :: forall a b. (IsString a, IsString b) => (a, b)
335opMul = (C.dataSemiring, C.mul)
351opMul = (C.dataSemiring, C.mul)
337−opEq :: (Text, Text)
353+opEq :: forall a b. (IsString a, IsString b) => (a, b)
338opEq = (C.dataEq, C.eq)
354opEq = (C.dataEq, C.eq)
340−opNotEq :: (Text, Text)
356+opNotEq :: forall a b. (IsString a, IsString b) => (a, b)
341opNotEq = (C.dataEq, C.notEq)
357opNotEq = (C.dataEq, C.notEq)
343−opLessThan :: (Text, Text)
359+opLessThan :: forall a b. (IsString a, IsString b) => (a, b)
344opLessThan = (C.dataOrd, C.lessThan)
360opLessThan = (C.dataOrd, C.lessThan)
346−opLessThanOrEq :: (Text, Text)
362+opLessThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)
347opLessThanOrEq = (C.dataOrd, C.lessThanOrEq)
363opLessThanOrEq = (C.dataOrd, C.lessThanOrEq)
349−opGreaterThan :: (Text, Text)
365+opGreaterThan :: forall a b. (IsString a, IsString b) => (a, b)
350opGreaterThan = (C.dataOrd, C.greaterThan)
366opGreaterThan = (C.dataOrd, C.greaterThan)
352−opGreaterThanOrEq :: (Text, Text)
368+opGreaterThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)
353opGreaterThanOrEq = (C.dataOrd, C.greaterThanOrEq)
369opGreaterThanOrEq = (C.dataOrd, C.greaterThanOrEq)
355−opAppend :: (Text, Text)
371+opAppend :: forall a b. (IsString a, IsString b) => (a, b)
356opAppend = (C.dataSemigroup, C.append)
372opAppend = (C.dataSemigroup, C.append)
358−opSub :: (Text, Text)
374+opSub :: forall a b. (IsString a, IsString b) => (a, b)
359opSub = (C.dataRing, C.sub)
375opSub = (C.dataRing, C.sub)
361−opNegate :: (Text, Text)
377+opNegate :: forall a b. (IsString a, IsString b) => (a, b)
362opNegate = (C.dataRing, C.negate)
378opNegate = (C.dataRing, C.negate)
364−opDiv :: (Text, Text)
380+opDiv :: forall a b. (IsString a, IsString b) => (a, b)
365opDiv = (C.dataEuclideanRing, C.div)
381opDiv = (C.dataEuclideanRing, C.div)
367−opMod :: (Text, Text)
383+opMod :: forall a b. (IsString a, IsString b) => (a, b)
368opMod = (C.dataEuclideanRing, C.mod)
384opMod = (C.dataEuclideanRing, C.mod)
370−opConj :: (Text, Text)
386+opConj :: forall a b. (IsString a, IsString b) => (a, b)
371opConj = (C.dataHeytingAlgebra, C.conj)
387opConj = (C.dataHeytingAlgebra, C.conj)
373−opDisj :: (Text, Text)
389+opDisj :: forall a b. (IsString a, IsString b) => (a, b)
374opDisj = (C.dataHeytingAlgebra, C.disj)
390opDisj = (C.dataHeytingAlgebra, C.disj)
376−opNot :: (Text, Text)
392+opNot :: forall a b. (IsString a, IsString b) => (a, b)
377opNot = (C.dataHeytingAlgebra, C.not)
393opNot = (C.dataHeytingAlgebra, C.not)