packages feed

fortran-src-0.3.0: test/Language/Fortran/Analysis/RenamingSpec.hs

module Language.Fortran.Analysis.RenamingSpec (spec) where

import Test.Hspec
import TestUtil

import Data.Map (elems)
--import Data.Data (Data)
import qualified Data.Map as M

import Language.Fortran.ParserMonad
import Language.Fortran.AST
import qualified Language.Fortran.Parser.Fortran90 as F90
import Language.Fortran.Analysis
import Language.Fortran.Analysis.Renaming
import Data.Generics.Uniplate.Data
import qualified Data.ByteString.Char8 as B

--testF90 :: Data a => ProgramFile a -> ProgramFile (Analysis a)
--testF90 pf = (resetSrcSpan . analyseRenames . initAnalysis) $ pf
extractNameMap' :: ProgramFile () -> M.Map String String
extractNameMap' = extractNameMap . analyseRenames . initAnalysis
unrename' :: ProgramFile () -> ProgramFile ()
unrename' = stripAnalysis . unrename . rename . analyseRenames . initAnalysis
--renameAndStrip' :: Data a => ProgramFile a -> ProgramFile a
--renameAndStrip' x = stripAnalysis . rename . analyseRenames . initAnalysis $ x

countUnrenamed :: ProgramFile (Analysis ()) -> Int
countUnrenamed e = length [ () | ExpValue Analysis { uniqueName = Nothing } _ ValVariable {} <- uniE_PF e ]
  where uniE_PF :: ProgramFile (Analysis ()) -> [Expression (Analysis ())]
        uniE_PF = universeBi

fortran90Parser :: String -> String -> ProgramFile A0
fortran90Parser src file = fromParseResultUnsafe $ F90.fortran90Parser (B.pack src) file

spec :: Spec
spec = do
  describe "Basic" $ do
    it "num-entries 1" $ do
      let entry = extractNameMap' ex3
      shouldBe ( length (filter (=="f1") (elems entry))
               , length (filter (=="a") (elems entry))
               , length (filter (=="b") (elems entry))
               , length (filter (=="d") (elems entry)) )
               ( 1, 2, 2, 2 )

    -- Test that every symbol that is supposed to be renamed is renamed.
    it "complete ex1" $
      countUnrenamed (analyseRenames . initAnalysis $ ex1) `shouldBe` 0
    it "complete ex2" $
      countUnrenamed (analyseRenames . initAnalysis $ ex2) `shouldBe` 0
    it "complete ex3" $
      countUnrenamed (analyseRenames . initAnalysis $ ex3) `shouldBe` 0
    it "complete ex4" $
      countUnrenamed (analyseRenames . initAnalysis $ ex4) `shouldBe` 0
    it "complete ex5" $
      countUnrenamed (analyseRenames . initAnalysis $ ex5) `shouldBe` 0
    it "complete ex6" $
      countUnrenamed (analyseRenames . initAnalysis $ ex6) `shouldBe` 0
    it "complete ex8" $
      countUnrenamed (analyseRenames . initAnalysis $ ex8) `shouldBe` 0
    it "complete ex9" $
      countUnrenamed (analyseRenames . initAnalysis $ ex9) `shouldBe` 0
    it "complete ex10" $
      countUnrenamed (analyseRenames . initAnalysis $ ex10) `shouldBe` 0
    it "complete ex11" $
      countUnrenamed (analyseRenames . initAnalysis $ ex11) `shouldBe` 0
    it "complete ex12" $
      countUnrenamed (analyseRenames . initAnalysis $ ex12) `shouldBe` 0
    it "complete ex13" $
      countUnrenamed (analyseRenames . initAnalysis $ ex13Renames) `shouldBe` 0

    it "complete exScope1" $
      countUnrenamed (analyseRenames . initAnalysis $ exScope1) `shouldBe` 0
    it "complete exScope2" $
      countUnrenamed (analyseRenames . initAnalysis $ exScope2) `shouldBe` 0

    it "functions 1" $ do
      let entry = extractNameMap' ex3
      length (filter (=="f1") (elems entry)) `shouldBe'` 1

  describe "Identity" $ do
    it "unrename-rename 1" $ do
      let entry = unrename' ex1
      entry `shouldBe'` ex1

    it "unrename-rename 2" $ do
      let entry = unrename' ex2
      entry `shouldBe'` ex2

    it "unrename-rename 3" $ do
      let entry = unrename' ex3
      entry `shouldBe'` ex3

    it "unrename-rename 4" $ do
      let entry = unrename' ex4
      entry `shouldBe'` ex4

  describe "Shadowing" $ do
    it "exScope1 testing non-shadowing of subprogram names" $ do
      let entry = extractNameMap' exScope1
      let keys = M.keys entry
      length keys `shouldBe` 1

    it "exScope2 testing shadowing of variables" $ do
      let entry = extractNameMap' exScope2
      length (filter (=="x") (elems entry)) `shouldBe` 2

  describe "Ordering" $
    it "exScope3 testing out-of-order definitions" $ do
      let entry = extractNameMap' exScope3
      length (filter (=="f1") (elems entry)) `shouldBe` 1
      length (filter (=="f2") (elems entry)) `shouldBe` 1
      length (filter (=="s1") (elems entry)) `shouldBe` 1
      length (filter (=="s2") (elems entry)) `shouldBe` 1

  describe "Common blocks" $
    it "common1" $ do
      let entry = extractNameMap' common1
      length (filter (=="x") (elems entry)) `shouldBe` 2
      M.lookup "c_x_common" entry `shouldBe` Just "x"
      M.lookup "c_y_common" entry `shouldBe` Just "y"

--------------------------------------------------

ex1 :: ProgramFile ()
ex1 = ProgramFile mi77 [ ex1pu1 ]
ex1pu1 :: ProgramUnit ()
ex1pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" Nothing Nothing [] Nothing

ex2 :: ProgramFile ()
ex2 = ProgramFile mi77 [ ex2pu1 ]
ex2pu1 :: ProgramUnit ()
ex2pu1 = PUMain () u (Just "main") ex2pu1bs Nothing
ex2pu1bs :: [Block ()]
ex2pu1bs =
  [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u
      [ DeclVariable () u (varGen "a") Nothing Nothing
      , DeclArray () u (varGen "b") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 1) ]) Nothing Nothing
      , DeclVariable () u (varGen "c") Nothing Nothing
      , DeclVariable () u (varGen "d") Nothing Nothing ]))
  , BlStatement () u Nothing (StDimension () u (AList () u
      [ DeclArray () u (varGen "a") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 1 ) ]) Nothing Nothing ]))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "a") (AList () u [ ixSinGen 1 ])) (intGen 1))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "b") (AList () u [ ixSinGen 1 ])) (intGen 1))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "c") (AList () u [ ixSinGen 1 ])) (intGen 1))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "d") (AList () u [ ixSinGen 1 ])) (intGen 1)) ]

ex3 :: ProgramFile ()
ex3 = ProgramFile mi77 [ ex3pu1, ex3pu2 ]
ex3pu1 :: ProgramUnit ()
ex3pu1 = PUMain () u (Just "main") ex3pu1bs Nothing
ex3pu1bs :: [Block ()]
ex3pu1bs =
  [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u
      [ DeclVariable () u (varGen "a") Nothing Nothing
      , DeclArray () u (varGen "b") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 1) ]) Nothing Nothing
      , DeclVariable () u (varGen "c") Nothing Nothing
      , DeclVariable () u (varGen "d") Nothing Nothing ]))
  , BlStatement () u Nothing (StDimension () u (AList () u
      [ DeclArray () u (varGen "a") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 1 ) ]) Nothing Nothing ]))
  , BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u
      [ DeclVariable () u (varGen "c") Nothing Nothing ]))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "a") (AList () u [ ixSinGen 1 ])) (intGen 1))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "b") (AList () u [ ixSinGen 1 ])) (intGen 1))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpSubscript () u (varGen "c") (AList () u [ ixSinGen 1 ])) (intGen 1))
  , BlStatement () u Nothing (StExpressionAssign () u
      (varGen "d") (ExpBinary () u Addition (varGen "d") (intGen 1))) ]
ex3pu2 :: ProgramUnit ()
ex3pu2 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "d", varGen "b"]) Nothing (ex3pu1bs ++ [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "d")) ]) Nothing

ex4 :: ProgramFile ()
ex4 = ProgramFile mi77 [ ex4pu1, ex4pu2 ]
ex4pu1 :: ProgramUnit ()
ex4pu1 = PUMain () u (Just "main") ex4pu1bs Nothing
ex4pu1bs :: [Block ()]
ex4pu1bs =
  [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u
      [ DeclVariable () u (varGen "f1") Nothing Nothing
      , DeclVariable () u (varGen "r") Nothing Nothing ]))
  , BlStatement () u Nothing (StExpressionAssign () u
      (ExpValue () u (ValVariable "r"))
      (ExpFunctionCall () u (ExpValue () u (ValVariable "f1"))
                            (Just $ AList () u [ Argument () u Nothing $ intGen 1 ]))) ]
ex4pu2 :: ProgramUnit ()
ex4pu2 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "x")) ] Nothing

ex5 :: ProgramFile ()
ex5 = ProgramFile mi77 [ ex5pu1, ex5pu2 ]
ex5pu1 :: ProgramUnit ()
ex5pu1 = PUMain () u (Just "main") ex5pu1bs Nothing
ex5pu1bs :: [a]
ex5pu1bs = []
ex5pu2 :: ProgramUnit ()
ex5pu2 = PUModule () u "ex5mod" ex5pu2bs (Just [ex5pu2pu1])
ex5pu2bs :: [a]
ex5pu2bs = []
ex5pu2pu1 :: ProgramUnit ()
ex5pu2pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "x")) ] Nothing

ex6 :: ProgramFile ()
ex6 = ProgramFile mi77 [ ex6pu1, ex6pu2 ]
ex6pu1 :: ProgramUnit ()
ex6pu1 = PUMain () u (Just "main") ex6pu1bs Nothing
ex6pu1bs :: [a]
ex6pu1bs = []
ex6pu2 :: ProgramUnit ()
ex6pu2 = PUModule () u "ex6mod" ex6pu2bs (Just [ex6pu2pu1])
ex6pu2bs :: [a]
ex6pu2bs = []
ex6pu2pu1 :: ProgramUnit ()
ex6pu2pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (ExpFunctionCall () u (ExpValue () u (ValVariable "f1")) (Just $ AList () u [Argument () u Nothing (varGen "x")]))) ] (Just [ex5pu2pu1])

--parseF90 :: [String] -> ProgramFile A0
--parseF90 = resetSrcSpan . flip fortran90Parser "" . unlines

ex8 :: ProgramFile A0
ex8 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "module m1"
  , "  implicit none"
  , "contains"
  , "  integer function foo ()"
  , "    foo = 0"
  , "  end function foo"
  , "end module m1"
  , ""
  , "module m2"
  , "  implicit none"
  , "contains"
  , "  integer function foo2 (x)"
  , "    use m1"
  , "    integer :: x"
  , "    foo2 = foo () + x"
  , "  end function foo2"
  , "end module m2"
  , ""
  , "module m3"
  , "  implicit none"
  , "contains"
  , "  integer function foo () result (r)"
  , "    r = 1"
  , "  end function foo"
  , "end module m3"
  , ""
  , "program main"
  , "  use m1"
  , "  integer :: x"
  , "  x = foo ()"
  , "end program main"
  ]

ex9 :: ProgramFile A0
ex9 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "module m1"
  , "  implicit none"
  , "  integer :: x"
  , "contains"
  , "  integer function f () result (x)"
  , "    integer :: x"
  , "    x = 0"
  , "  end function f"
  , "  subroutine s ()"
  , "    x = 0"
  , "  end subroutine s"
  , "end module m1"
  ]

ex10 :: ProgramFile ()
ex10 = ProgramFile mi77 [ ex10pu1 ]
ex10pu1 :: ProgramUnit ()
ex10pu1 = PUSubroutine () u emptyPrefixSuffix "s1" Nothing ex10pu1bs Nothing
ex10pu1bs :: [Block ()]
ex10pu1bs =
  [ BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e1")) Nothing Nothing)
  , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e2")) Nothing Nothing)
  , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e3")) Nothing Nothing) ]

ex11 :: ProgramFile ()
ex11 = ProgramFile mi77 [ ex11pu1 ]
ex11pu1 :: ProgramUnit ()
ex11pu1 = PUFunction () u (Just (TypeSpec () u TypeInteger Nothing)) emptyPrefixSuffix "f1" Nothing (Just (varGen "r1")) ex11pu1bs Nothing
ex11pu1bs :: [Block ()]
ex11pu1bs =
  [ BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e1")) Nothing Nothing)
  , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e2")) Nothing Nothing)
  , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e3")) Nothing (Just (varGen "r2"))) ]

ex12 :: ProgramFile A0
ex12 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "module m1"
  , "  implicit none"
  , "  integer :: z"
  , "contains"
  , "  integer function foo ()"
  , "    foo = 0"
  , "  end function foo"
  , "end module m1"
  , ""
  , "module m2"
  , "  implicit none"
  , "contains"
  , "  integer function foo2 (x)"
  , "    use m1"
  , "    integer :: x"
  , "    foo2 = foo () + x"
  , "  end function foo2"
  , "end module m2"
  , ""
  , "module m3"
  , "  implicit none"
  , "contains"
  , "  integer function foo () result (r)"
  , "    r = 1"
  , "  end function foo"
  , "end module m3"
  , ""
  , "program main"
  , "  use m1, only: z"
  , "  use m3, only: foo"
  , "  integer :: x"
  , "  x = foo ()"
  , "end program main"
  ]

ex13Renames :: ProgramFile A0
ex13Renames = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "module m1"
  , "  implicit none"
  , "  integer :: z"
  , "contains"
  , "  integer function foo ()"
  , "    foo = 0"
  , "  end function foo"
  , "end module m1"
  , ""
  , "module m2"
  , "  implicit none"
  , "contains"
  , "  integer function foo2 (x)"
  , "    use m1, only: frob => foo"
  , "    integer :: x"
  , "    foo2 = frob () + x"
  , "  end function foo2"
  , "end module m2"
  , ""
  , "module m3"
  , "  implicit none"
  , "contains"
  , "  integer function foo () result (r)"
  , "    r = 1"
  , "  end function foo"
  , "end module m3"
  , ""
  , "program main"
  , "  use m1, only: z, baz => foo"
  , "  use m3, only: bar => foo"
  , "  integer :: x"
  , "  x = bar () + baz () + z"
  , "end program main"
  ]


exScope1 :: ProgramFile A0
exScope1 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "program scope1"
  -- local variables cannot take on the name of subprogram, therefore
  -- this declaration must be simply redeclaring the function x.
  , "  integer :: x"
  , ""
  , "  print *, x()" -- function use prior to definition is OK
  , ""
  , "end program scope1"
  , "integer function x ()"
  , "  x = 1"
  , "end function x"
  , ""
  ]

exScope2 :: ProgramFile A0
exScope2 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "module scope2"
  , "  integer :: x"
  , "contains"
  , "  subroutine s1 ()"
  , "    ! this is variable shadowing"
  , "    integer :: x"
  , "    x = 1"
  , "    print *, x"
  , "    call s2 ()"
  , "    print *, x"
  , "  contains"
  , "    subroutine s2"
  , "      ! reference to outside variable"
  , "      x = 2"
  , "    end subroutine s2"
  , "  end subroutine s1"
  , "end module scope2"
  , ""
  , "program main"
  , "  use scope2"
  , "  x = 0"
  , "  print *, x"
  , "  call s1 ()"
  , "  print *, x"
  , "  ! should print 0 at end"
  , "end program main"
  ]

exScope3 :: ProgramFile A0
exScope3 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "module m1"
  , "  implicit none"
  , "  integer :: x"
  , "contains"
  , ""
  , "  subroutine s1 ()"
  , "    call s2 (f1(x))"
  , "  end subroutine s1"
  , ""
  , "  integer function f1(x)"
  , "    integer :: x, f2"
  , "    f1 = f2(x)"
  , "  end function f1"
  , ""
  , ""
  , "end module m1"
  , ""
  , "program main"
  , "  use m1"
  , "  implicit none"
  , "  call s1()"
  , "  print *, f1(x)"
  , "end program main"
  , ""
  , "subroutine s2 (x)"
  , "  integer :: x, f2"
  , "  x = f2 (x)"
  , "end subroutine s2"
  , ""
  , "function f2(x)"
  , "  integer :: x, f2"
  , "  f2 = x + 1"
  , "end function f2"
  ]

common1 :: ProgramFile A0
common1 = resetSrcSpan . flip fortran90Parser "" $ unlines [
    "program p1"
  , "  implicit none"
  , "  integer :: x, y"
  , "  common /c/ x, y(10)"
  , "contains"
  , "  subroutine s1 ()"
  , "    call s2 (f1(x))"
  , "  end subroutine s1"
  , "  integer function f1(x)"
  , "    integer :: x, f2"
  , "    f1 = f2(x)"
  , "  end function f1"
  , "end program p1"
  ]

-- Local variables:
-- mode: haskell
-- haskell-program-name: "cabal repl test-suite:spec"
-- End: