packages feed

zephyr-0.1.1.0: test/TestDCECoreFn.hs

module TestDCECoreFn (main) where

import Prelude ()
import Prelude.Compat

import Data.List (concatMap)

import Language.PureScript.AST.Literals
import Language.PureScript.AST.SourcePos
import Language.PureScript.CoreFn
import Language.PureScript.DCE
import Language.PureScript.Names
import Language.PureScript.PSString

import Test.Hspec

main :: IO ()
main = hspec spec

getNames :: Bind a -> [Ident]
getNames (NonRec _ i _) = [i]
getNames (Rec l) = (\((_, i), _) -> i) `map` l

hasIdent :: Ident -> [Bind Ann] -> Bool
hasIdent i = (i `elem`) . concatMap getNames

ann :: Ann
ann = ssAnn (SourceSpan "src/Test.purs" (SourcePos 0 0) (SourcePos 0 0))

spec :: Spec
spec =
  context "dceExpr" $ do
    specify "should remove unused identifier" $ do
      let e :: Expr Ann
          e = Let ann
                [ NonRec ann (Ident "notUsed") (Literal ann (CharLiteral 'a'))
                , NonRec ann (Ident "used") (Literal ann (CharLiteral 'b'))
                ]
                (Var ann (Qualified Nothing (Ident "used")))
      case dceExpr (NonRec ann (Ident "v") e) of
        NonRec _ _ (Let _ bs _) -> do
          bs `shouldSatisfy` not . hasIdent (Ident "notUsed")
          bs `shouldSatisfy` hasIdent (Ident "used")
        _ -> return ()

    specify "should not remove transitive dependency" $ do
      let e :: Expr Ann
          e = Let ann
                [ NonRec ann (Ident "used") (Abs ann (Ident "x") (Var ann (Qualified Nothing (Ident "trDep"))))
                , NonRec ann (Ident "trDep") (Literal ann (CharLiteral 'a'))
                ]
                (Var ann (Qualified Nothing (Ident "used")))
      case dceExpr (NonRec ann (Ident "v") e) of
        NonRec _ _ (Let _ bs _) -> do
          bs `shouldSatisfy` hasIdent (Ident "trDep")
          bs `shouldSatisfy` hasIdent (Ident "used")
        _ -> return ()

    specify "should include all used recursive binds" $ do
      let e :: Expr Ann
          e = Let ann
                [ NonRec ann (Ident "entry") (Abs ann (Ident "x") (Var ann (Qualified Nothing (Ident "mutDep1"))))
                , Rec
                  [ ((ann, Ident "mutDep1"), Abs ann (Ident "x") (Var ann (Qualified Nothing (Ident "mutDep2"))))
                  , ((ann, Ident "mutDep2"), Abs ann (Ident "x") (Var ann (Qualified Nothing (Ident "mutDep1"))))
                  ]
                ]
                (App ann (Var ann (Qualified Nothing (Ident "entry"))) (Literal ann (CharLiteral 'a')))
      case dceExpr (NonRec ann (Ident "v") e) of
        NonRec _ _ (Let _ bs _) -> do
          bs `shouldSatisfy` hasIdent (Ident "entry")
          bs `shouldSatisfy` hasIdent (Ident "mutDep1")
          bs `shouldSatisfy` hasIdent (Ident "mutDep2")
        _ -> return ()

    specify "should dce case expressions" $ do
      let e :: Expr Ann
          e = Let ann
                [ NonRec ann (Ident "usedInExpr") (Literal ann (CharLiteral 'a'))
                , NonRec ann (Ident "notUsed") (Literal ann (CharLiteral 'a'))
                , NonRec ann (Ident "usedInGuard") (Literal ann (CharLiteral 'a'))
                , NonRec ann (Ident "usedInResult1") (Literal ann (CharLiteral 'a'))
                , NonRec ann (Ident "usedInResult2") (Literal ann (CharLiteral 'a'))
                ]
                (Case ann
                  [Var ann (Qualified Nothing (Ident "usedInExpr"))]
                  [ CaseAlternative
                      [NullBinder ann]
                      (Left
                        [ ( Var ann (Qualified Nothing (Ident "usedInGuard"))
                          , Var ann (Qualified Nothing (Ident "usedInResult1"))
                          )
                        ])
                  , CaseAlternative
                      [NullBinder ann]
                      (Right $ Var ann (Qualified Nothing (Ident "usedInResult2")))
                  ])
      case dceExpr (NonRec ann (Ident "v") e) of
        NonRec _ _ (Let _ bs _) -> do
          bs `shouldSatisfy` hasIdent (Ident "usedInExpr")
          bs `shouldSatisfy` not . hasIdent (Ident "notUsed")
          bs `shouldSatisfy` hasIdent (Ident "usedInGuard")
          bs `shouldSatisfy` hasIdent (Ident "usedInResult1")
          bs `shouldSatisfy` hasIdent (Ident "usedInResult2")
        _ -> return ()

    specify "should not remove shadowed identifiers" $ do
      let e :: Expr Ann
          e = Let ann
                [ NonRec ann (Ident "shadow") (Literal ann (CharLiteral 'a'))
                , NonRec ann (Ident "sunny") (Literal ann (CharLiteral 'a'))
                ]
                $ Let ann
                  [ NonRec ann (Ident "shadow") (Literal ann (CharLiteral 'a')) ]
                  $ Literal ann
                    $ ObjectLiteral 
                      [ ( mkString "a", Var ann (Qualified Nothing (Ident "shadow")) )
                      , ( mkString "b", Var ann (Qualified Nothing (Ident "sunny")) )
                      ]
      case dceExpr (NonRec ann (Ident "v") e) of
        NonRec _ _ (Let _ bs (Let _ cs _)) -> do
          bs `shouldSatisfy` hasIdent (Ident "sunny")
          bs `shouldSatisfy` not . hasIdent (Ident "shadow")
          cs `shouldSatisfy` hasIdent (Ident "shadow")
        _ -> undefined