tock-mirror/common/CommonTest.hs
Adam Sampson eb29e65bad Smarter tree traversals: "Scrap Your Uniplate".
This provides gmapMFor and gmapMFor2, which are like gmapM, but know what
they're looking for, and can therefore avoid going down branches of the tree
that won't contain any interesting types.

The basic approach is quite similar to Uniplate's PlateData: there's a function
(containsType) that'll tell you whether one type is contained somewhere within
another. However, unlike Uniplate, we build a static IntMap IntSet of the types
we need to know about, which allows rather quicker lookups. (I did try using
PlateData first.)

The result is that applyDepthM is now much quicker than it was before.
applyDepthM2 is a bit less impressive, which I assume is because it can't
really prune the tree much if it's looking for two types.

Future enhancements:
- convert more passes to use applyDepthM*;
- make gmapMFor* aware of constructors rather than just types, which should
  allow a bit more pruning.
2008-03-20 16:49:24 +00:00

159 lines
5.6 KiB
Haskell

{-
Tock: a compiler for parallel languages
Copyright (C) 2007 University of Kent
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
-}
-- #ignore-exports
-- | A module with tests for various miscellaneous things in the common directory.
module CommonTest (tests) where
import Data.Generics
import Test.HUnit hiding (State)
import qualified AST as A
import GenericUtils
import Metadata
import TreeUtils
import Types
-- | Tests the isSafeConversion function:
testIsSafeConversion :: Test
testIsSafeConversion = TestList $ map runTestRow resultsWithIndexes
where
resultsWithIndexes :: [(Int,[(Int,Bool)])]
resultsWithIndexes = zip [0..] $ map (zip [0..]) results
runTestRow :: (Int,[(Int,Bool)]) -> Test
runTestRow (a,b) = TestList $ map (runTest a) b
where
runTest :: Int -> (Int,Bool) -> Test
runTest destIndex (srcIndex,result) = TestCase $ assertEqual
("Testing from type: " ++ (show $ index srcIndex) ++ " to: " ++ (show $ index destIndex))
result $ isSafeConversion (index srcIndex) (index destIndex)
--Integer types are:
--A.Bool
--A.Byte
--A.UInt16
--A.UInt32
--A.UInt64
--A.Int8
--A.Int
--A.Int16
--A.Int32
--A.Int64
--We will assume (like the rest of Tock) that Int is 32-bits for testing. We can actually perform an exhaustive test without too much trouble:
index :: Int -> A.Type
index 0 = A.Bool
index 1 = A.Byte
index 2 = A.UInt16
index 3 = A.UInt32
index 4 = A.UInt64
index 5 = A.Int8
index 6 = A.Int16
index 7 = A.Int
index 8 = A.Int32
index 9 = A.Int64
t = True
f = False
results :: [[Bool]]
--Each row is a conversion to that type. For example, the first row is conversions *to* Bool:
results =
[ [t, f,f,f,f, f,f,f,f,f] --to Bool
,[t, t,f,f,f, f,f,f,f,f] --to Byte
,[t, t,t,f,f, f,f,f,f,f] --to UInt16
,[t, t,t,t,f, f,f,f,f,f] --to UInt32
,[t, t,t,t,t, f,f,f,f,f] --to UInt64
,[t, f,f,f,f, t,f,f,f,f] --to Int8
,[t, t,f,f,f, t,t,f,f,f] --to Int16
,[t, t,t,f,f, t,t,t,t,f] --to Int
,[t, t,t,f,f, t,t,t,t,f] --to Int32
,[t, t,t,t,f, t,t,t,t,t] --to Int64
]
-- | Tests the pass that checks a certain constructor is not present in the tree.
-- Here, we provide various small AST fragments, and check that the list of constructors returned
-- is the same as we expected.
testCheckTreeForConstr :: Test
testCheckTreeForConstr = TestList
[
doTest (0,A.Int,[],[])
,doTest (1,A.Int,[con0 A.Int],[ADI A.Int])
,doTest (100, A.True emptyMeta, [con1 A.True],[ADI $ A.True emptyMeta])
,doTest (200, A.Seq emptyMeta $ A.Several emptyMeta [A.Only emptyMeta $ A.Skip emptyMeta], [con1 A.Skip], [ADI $ A.Skip emptyMeta])
,doTest (201, A.Seq emptyMeta $ A.Several emptyMeta [A.Only emptyMeta $ A.Skip emptyMeta],
[con2 (A.Several :: Meta -> [A.Structured A.Process] -> A.Structured A.Process)],
[ADI $ A.Several emptyMeta [A.Only emptyMeta $ A.Skip emptyMeta]])
,doTest (202, A.Seq emptyMeta $ A.Several emptyMeta [A.Only emptyMeta $ A.Skip emptyMeta], [con0 A.Int], [])
,doTest (203, A.Seq emptyMeta $ A.Several emptyMeta [A.Only emptyMeta $ A.Skip emptyMeta], [con2 (A.Only :: Meta -> A.Process -> A.Structured A.Process), con1 A.Skip],
[ADI $ A.Only emptyMeta $ A.Skip emptyMeta, ADI $ A.Skip emptyMeta])
]
where
doTest :: Data a => (Int, a, [Constr], [AnyDataItem]) -> Test
doTest (n,testIn,testFor,testOut) = TestCase $ assertEqual ("testCheckAny " ++ (show n)) testOut (checkTreeForConstr testFor testIn)
testDecomp :: Test
testDecomp = TestList
[
doTest 0 (Just $ Just "xy") (decomp1 Just (return . (++ "y")) (Just "x"))
,doTest 1 Nothing (decomp1 Right (return . (++ "y")) (Left "x"))
]
where
doTest :: (Eq a, Show a) => Int -> Maybe a -> Maybe a -> Test
doTest n exp act = TestCase $ assertEqual ("testDecomp " ++ show n) exp act
data NotPartOfAST = NotPartOfAST Int
deriving (Show, Typeable, Data)
-- | Test 'typeContains'.
testTypeContains :: Test
testTypeContains = TestList
[
-- AST elements that it should know about
test 0 True (undefined :: A.AST) (undefined :: Meta)
, test 1 False (undefined :: Meta) (undefined :: A.AST)
, test 2 True (undefined :: A.Process) (undefined :: A.Name)
, test 3 False (undefined :: A.AbbrevMode) (undefined :: A.Formal)
, test 4 False (undefined :: String) (undefined :: Meta)
, test 5 True (undefined :: String) (undefined :: Char)
-- Things outside the AST
, test 100 True (NotPartOfAST 42) (undefined :: String)
, test 101 False (undefined :: String) (NotPartOfAST 42)
]
where
test :: (Show a, Data a, Typeable a, Show b, Data b, Typeable b) =>
Int -> Bool -> a -> b -> Test
test n exp start find
= TestCase $ assertEqual ("testTypeContains " ++ show n)
exp (typeContains start find)
--Returns the list of tests:
tests :: Test
tests = TestLabel "CommonTest" $ TestList
[ testIsSafeConversion
, testCheckTreeForConstr
, testDecomp
, testTypeContains
]