@@ -27,7 +27,9 @@
2727--
2828-- * Inlining variables
2929--
30−-- * Inline Prelude.($)
30+-- * Inline Prelude.($), Prelude.(++), Prelude.(!!)
31+--
32+-- * Inlining primitive Javascript operators
3133--
3234-----------------------------------------------------------------------------
3335
@@ -45,13 +47,14 @@ import Language.PureScript.Options
4547import Language.PureScript.CodeGen.Common (identToJs)
4648import Language.PureScript.Sugar.TypeClasses
4749 (mkDictionaryValueName)
48−import Language.PureScript.Types (Type(..))
50+import Language.PureScript.Types
4951
5052-- |
5153-- Apply a series of optimizer passes to simplified Javascript code
5254--
5355optimize :: Options -> JS -> JS
54−optimize opts = untilFixedPoint $ applyAll
56+optimize opts | optionsNoOptimizations opts = id
57+ | otherwise = untilFixedPoint $ applyAll
5558 [ collapseNestedBlocks
5659 , tco opts
5760 , magicDo opts
@@ -59,7 +62,10 @@ optimize opts = untilFixedPoint $ applyAll
5962 , unThunk
6063 , etaConvert
6164 , inlineVariables
62− , inlineDollar ]
65+ , inlineOperator "$" $ \f x -> JSApp f [x]
66+ , inlineOperator "!!" $ flip JSIndexer
67+ , inlineOperator "++" $ JSBinary Add
68+ , inlineCommonOperators ]
6369
6470applyAll :: [a -> a] -> a -> a
6571applyAll = foldl1 (.)
@@ -293,12 +299,71 @@ collapseNestedBlocks = everywhere (mkT collapse)
293299 go (JSBlock sts) = sts
294300 go s = [s]
295301
296−inlineDollar :: JS -> JS
297−inlineDollar = everywhere (mkT convert)
302+inlineOperator :: String -> (JS -> JS -> JS) -> JS -> JS
303+inlineOperator op f = everywhere (mkT convert)
298304 where
299305 convert :: JS -> JS
300− convert (JSApp (JSApp dollar [f]) [x]) | isDollar dollar = JSApp f [x]
306+ convert (JSApp (JSApp op [x]) [y]) | isOp op = f x y
301307 convert other = other
302− isDollar (JSAccessor "$dollar" (JSVar "Prelude")) = True
303− isDollar (JSIndexer (JSStringLiteral "$") (JSVar "Prelude")) = True
304− isDollar _ = False
308+ isOp (JSAccessor longForm (JSVar "Prelude")) | longForm == identToJs (Op op) = True
309+ isOp (JSIndexer (JSStringLiteral op') (JSVar "Prelude")) | op == op' = True
310+ isOp _ = False
311+
312+inlineCommonOperators :: JS -> JS
313+inlineCommonOperators = applyAll
314+ [ binary "+" "Num" tyNumber Add
315+ , binary "-" "Num" tyNumber Subtract
316+ , binary "*" "Num" tyNumber Multiply
317+ , binary "/" "Num" tyNumber Divide
318+ , binary "%" "Num" tyNumber Modulus
319+ , unary "negate" "Num" tyNumber Negate
320+
321+ , binary "<" "Ord" tyNumber LessThan
322+ , binary ">" "Ord" tyNumber GreaterThan
323+ , binary "<=" "Ord" tyNumber LessThanOrEqualTo
324+ , binary ">=" "Ord" tyNumber GreaterThanOrEqualTo
325+
326+ , binary "==" "Eq" tyNumber EqualTo
327+ , binary "/=" "Eq" tyNumber NotEqualTo
328+ , binary "==" "Eq" tyString EqualTo
329+ , binary "/=" "Eq" tyString NotEqualTo
330+ , binary "==" "Eq" tyBoolean EqualTo
331+ , binary "/=" "Eq" tyBoolean NotEqualTo
332+
333+ , binary "<<" "Bits" tyNumber ShiftLeft
334+ , binary ">>" "Bits" tyNumber ShiftRight
335+ , binary ">>>" "Bits" tyNumber ZeroFillShiftRight
336+ , binary "&" "Bits" tyNumber BitwiseAnd
337+ , binary "|" "Bits" tyNumber BitwiseOr
338+ , binary "^" "Bits" tyNumber BitwiseXor
339+ , unary "complement" "Bits" tyNumber BitwiseNot
340+
341+ , binary "&&" "BoolLike" tyBoolean And
342+ , binary "||" "BoolLike" tyBoolean Or
343+ , unary "not" "BoolLike" tyBoolean Not
344+ ]
345+ where
346+ binary :: String -> String -> Type -> BinaryOperator -> JS -> JS
347+ binary opString className classTy op = everywhere (mkT convert)
348+ where
349+ convert :: JS -> JS
350+ convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isOp fn && isOpDict className classTy dict = JSBinary op x y
351+ convert other = other
352+ isOp (JSAccessor longForm (JSVar "Prelude")) | longForm == identToJs (Op opString) = True
353+ isOp (JSIndexer (JSStringLiteral op') (JSVar "Prelude")) | opString == op' = True
354+ isOp _ = False
355+ unary :: String -> String -> Type -> UnaryOperator -> JS -> JS
356+ unary fnName className classTy op = everywhere (mkT convert)
357+ where
358+ convert :: JS -> JS
359+ convert (JSApp (JSApp fn [dict]) [x]) | isOp fn && isOpDict className classTy dict = JSUnary op x
360+ convert other = other
361+ isOp (JSAccessor fnName' (JSVar "Prelude")) | fnName' == fnName = True
362+ isOp _ = False
363+ isOpDict className ty (JSAccessor prop (JSVar "Prelude")) | prop == dictName = True
364+ where
365+ Right (Ident dictName) = mkDictionaryValueName
366+ (ModuleName (ProperName "Prelude"))
367+ (Qualified (Just (ModuleName (ProperName "Prelude"))) (ProperName className))
368+ ty
369+ isOpDict _ _ _ = False