{- 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 . -} -- | Contains test for various shared passes. module PassTest (tests) where import Control.Monad.State hiding (guard) import Data.Generics import qualified Data.Map as Map import Test.HUnit hiding (State) import qualified AST as A import CompState import Metadata import OccamEDSL import Pattern import SimplifyComms import SimplifyExprs import TagAST import TestUtils import TreeUtils import Unnest import Utils m :: Meta m = emptyMeta -- | An expression list containing a single value of 0. valof0 :: A.Structured A.ExpressionList valof0 = A.Only m $ A.ExpressionList m [intLiteral 0] -- | An expression list containing variables with the two given names. valofTwo :: String -> String -> A.Structured A.ExpressionList valofTwo a b = A.Only m $ A.ExpressionList m [exprVariable a,exprVariable b] -- | Looks up an item from the Items, and attempts to cast it. Fails (via assertions) if -- either the item is not found, or if the cast is invalid. assertGetItemCast :: Typeable t => String -> Items -> IO t assertGetItemCast k kv = case (Map.lookup k kv) of Nothing -> (assertFailure "Internal error; expected item not present") >> return (undefined) Just (ADI v) -> case (cast v) of Just v' -> return v' Nothing -> (assertFailure $ "Wrong type when casting in assertGetItemCast for key: " ++ k) >> return (undefined) -- | Given a body, returns a function spec: singleParamFunc :: A.Structured A.ExpressionList -> A.Specification singleParamFunc body = A.Specification m (simpleName "foo") (A.Function m (A.PlainSpec, A.PlainRec) [A.Int] [A.Formal A.ValAbbrev A.Byte (simpleName "param0")] (Left body)) singleParamFuncProc :: A.Process -> A.Specification singleParamFuncProc body = A.Specification m (simpleName "foo") (A.Function m (A.PlainSpec, A.PlainRec) [A.Int] [A.Formal A.ValAbbrev A.Byte (simpleName "param0")] (Right body)) -- | Returns the expected body of the single parameter process (when the function had valof0 as a body) singleParamBodyExp :: Pattern -- ^ to match: A.Process singleParamBodyExp = tag2 A.Seq DontCare $ mOnlyP $ tag3 A.Assign DontCare [tag2 A.Variable DontCare (Named "ret0" DontCare)] $ tag2 A.ExpressionList DontCare [intLiteral 0] -- | Returns the expected specification type of the single parameter process singleParamSpecExp :: Pattern -> Pattern -- ^ to match: A.SpecType singleParamSpecExp body = tag4 A.Proc DontCare (A.PlainSpec, A.PlainRec) [tag3 A.Formal A.ValAbbrev A.Byte (simpleName "param0"), tag3 A.Formal A.Abbrev A.Int (Named "ret0" DontCare)] body -- | Tests a function with a single return, and a single parameter. testFunctionsToProcs0 :: Test testFunctionsToProcs0 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs0" exp functionsToProcs orig (return ()) check where orig = singleParamFunc valof0 exp = tag3 A.Specification DontCare (simpleName "foo") procSpec procSpec = singleParamSpecExp singleParamBodyExp --check return parameters were defined: check (items,state) = do ret0 <- ((assertGetItemCast "ret0" items) :: IO A.Name) assertVarDef "testFunctionsToProcs0" state (A.nameName ret0) $ tag7 A.NameDef DontCare (A.nameName ret0) (A.nameName ret0) (A.Declaration m A.Int) A.Abbrev A.NameNonce A.Unplaced --check proc was defined: assertVarDef "testFunctionsToProcs0" state "foo" $ tag7 A.NameDef DontCare ("foo") ("foo") procSpec A.Original A.NameUser A.Unplaced --check csFunctionReturns was changed: assertEqual "testFunctionsToProcs0" (Just [A.Int]) (Map.lookup "foo" (csFunctionReturns state)) -- | Tests a function with multiple returns, and multiple parameters. testFunctionsToProcs1 :: Test testFunctionsToProcs1 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs1 A" exp functionsToProcs orig (return ()) check where orig = A.Specification m (simpleName "foo") (A.Function m (A.PlainSpec, A.Recursive) [A.Int,A.Real32] [A.Formal A.ValAbbrev A.Byte (simpleName "param0"),A.Formal A.Abbrev A.Real32 (simpleName "param1")] (Left $ valofTwo "param0" "param1")) exp = tag3 A.Specification DontCare (simpleName "foo") procBody procBody = tag4 A.Proc DontCare (A.PlainSpec, A.Recursive) [tag3 A.Formal A.ValAbbrev A.Byte (simpleName "param0"), tag3 A.Formal A.Abbrev A.Real32 (simpleName "param1"), tag3 A.Formal A.Abbrev A.Int (Named "ret0" DontCare), tag3 A.Formal A.Abbrev A.Real32 (Named "ret1" DontCare)] $ tag2 A.Seq DontCare $ mOnlyP $ tag3 A.Assign DontCare [tag2 A.Variable DontCare (Named "ret0" DontCare),tag2 A.Variable DontCare (Named "ret1" DontCare)] $ tag2 A.ExpressionList DontCare [exprVariable "param0",exprVariable "param1"] --check return parameters were defined: check (items,state) = do ret0 <- ((assertGetItemCast "ret0" items) :: IO A.Name) ret1 <- ((assertGetItemCast "ret1" items) :: IO A.Name) assertVarDef "testFunctionsToProcs1 B" state (A.nameName ret0) $ tag7 A.NameDef DontCare (A.nameName ret0) (A.nameName ret0) (A.Declaration m A.Int) A.Abbrev A.NameNonce A.Unplaced assertVarDef "testFunctionsToProcs1 C" state (A.nameName ret1) $ tag7 A.NameDef DontCare (A.nameName ret1) (A.nameName ret1) (A.Declaration m A.Real32) A.Abbrev A.NameNonce A.Unplaced --check proc was defined: assertVarDef "testFunctionsToProcs1 D" state "foo" $ tag7 A.NameDef DontCare ("foo") ("foo") procBody A.Original A.NameUser A.Unplaced --check csFunctionReturns was changed: assertEqual "testFunctionsToProcs1 E" (Just [A.Int,A.Real32]) (Map.lookup "foo" (csFunctionReturns state)) -- | Tests a function that contains a function. -- Currently I have chosen to put DontCare for the body of the function as stored in the NameDef. -- This behaviour is not too important, and may change at a later date. testFunctionsToProcs2 :: Test testFunctionsToProcs2 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs2 A" exp functionsToProcs orig (return ()) check where orig = A.Specification m (simpleName "fooOuter") (A.Function m (A.PlainSpec, A.PlainRec) [A.Int] [A.Formal A.ValAbbrev A.Byte (simpleName "paramOuter0")] $ Left $ A.Spec m (singleParamFunc valof0) valof0) exp = tag3 A.Specification DontCare (simpleName "fooOuter") procBodyOuter procHeader body = tag4 A.Proc DontCare (A.PlainSpec, A.PlainRec) [tag3 A.Formal A.ValAbbrev A.Byte (simpleName "paramOuter0"), tag3 A.Formal A.Abbrev A.Int (Named "retOuter0" DontCare)] body procBodyOuter = procHeader $ tag2 A.Seq DontCare $ mSpecP (tag3 A.Specification DontCare (simpleName "foo") (singleParamSpecExp singleParamBodyExp)) $ mOnlyP $ tag3 A.Assign DontCare [tag2 A.Variable DontCare (Named "retOuter0" DontCare)] $ tag2 A.ExpressionList DontCare [intLiteral 0] --check return parameters were defined: check (items,state) = do retOuter0 <- ((assertGetItemCast "retOuter0" items) :: IO A.Name) ret0 <- ((assertGetItemCast "ret0" items) :: IO A.Name) assertVarDef "testFunctionsToProcs2 B" state (A.nameName ret0) $ tag7 A.NameDef DontCare (A.nameName ret0) (A.nameName ret0) (A.Declaration m A.Int) A.Abbrev A.NameNonce A.Unplaced assertVarDef "testFunctionsToProcs2 C" state (A.nameName retOuter0) $ tag7 A.NameDef DontCare (A.nameName retOuter0) (A.nameName retOuter0) (A.Declaration m A.Int) A.Abbrev A.NameNonce A.Unplaced --check proc was defined: assertVarDef "testFunctionsToProcs2 D" state "foo" $ tag7 A.NameDef DontCare ("foo") ("foo") (singleParamSpecExp DontCare) A.Original A.NameUser A.Unplaced assertVarDef "testFunctionsToProcs2 E" state "fooOuter" $ tag7 A.NameDef DontCare ("fooOuter") ("fooOuter") (procHeader DontCare) A.Original A.NameUser A.Unplaced --check csFunctionReturns was changed: assertEqual "testFunctionsToProcs2 F" (Just [A.Int]) (Map.lookup "foo" (csFunctionReturns state)) assertEqual "testFunctionsToProcs2 G" (Just [A.Int]) (Map.lookup "fooOuter" (csFunctionReturns state)) -- | Tests a function with a single return, and a single parameter, with a Process body testFunctionsToProcs3 :: Test testFunctionsToProcs3 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs3" exp functionsToProcs orig (return ()) check where orig = singleParamFuncProc $ A.Seq m $ A.Only m $ A.Assign m [variable "foo"] $ A.ExpressionList m [intLiteral 0] exp = tag3 A.Specification DontCare (simpleName "foo") procSpec procSpec = singleParamSpecExp singleParamBodyExp --check return parameters were defined: check (items,state) = do ret0 <- ((assertGetItemCast "ret0" items) :: IO A.Name) assertVarDef "testFunctionsToProcs3" state (A.nameName ret0) $ tag7 A.NameDef DontCare (A.nameName ret0) (A.nameName ret0) (A.Declaration m A.Int) A.Abbrev A.NameNonce A.Unplaced --check proc was defined: assertVarDef "testFunctionsToProcs3" state "foo" $ tag7 A.NameDef DontCare ("foo") ("foo") procSpec A.Original A.NameUser A.Unplaced --check csFunctionReturns was changed: assertEqual "testFunctionsToProcs3" (Just [A.Int]) (Map.lookup "foo" (csFunctionReturns state)) -- | Tests a function with multiple returns, and multiple parameters. testFunctionsToProcs4 :: Test testFunctionsToProcs4 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs4 A" exp functionsToProcs orig (return ()) check where orig = A.Specification m (simpleName "foo") (A.Function m (A.PlainSpec, A.PlainRec) [A.Int,A.Real32] [A.Formal A.ValAbbrev A.Byte (simpleName "param0"),A.Formal A.Abbrev A.Real32 (simpleName "param1")] $ Right $ A.Seq m $ A.Only m $ A.Assign m [variable "foo"] $ A.ExpressionList m [exprVariable "param0", exprVariable "param1"]) exp = tag3 A.Specification DontCare (simpleName "foo") procBody procBody = tag4 A.Proc DontCare (A.PlainSpec, A.PlainRec) [tag3 A.Formal A.ValAbbrev A.Byte (simpleName "param0"), tag3 A.Formal A.Abbrev A.Real32 (simpleName "param1"), tag3 A.Formal A.Abbrev A.Int (Named "ret0" DontCare), tag3 A.Formal A.Abbrev A.Real32 (Named "ret1" DontCare)] $ tag2 A.Seq DontCare $ mOnlyP $ tag3 A.Assign DontCare [tag2 A.Variable DontCare (Named "ret0" DontCare),tag2 A.Variable DontCare (Named "ret1" DontCare)] $ tag2 A.ExpressionList DontCare [exprVariable "param0",exprVariable "param1"] --check return parameters were defined: check (items,state) = do ret0 <- ((assertGetItemCast "ret0" items) :: IO A.Name) ret1 <- ((assertGetItemCast "ret1" items) :: IO A.Name) assertVarDef "testFunctionsToProcs4 B" state (A.nameName ret0) $ tag7 A.NameDef DontCare (A.nameName ret0) (A.nameName ret0) (A.Declaration m A.Int) A.Abbrev A.NameNonce A.Unplaced assertVarDef "testFunctionsToProcs4 C" state (A.nameName ret1) $ tag7 A.NameDef DontCare (A.nameName ret1) (A.nameName ret1) (A.Declaration m A.Real32) A.Abbrev A.NameNonce A.Unplaced --check proc was defined: assertVarDef "testFunctionsToProcs4 D" state "foo" $ tag7 A.NameDef DontCare ("foo") ("foo") procBody A.Original A.NameUser A.Unplaced --check csFunctionReturns was changed: assertEqual "testFunctionsToProcs4 E" (Just [A.Int,A.Real32]) (Map.lookup "foo" (csFunctionReturns state)) skipP :: A.Structured A.Process skipP = A.Only m (A.Skip m) -- | Tests that a simple constructor (with no expression, nor function call) gets converted into the appropriate initialisation code testTransformConstr0 :: Test testTransformConstr0 = TestCase $ testPass "transformConstr0" exp transformConstr orig startState where startState :: State CompState () startState = defineConst "x" A.Int (intLiteral 42) t = A.Array [dimension 10] A.Int orig = A.Spec m (A.Specification m (simpleName "arr") $ A.IsExpr m A.ValAbbrev t $ A.ExprConstr m $ A.RepConstr m t (simpleName "x") (A.For m (intLiteral 0) (intLiteral 10) (intLiteral 1)) (exprVariable "x")) skipP exp = nameAndStopCaringPattern "indexVar" "i" $ mkPattern exp' exp' = A.Spec m (A.Specification m (simpleName "arr") (A.Declaration m t)) $ A.ProcThen m (A.Seq m $ A.Spec m (A.Specification m (simpleName "i") (A.Declaration m A.Int)) $ A.Several m [A.Only m $ A.Assign m [variable "i"] $ A.ExpressionList m [intLiteral 0], A.Spec m (A.Specification m (simpleName "x") $ A.Rep m (A.For m (intLiteral 0) (intLiteral 10) (intLiteral 1))) $ A.Only m $ A.Seq m $ A.Several m [A.Only m $ A.Assign m [A.SubscriptedVariable m (A.Subscript m A.NoCheck $ exprVariable "i") (variable "arr")] $ A.ExpressionList m [exprVariable "x"], A.Only m $ A.Assign m [variable "i"] $ A.ExpressionList m [A.Dyadic m A.Add (intLiteral 1) (exprVariable "i")]] ] ) skipP testOutExprs :: Test testOutExprs = TestList [ -- Test outputting from an expression: TestCase $ testPassWithItemsStateCheck "testOutExprs 0" (tag2 A.Seq DontCare $ (abbr "temp_var" A.Int (eXM 1)) (mOnlyP $ tag3 A.Output emptyMeta chan [tag2 A.OutExpression emptyMeta (tag2 A.ExprVariable DontCare (tag2 A.Variable DontCare (Named "temp_var" DontCare)))]) ) outExprs ( A.Output emptyMeta chan [outXM 1] ) (defineName (xName) $ simpleDefDecl "x" A.Int) (checkTempVarTypes "testOutExprs 0" [("temp_var", A.Int)]) -- Test outputting from a variable already: ,TestCase $ testPass "testOutExprs 1" (tag2 A.Seq DontCare $ (mOnlyP $ tag3 A.Output emptyMeta chan [outX]) ) outExprs ( A.Output emptyMeta chan [outX] ) (return ()) -- Test outputting from multiple output items: ,TestCase $ testPassWithItemsStateCheck "testOutExprs 2" (tag2 A.Seq DontCare $ (abbr "temp_var0" A.Byte (eXM 1)) $ (abbr "temp_var1" A.Int (intLiteral 2)) (mOnlyP $ tag3 A.Output emptyMeta chan [tag2 A.OutExpression emptyMeta (tag2 A.ExprVariable DontCare (tag2 A.Variable DontCare (Named "temp_var0" DontCare))) ,mkPattern outX ,tag2 A.OutExpression emptyMeta (tag2 A.ExprVariable DontCare (tag2 A.Variable DontCare (Named "temp_var1" DontCare))) ] ) ) outExprs ( A.Output emptyMeta chan [outXM 1,outX,A.OutExpression emptyMeta $ intLiteral 2] ) (defineName (xName) $ simpleDefDecl "x" A.Byte) (checkTempVarTypes "testOutExprs 2" [("temp_var0", A.Byte),("temp_var1", A.Int)]) -- Test an OutCounted ,TestCase $ testPassWithItemsStateCheck "testOutExprs 3" (tag2 A.Seq DontCare $ (abbr "temp_var" A.Byte (eXM 1)) (mOnlyP $ tag3 A.Output emptyMeta chan [tag3 A.OutCounted emptyMeta (tag2 A.ExprVariable DontCare (tag2 A.Variable DontCare (Named "temp_var0" DontCare))) (exprVariable "x") ] ) ) outExprs ( A.Output emptyMeta chan [A.OutCounted emptyMeta (eXM 1) (exprVariable "x")] ) (defineName (xName) $ simpleDefDecl "x" A.Byte) (checkTempVarTypes "testOutExprs 3" [("temp_var", A.Byte)]) -- Test that OutputCase is also processed: ,TestCase $ testPassWithItemsStateCheck "testOutExprs 4" (tag2 A.Seq DontCare $ (abbr "temp_var" A.Int (eXM 1)) (mOnlyP $ tag4 A.OutputCase emptyMeta chan (simpleName "foo") [tag2 A.OutExpression emptyMeta (tag2 A.ExprVariable DontCare (tag2 A.Variable DontCare (Named "temp_var" DontCare)))]) ) outExprs ( A.OutputCase emptyMeta chan (simpleName "foo") [outXM 1] ) (defineName (xName) $ simpleDefDecl "x" A.Int) (checkTempVarTypes "testOutExprs 3" [("temp_var", A.Int)]) -- Test that an empty outputcase works okay: ,TestCase $ testPass "testOutExprs 5" (tag2 A.Seq DontCare $ (mOnlyP $ A.OutputCase emptyMeta chan (simpleName "foo") []) ) outExprs ( A.OutputCase emptyMeta chan (simpleName "foo") [] ) (return ()) ] where outX = A.OutExpression emptyMeta $ exprVariable "x" outXM n = A.OutExpression emptyMeta $ eXM n eXM n = buildExpr $ Dy (Var "x") A.Minus (Lit $ intLiteral n) abbr key t e = mSpecP (tag3 A.Specification DontCare (Named key DontCare) $ tag4 A.IsExpr DontCare A.ValAbbrev t e) chan = variable "c" xName = simpleName "x" testInputCase :: Test testInputCase = TestList [ -- Input that only involves tags: {- The idea is to transform: c ? CASE a0 --Process p0 into: SEQ INT tag: SEQ c ? tag CASE tag a0 --Process p0 -} testOccamPassTransform "testInputCase 0" (nameAndStopCaringPattern "tag" "A") ( defineProtocolAndC $ (oC *? oCASEinput [inputCaseOption (a0, [], p0)] ) `becomes` oSEQ [declNonce (return A.Int) oA [oC *? oA ,oCASE oA [caseOption ([0 :: Int], p0)] ] ] ) transformInputCase -- Input that involves multiple tags and multiple inputs: {- The idea is to transform: c ? CASE a0 --Process p0 c1 ; z --Process p1 b2 ; x ; y --Process p2 into: SEQ INT tag: SEQ c ? tag CASE tag a0 --Process p0 c1 SEQ c ? z --Process p1 b2 SEQ c ? x ; y --Process p2 -} ,testOccamPassTransform "testInputCase 1" (nameAndStopCaringPattern "tag" "A") ( defineProtocolAndC $ (oC *? oCASEinput [inputCaseOption (a0, [], p0) ,inputCaseOption (c1, [oZ], p1) ,inputCaseOption (b2, [oX, oY], p2) ] ) `becomes` oSEQ [declNonce (return A.Int) oA [oC *? oA ,oCASE oA [caseOption ([0 :: Int], p0) ,caseOption ([2 :: Int], oSEQ [oC *? oZ ,p1]) ,caseOption ([1 :: Int], oSEQ [oC *? sequence [oX, oY] ,p2]) ] ] ] ) transformInputCase -- Input that involves multiple tags and multiple inputs and specs (sheesh!): {- The idea is to transform: c ? CASE a0 --Process p0 INT z: c1 ; z --Process p1 INT x: INT y: b2 ; x ; y --Process p2 into: SEQ INT tag: SEQ c ? tag CASE tag a0 --Process p0 INT z: c1 SEQ c ? z --Process p1 INT x: INT y: b2 SEQ c ? x ; y --Process p2 -} ,testOccamPassTransform "testInputCase 2" (nameAndStopCaringPattern "tag" "A") ( defineProtocolAndC $ (oC *? oCASEinput [inputCaseOption (a0, [], p0) ,decl (return A.Int) oZ [inputCaseOption (c1, [oZ], p1)] ,decl (return A.Int) oX [decl (return A.Int) oY [inputCaseOption (b2, [oX, oY], p2)]] ] ) `becomes` oSEQ [declNonce (return A.Int) oA [oC *? oA ,oCASE oA [caseOption ([0 :: Int], p0) ,decl (return A.Int) oZ [caseOption ([2 :: Int], oSEQ [oC *? oZ ,p1])] ,decl (return A.Int) oX [decl (return A.Int) oY [caseOption ([1 :: Int], oSEQ [oC *? sequence [oX, oY] ,p2])]] ] ] ] ) transformInputCase -- Input that only involves tags: {- The idea is to transform: ALT c ? CASE a0 --Process p0 into: ALT INT tag: c ? tag CASE tag a0 --Process p0 -} ,testOccamPassTransform "testInputCase 100" (nameAndStopCaringPattern "tag" "A") ( defineProtocolAndC $ (oALT [guard (oC *? oCASEinput [inputCaseOption (a0, [], p0)], return $ A.Skip emptyMeta) ] ) `becomes` oALT [declNonce (return A.Int) oA [guard (oC *? oA, oCASE oA [caseOption ([0 :: Int], p0)]) ] ] ) transformInputCase ] where a0 = simpleName "a0" b2 = simpleName "b2" c1 = simpleName "c1" defineProtocolAndC :: Occ (A.Structured A.Process) -> Occ (A.Structured A.Process) defineProtocolAndC = decl' (simpleName "prot") (A.ProtocolCase emptyMeta [(a0,[]),(b2,[A.Int,A.Int]),(c1,[A.Int])]) A.Original A.NameUser . singleton . decl (return $ A.Chan (A.ChanAttributes False False) (A.UserProtocol $ simpleName "prot")) oC . singleton testTransformProtocolInput :: Test testTransformProtocolInput = TestList [ TestCase $ testPass "testTransformProtocolInput0" (seqItems [ii0]) transformProtocolInput (seqItems [ii0]) (return ()) ,TestCase $ testPass "testTransformProtocolInput1" (A.Seq emptyMeta $ A.Several emptyMeta $ map onlySingle [ii0, ii1, ii2]) transformProtocolInput (seqItems [ii0, ii1, ii2]) (return ()) ,TestCase $ testPass "testTransformProtocolInput2" (A.Alt emptyMeta False $ onlySingleAlt ii0) transformProtocolInput (A.Alt emptyMeta False $ onlySingleAlt ii0) (return ()) ,TestCase $ testPass "testTransformProtocolInput3" (A.Alt emptyMeta True $ A.Only emptyMeta $ A.Alternative emptyMeta (A.True emptyMeta) (variable "c") (A.InputSimple emptyMeta [ii0]) $ A.Seq emptyMeta $ A.Several emptyMeta $ onlySingle ii1 : [A.Only emptyMeta $ A.Skip emptyMeta]) transformProtocolInput (A.Alt emptyMeta True $ A.Only emptyMeta $ altItems [ii0, ii1]) (return ()) ,TestCase $ testPass "testTransformProtocolInput4" (A.Alt emptyMeta False $ A.Only emptyMeta $ A.Alternative emptyMeta (A.True emptyMeta) (variable "c") (A.InputSimple emptyMeta [ii0]) $ A.Seq emptyMeta $ A.Several emptyMeta $ map onlySingle [ii1,ii2] ++ [A.Only emptyMeta $ A.Skip emptyMeta]) transformProtocolInput (A.Alt emptyMeta False $ A.Only emptyMeta $ altItems [ii0, ii1, ii2]) (return ()) ] where ii0 = A.InVariable emptyMeta (variable "x") ii1 = A.InCounted emptyMeta (variable "y") (variable "z") ii2 = A.InVariable emptyMeta (variable "a") onlySingle = A.Only emptyMeta . A.Input emptyMeta (variable "c") . A.InputSimple emptyMeta . singleton onlySingleAlt = A.Only emptyMeta . flip (A.Alternative emptyMeta (A.True emptyMeta) (variable "c")) (A.Skip emptyMeta) . A.InputSimple emptyMeta . singleton seqItems = A.Input emptyMeta (variable "c") . A.InputSimple emptyMeta altItems = flip (A.Alternative emptyMeta (A.True emptyMeta) (variable "c")) (A.Skip emptyMeta) . A.InputSimple emptyMeta testPullRepCounts :: Test testPullRepCounts = TestList [ testUnchanged 4 $ A.If emptyMeta ,forAllThree $ \blockType -> testOccamPassTransform "testPullRepCounts 5" (nameAndStopCaringPattern "nonce" "A") (blockType [decl' (simpleName "X") (A.Rep emptyMeta (A.For emptyMeta (intLiteral 0) (intLiteral 6) (intLiteral 1))) A.Original A.NameUser [] ] `becomes` blockType [decl' (simpleName "A") (A.IsExpr emptyMeta A.ValAbbrev A.Int $ intLiteral 6) A.ValAbbrev A.NameNonce [decl' (simpleName "X") (A.Rep emptyMeta (A.For emptyMeta (intLiteral 0) (exprVariable "A") (intLiteral 1))) A.Original A.NameUser [] ] ] ) pullRepCounts ,forAllThree $ \blockType -> testOccamPassTransform "testPullRepCounts 6" (nameAndStopCaringPattern "nonce1" "A" . nameAndStopCaringPattern "nonce2" "B") (blockType [decl' (simpleName "X") (A.Rep emptyMeta (A.For emptyMeta (intLiteral 0) (intLiteral 6) (intLiteral 1))) A.Original A.NameUser [decl' (simpleName "Y") (A.Rep emptyMeta (A.For emptyMeta (intLiteral 1) (intLiteral 8) (intLiteral 2))) A.Original A.NameUser [] ] ] `becomes` blockType [decl' (simpleName "A") (A.IsExpr emptyMeta A.ValAbbrev A.Int $ intLiteral 6) A.ValAbbrev A.NameNonce [decl' (simpleName "X") (A.Rep emptyMeta (A.For emptyMeta (intLiteral 0) (exprVariable "A") (intLiteral 1))) A.Original A.NameUser [decl' (simpleName "B") (A.IsExpr emptyMeta A.ValAbbrev A.Int $ intLiteral 8) A.ValAbbrev A.NameNonce [decl' (simpleName "Y") (A.Rep emptyMeta (A.For emptyMeta (intLiteral 1) (exprVariable "B") (intLiteral 2))) A.Original A.NameUser [] ] ] ] ] ) pullRepCounts ] where forAllThree :: (forall a. Data a => ([Occ (A.Structured a)] -> Occ A.Process) -> Test) -> Test forAllThree f = TestList [f oSEQ, f oPAR, f oALT] testUnchanged :: Data a => Int -> (A.Structured a -> A.Process) -> Test testUnchanged n f = TestCase $ testPass ("testPullRepCounts/testUnchanged " ++ show n) code pullRepCounts code (return ()) where code = (f $ A.Spec emptyMeta (A.Specification emptyMeta (simpleName "i") $ A.Rep emptyMeta (A.For emptyMeta (intLiteral 0) (intLiteral 5) (intLiteral 1))) $ A.Several emptyMeta []) testRemoveNesting :: Test testRemoveNesting = TestList [ test "Blank PROC" $ oPROC "foo" [] ( oSKIP ) oempty , test "Nested PROC" $ (oPROC "bar" [] ( oSEQ [decl oINT oX []] ) $ oPROC "foo" [] ( oSEQ [decl oINT oX $ [oX *:= return (0::Int) ,oX *:= return (1::Int)]] ) oempty) `shouldComeFrom` oPROC "foo" [] ( oSEQ [oPROC "bar" [] ( oSEQ [decl oINT oX []] ) $ decl oINT oX [oX *:= return (0::Int) ,oX *:= return (1::Int)]] ) oempty ] where test :: String -> Occ A.AST -> Test test name x = testOccamPass name x removeNesting --Returns the list of tests: tests :: Test tests = TestLabel "PassTest" $ TestList [ testFunctionsToProcs0 ,testFunctionsToProcs1 ,testFunctionsToProcs2 ,testFunctionsToProcs3 ,testFunctionsToProcs4 ,testInputCase ,testOutExprs ,testPullRepCounts ,testRemoveNesting ,testTransformConstr0 ,testTransformProtocolInput ]