Moved all the remaining pass information to be with the passes themselves, and adjusted the tests accordingly

All the passes now have their information (name, pre-requisites and post- properties) stored at the point where the pass is declared, which means the pass lists are just a simple list of pass functions.

The main consequence of this change was that the tests had to be changed.  Now, instead of taking a "pass applied to data" item (type: PassM b), they take both the pass (type: Pass) and source data (type: b), and apply them later.  This was the decision that involved the simplest changes to the existing tests (simply unbracketing the application of the pass to the source).  I also had to include a few old-style versions though (testPass', testPassShouldFail') for where the functions were being used to test things that weren't actually passes (mainly StructureOccam).

Fixes #48
This commit is contained in:
Neil Brown 2008-06-02 14:31:19 +00:00
parent 6f6538ed57
commit ba66cce89f
23 changed files with 328 additions and 242 deletions

View File

@ -17,7 +17,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
-}
-- | Passes associated with the backends
module BackendPasses where
module BackendPasses (addSizesActualParameters, addSizesFormalParameters, declareSizesArray, simplifySlices, squashArrays, transformWaitFor) where
import Control.Monad.State
import Data.Generics
@ -35,18 +35,21 @@ import Types
import Utils
squashArrays :: [Pass]
squashArrays = makePassesDep
[ ("Simplify array slices", simplifySlices, prereq, [Prop.slicesSimplified])
, ("Declare array-size arrays", declareSizesArray, prereq ++ [Prop.slicesSimplified,
Prop.arrayConstructorsRemoved], [Prop.arraySizesDeclared])
, ("Add array-size arrays to PROC headers", addSizesFormalParameters, prereq ++ [Prop.arraySizesDeclared], [])
, ("Add array-size arrays to PROC calls", addSizesActualParameters, prereq ++ [Prop.arraySizesDeclared], [])
squashArrays =
[ simplifySlices
, declareSizesArray
, addSizesFormalParameters
, addSizesActualParameters
]
where
prereq = Prop.agg_namesDone ++ Prop.agg_typesDone ++ Prop.agg_functionsGone ++ [Prop.subscriptsPulledUp, Prop.arrayLiteralsExpanded]
transformWaitFor :: PassType
transformWaitFor = applyDepthM doAlt
prereq :: [Property]
prereq = Prop.agg_namesDone ++ Prop.agg_typesDone ++ Prop.agg_functionsGone ++ [Prop.subscriptsPulledUp, Prop.arrayLiteralsExpanded]
transformWaitFor :: Pass
transformWaitFor = cOnlyPass "Transform wait for guards into wait until guards"
[]
[Prop.waitForRemoved]
$ applyDepthM doAlt
where
doAlt :: A.Process -> PassM A.Process
doAlt a@(A.Alt m pri s)
@ -79,8 +82,11 @@ append_sizes n = n {A.nameName = A.nameName n ++ "_sizes"}
-- | Declares a _sizes array for every array, statically sized or dynamically sized.
-- For each record type it declares a _sizes array too.
declareSizesArray :: PassType
declareSizesArray = applyDepthSM doStructured
declareSizesArray :: Pass
declareSizesArray = occamOnlyPass "Declare array-size arrays"
(prereq ++ [Prop.slicesSimplified, Prop.arrayConstructorsRemoved])
[Prop.arraySizesDeclared]
$ applyDepthSM doStructured
where
defineSizesName :: Meta -> A.Name -> A.SpecType -> PassM ()
defineSizesName m n spec
@ -229,8 +235,11 @@ declareSizesArray = applyDepthSM doStructured
-- | A pass for adding _sizes parameters to PROC arguments
-- TODO in future, only add _sizes for variable-sized parameters
addSizesFormalParameters :: PassType
addSizesFormalParameters = applyDepthM doSpecification
addSizesFormalParameters :: Pass
addSizesFormalParameters = occamOnlyPass "Add array-size arrays to PROC headers"
(prereq ++ [Prop.arraySizesDeclared])
[]
$ applyDepthM doSpecification
where
doSpecification :: A.Specification -> PassM A.Specification
doSpecification (A.Specification m n (A.Proc m' sm args body))
@ -263,8 +272,11 @@ addSizesFormalParameters = applyDepthM doSpecification
return (f : rest, new)
-- | A pass for adding _sizes parameters to actuals in PROC calls
addSizesActualParameters :: PassType
addSizesActualParameters = applyDepthM doProcess
addSizesActualParameters :: Pass
addSizesActualParameters = occamOnlyPass "Add array-size arrays to PROC calls"
(prereq ++ [Prop.arraySizesDeclared])
[]
$ applyDepthM doProcess
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.ProcCall m n params) = concatMapM transformActual params >>* A.ProcCall m n
@ -289,8 +301,11 @@ addSizesActualParameters = applyDepthM doProcess
transformActualVariable a _ = return [a]
-- | Transforms all slices into the FromFor form.
simplifySlices :: PassType
simplifySlices = applyDepthM doVariable
simplifySlices :: Pass
simplifySlices = occamOnlyPass "Simplify array slices"
prereq
[Prop.slicesSimplified]
$ applyDepthM doVariable
where
doVariable :: A.Variable -> PassM A.Variable
doVariable (A.SubscriptedVariable m (A.SubscriptFor m' check for) v)

View File

@ -61,13 +61,13 @@ mGetTime v = mInput (mVariable timerName) (mInputTimerRead $ mInVariable v)
-- | Test WaitUntil guard (should be unchanged)
testTransformWaitFor0 :: Test
testTransformWaitFor0 = TestCase $ testPass "testTransformWaitFor0" orig (transformWaitFor orig) (return ())
testTransformWaitFor0 = TestCase $ testPass "testTransformWaitFor0" orig transformWaitFor orig (return ())
where
orig = A.Alt m True $ A.Only m $ waitUntil (exprVariable "t") (A.Skip m)
-- | Test pulling out a single WaitFor:
testTransformWaitFor1 :: Test
testTransformWaitFor1 = TestCase $ testPass "testTransformWaitFor1" exp (transformWaitFor orig) (return ())
testTransformWaitFor1 = TestCase $ testPass "testTransformWaitFor1" exp transformWaitFor orig (return ())
where
orig = A.Alt m True $ A.Only m $ waitFor (exprVariable "t") (A.Skip m)
exp = tag2 A.Seq DontCare $ mSpecP (tag3 A.Specification DontCare varName $ A.Declaration m A.Time) $
@ -83,7 +83,7 @@ testTransformWaitFor1 = TestCase $ testPass "testTransformWaitFor1" exp (transfo
-- | Test pulling out two WaitFors:
testTransformWaitFor2 :: Test
testTransformWaitFor2 = TestCase $ testPass "testTransformWaitFor2" exp (transformWaitFor orig) (return ())
testTransformWaitFor2 = TestCase $ testPass "testTransformWaitFor2" exp transformWaitFor orig (return ())
where
orig = A.Alt m True $ A.Several m [A.Only m $ waitFor (exprVariable "t0") (A.Skip m),
A.Only m $ waitFor (exprVariable "t1") (A.Skip m)]
@ -108,7 +108,7 @@ testTransformWaitFor2 = TestCase $ testPass "testTransformWaitFor2" exp (transfo
-- | Test pulling out a single WaitFor with an expression:
testTransformWaitFor3 :: Test
testTransformWaitFor3 = TestCase $ testPass "testTransformWaitFor3" exp (transformWaitFor orig) (return ())
testTransformWaitFor3 = TestCase $ testPass "testTransformWaitFor3" exp transformWaitFor orig (return ())
where
orig = A.Alt m True $ A.Only m $ waitFor (A.Dyadic m A.Plus (exprVariable "t0") (exprVariable "t1")) (A.Skip m)
exp = tag2 A.Seq DontCare $ mSpecP (tag3 A.Specification DontCare varName $ A.Declaration m A.Time) $
@ -125,7 +125,7 @@ testTransformWaitFor3 = TestCase $ testPass "testTransformWaitFor3" exp (transfo
-- | Test pulling out a single WaitFor with some slight nesting in the ALT:
testTransformWaitFor4 :: Test
testTransformWaitFor4 = TestCase $ testPass "testTransformWaitFor4" exp (transformWaitFor orig) (return ())
testTransformWaitFor4 = TestCase $ testPass "testTransformWaitFor4" exp transformWaitFor orig (return ())
where
orig = A.Alt m True $ A.Several m [A.Only m $ waitFor (exprVariable "t") (A.Skip m)]
exp = tag2 A.Seq DontCare $ mSpecP (tag3 A.Specification DontCare varName $ A.Declaration m A.Time) $
@ -142,7 +142,7 @@ testTransformWaitFor4 = TestCase $ testPass "testTransformWaitFor4" exp (transfo
-- | Test pulling out two WaitFors that use the same variable:
testTransformWaitFor5 :: Test
testTransformWaitFor5 = TestCase $ testPass "testTransformWaitFor5" exp (transformWaitFor orig) (return ())
testTransformWaitFor5 = TestCase $ testPass "testTransformWaitFor5" exp transformWaitFor orig (return ())
where
orig = A.Alt m True $ A.Several m [A.Only m $ waitFor (exprVariable "t") (A.Skip m),
A.Only m $ waitFor (exprVariable "t") (A.Skip m)]
@ -313,7 +313,7 @@ qcTestDeclareSizes =
term = A.Only emptyMeta ()
test :: TestMonad m r => Int -> A.Structured () -> A.Structured () -> State CompState () -> (CompState -> m ()) -> m ()
test n exp inp st chk = testPassWithStateCheck label exp (declareSizesArray inp) st chk
test n exp inp st chk = testPassWithStateCheck label exp declareSizesArray inp st chk
where
label = "testDeclareSizes " ++ show n
@ -354,7 +354,7 @@ qcTestSizeParameters =
testActual :: TestMonad m r => [A.Type] -> m ()
testActual ts = testPassWithStateCheck "qcTestSizeParameters Actual"
(procCall "p" argsWithSizes)
(addSizesActualParameters $ procCall "p" args)
addSizesActualParameters (procCall "p" args)
(do recordProcDef args
recordProcFormals args)
(const $ return ())
@ -369,7 +369,7 @@ qcTestSizeParameters =
testFormal :: TestMonad m r => [A.Type] -> m ()
testFormal ts = testPassWithStateCheck "qcTestSizeParameters Formal"
(wrapSpec "p" $ makeProcDef argsWithSizes)
(addSizesFormalParameters $ wrapSpec "p" $ makeProcDef args)
addSizesFormalParameters (wrapSpec "p" $ makeProcDef args)
(do recordProcDef args
recordProcFormals args)
(\x -> do checkProcDef argsWithSizes x

View File

@ -62,9 +62,7 @@ import Utils
--{{{ passes related to C generation
genCPasses :: [Pass]
genCPasses = makePassesDep' ((== BackendC) . csBackend)
[ ("Transform wait for guards into wait until guards", transformWaitFor, [], [Prop.waitForRemoved])
]
genCPasses = [transformWaitFor]
--}}}
cPreReq :: [Property]

View File

@ -90,12 +90,13 @@ cppgenOps = cgenOps {
--}}}
genCPPCSPPasses :: [Pass]
genCPPCSPPasses = makePassesDep' ((== BackendCPPCSP) . csBackend)
[ ("Transform channels to ANY", chansToAny, [Prop.processTypesChecked], [Prop.allChansToAnyOrProtocol])
]
genCPPCSPPasses = [chansToAny]
chansToAny :: PassType
chansToAny x = do st <- get
chansToAny :: Pass
chansToAny = cppOnlyPass "Transform channels to ANY"
[Prop.processTypesChecked]
[Prop.allChansToAnyOrProtocol]
$ \x -> do st <- get
case csFrontend st of
FrontendOccam ->
do chansToAnyInCompState

View File

@ -955,10 +955,6 @@ assertEquivalentProblems title exp act
sortProblem :: [(EqualityProblem, InequalityProblem)] -> [(EqualityProblem, InequalityProblem)]
sortProblem = sort
checkRight :: (Show a, TestMonad m r) => Either a b -> m b
checkRight (Left err) = testFailure ("Not Right: " ++ show err) >> return undefined
checkRight (Right x) = return x
-- QuickCheck tests for Omega Test:
-- The idea is to begin with a random list of integers, representing answers.
-- Combine this with a randomly generated matrix of coefficients for equalities

View File

@ -109,7 +109,7 @@ testGetVarProc = TestList (map doTest tests)
-- TestUtils.
doTest :: (Int,[Var],[Var],[Var],A.Process) -> Test
doTest (index, r, w, u, proc)
= TestCase $ do result <- runPass (getVarProc proc) startState
= TestCase $ do result <- runPass' (getVarProc proc) startState
case result of
(_, Left err) ->
testFailure $ name ++ " failed: " ++ show err

View File

@ -38,7 +38,6 @@ If they are not equal, it shows them (using 'show') with the given message prefi
module TestUtils where
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Writer
import Data.Generics
@ -54,7 +53,6 @@ import Metadata (emptyMeta)
import Pass
import Pattern
import PrettyShow
import TagAST
import TestFramework
import TreeUtils
import Types
@ -447,8 +445,8 @@ checkTempVarTypes testName vars is = mapM_ (checkTempVarType testName is) vars
Nothing -> liftIO $ assertFailure (testName ++ ": spec does not have identifiable type for key \"" ++ key ++ "\": " ++ show (A.ndSpecType nd))
) state
assertEither :: (Eq a, Show a) => String -> a -> Either String a -> Assertion
assertEither testName exp = assertEqual testName (Right exp)
assertEither :: (Eq a, Eq e, Show a, Show e, TestMonad m r) => String -> a -> Either e a -> m ()
assertEither testName exp = testEqual testName (Right exp)
assertEitherFail :: String -> Either String a -> Assertion
assertEitherFail testName result
@ -456,6 +454,10 @@ assertEitherFail testName result
Left _ -> return ()
Right _ -> assertFailure $ testName ++ "; test expected to fail but passed"
checkRight :: (Show a, TestMonad m r) => Either a b -> m b
checkRight (Left err) = testFailure ("Not Right: " ++ show err) >> return undefined
checkRight (Right x) = return x
--}}}
--{{{ canned tests
@ -466,12 +468,13 @@ testPassGetItems ::
(Data a, Data b, TestMonad m r) =>
String -- ^ The message\/test name to prefix on failure.
-> a -- ^ The expected outcome of the pass. Will be used as a 'Pattern', to find the named items in the result of the pass.
-> PassM b -- ^ The actual pass.
-> Pass
-> b
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> m (CompState, Either (m ()) Items) -- ^ Returns the state, along with either an 'Assertion' (if the pass fails) or the 'Items' (if the pass succeeds).
testPassGetItems testName expected actualPass startStateTrans =
testPassGetItems testName expected actualPass src startStateTrans =
--passResult :: Either String b
do passResult <- runPass actualPass startState
do passResult <- runPass actualPass src startState
case passResult of
(st, Left (_, err)) -> return (st, Left $ testFailure (prefixErr $ "pass actually failed: " ++ err))
(st, Right resultItem) -> return (st, transformEither (mapM_ (testFailure . prefixErr)) (id) $ getMatchedItems expected resultItem)
@ -484,35 +487,52 @@ testPassGetItems testName expected actualPass startStateTrans =
-- | Runs a given AST pass and returns the subsequent state, along with either an error or the result. This function is primarily intended for internal use by this module.
runPass :: TestMonad m r =>
PassM b -- ^ The actual pass.
runPass :: (Data b, TestMonad m r) =>
Pass -> b -- ^ The actual pass.
-> CompState -- ^ The state to use to run the pass.
-> m (CompState, Either ErrorReport b) -- ^ The resultant state, and either an error or the successful outcome of the pass.
runPass actualPass startState = liftM (\(x,y,_) -> (y,x)) $
runIO (runPassM startState actualPass)
runPass actualPass src startState = liftM (\(x,y,_) -> (y,x)) $
runIO (runPassM startState $ passCode actualPass src)
runPass' :: TestMonad m r =>
PassM b -> CompState -> m (CompState, Either ErrorReport b)
runPass' actualPass startState
= runIO (runPassM startState actualPass) >>* \(x,y,_) -> (y,x)
-- | A test that runs a given AST pass and checks that it succeeds.
testPass ::
(Data a, Data b, TestMonad m r) =>
String -- ^ The test name.
-> a -- ^ The expected value. Can either be an actual AST, or a 'Pattern' to match an AST.
-> PassM b -- ^ The actual pass.
-> Pass -- ^ The actual pass.
-> b -- ^ The source for the actual pass
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> m ()
--If Items are returned by testPassGetItems we return () [i.e. give an empty assertion], otherwise give back the assertion:
testPass w x y z = join $ liftM (either (id) (\x -> return ())) $ (liftM snd) $ (testPassGetItems w x y z)
testPass w x x' y z = join $ testPassGetItems w x x' y z >>* (either id (const $ return ()) . snd)
testPass' ::
(Data a, Show a, Eq a, Data b, TestMonad m r) =>
String -> a -> PassM b -> State CompState () -> m ()
testPass' name exp act st
= runPass' act (execState st emptyState)
>>= \x -> case snd x of
Left err -> testFailure $ name ++ " expected to pass but failed: " ++
show err
Right x' -> testPatternMatch name exp x'
-- | A test that runs a given AST pass and checks that it succeeds, and performs an additional check on the result
testPassWithCheck ::
(Data a, Data b, TestMonad m r) =>
String -- ^ The test name.
-> a -- ^ The expected value. Can either be an actual AST, or a 'Pattern' to match an AST.
-> PassM b -- ^ The actual pass.
-> Pass -- ^ The actual pass.
-> b -- ^ The source for the actual pass
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> (b -> m ())
-> m ()
testPassWithCheck testName expected actualPass startStateTrans checkFunc =
do passResult <- runPass actualPass (execState startStateTrans emptyState)
testPassWithCheck testName expected actualPass src startStateTrans checkFunc =
do passResult <- runPass actualPass src (execState startStateTrans emptyState)
case snd passResult of
Left (_,err) -> testFailure (testName ++ "; pass actually failed: " ++ err)
Right result -> (testPatternMatch testName expected result) >> (checkFunc result)
@ -522,12 +542,13 @@ testPassWithItemsCheck ::
(Data a, Data b, TestMonad m r) =>
String -- ^ The test name.
-> a -- ^ The expected value. Can either be an actual AST, or a 'Pattern' to match an AST.
-> PassM b -- ^ The actual pass.
-> Pass -- ^ The actual pass.
-> b -- ^ The source for the actual pass
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> (Items -> m ()) -- ^ A function to check the 'Items' once the pass succeeds.
-> m ()
testPassWithItemsCheck testName expected actualPass startStateTrans checkFunc =
((liftM snd) (testPassGetItems testName expected actualPass startStateTrans))
testPassWithItemsCheck testName expected actualPass src startStateTrans checkFunc =
((liftM snd) (testPassGetItems testName expected actualPass src startStateTrans))
>>= (\res ->
case res of
Left assert -> assert
@ -539,12 +560,13 @@ testPassWithStateCheck ::
(Data a, Data b, TestMonad m r) =>
String -- ^ The test name.
-> a -- ^ The expected value. Can either be an actual AST, or a 'Pattern' to match an AST.
-> PassM b -- ^ The actual pass.
-> Pass -- ^ The actual pass.
-> b -- ^ The source for the actual pass
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> (CompState -> m ()) -- ^ A function to check the 'CompState' once the pass succeeds.
-> m ()
testPassWithStateCheck testName expected actualPass startStateTrans checkFunc =
(testPassGetItems testName expected actualPass startStateTrans)
testPassWithStateCheck testName expected actualPass src startStateTrans checkFunc =
(testPassGetItems testName expected actualPass src startStateTrans)
>>= (\x ->
case x of
(_,Left assert) -> assert
@ -556,12 +578,13 @@ testPassWithItemsStateCheck ::
(Data a, Data b, TestMonad m r) =>
String -- ^ The test name.
-> a -- ^ The expected value. Can either be an actual AST, or a 'Pattern' to match an AST.
-> PassM b -- ^ The actual pass.
-> Pass -- ^ The actual pass.
-> b -- ^ The source for the actual pass
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> ((Items,CompState) -> m ()) -- ^ A function to check the 'Items' and 'CompState' once the pass succeeds.
-> m ()
testPassWithItemsStateCheck testName expected actualPass startStateTrans checkFunc =
(testPassGetItems testName expected actualPass startStateTrans)
testPassWithItemsStateCheck testName expected actualPass src startStateTrans checkFunc =
(testPassGetItems testName expected actualPass src startStateTrans)
>>= (\x ->
case x of
(_,Left assert) -> assert
@ -572,15 +595,29 @@ testPassWithItemsStateCheck testName expected actualPass startStateTrans checkFu
testPassShouldFail ::
(Show b, Data b, TestMonad m r) =>
String -- ^ The test name.
-> PassM b -- ^ The actual pass.
-> Pass -- ^ The actual pass.
-> b -- ^ The source for the actual pass
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> m ()
testPassShouldFail testName actualPass startStateTrans =
do ret <- runPass actualPass (execState startStateTrans emptyState)
testPassShouldFail testName actualPass src startStateTrans =
do ret <- runPass actualPass src (execState startStateTrans emptyState)
case ret of
(_,Left err) -> return ()
(state, Right output) -> testFailure $ testName ++ " pass succeeded when expected to fail; output: " ++ pshow output
testPassShouldFail' ::
(Show b, Data b, TestMonad m r) =>
String -- ^ The test name.
-> PassM b -- ^ The actual pass.
-> (State CompState ()) -- ^ A function to transform a 'CompState'. Will be used on the 'emptyState' to get the initial state for the pass.
-> m ()
testPassShouldFail' testName actualPass startStateTrans =
do ret <- runPass' actualPass (execState startStateTrans emptyState)
case ret of
(_,Left err) -> return ()
(state, Right output) -> testFailure $ testName ++ " pass succeeded when expected to fail; output: " ++ pshow output
--}}}
--{{{ miscellaneous utilities

View File

@ -36,34 +36,22 @@ import Types
-- | Occam-specific frontend passes.
occamPasses :: [Pass]
occamPasses = makePassesDep' ((== FrontendOccam) . csFrontend)
[ ("Dummy occam pass", dummyOccamPass,
[],
Prop.agg_namesDone ++ [Prop.mainTagged])
, ("Infer types", inferTypes,
[],
[Prop.inferredTypesRecorded])
, ("Fold constants", foldConstants,
[Prop.inferredTypesRecorded],
[Prop.constantsFolded])
, ("Fix the types of array constructors", fixConstructorTypes,
[Prop.constantsFolded],
[Prop.arrayConstructorTypesDone])
, ("Check mandatory constants", checkConstants,
[Prop.constantsFolded, Prop.arrayConstructorTypesDone],
[Prop.constantsChecked])
, ("Resolve ambiguities", resolveAmbiguities,
[Prop.inferredTypesRecorded],
[Prop.ambiguitiesResolved])
, ("Check types", checkTypes,
[Prop.inferredTypesRecorded, Prop.ambiguitiesResolved],
[Prop.expressionTypesChecked, Prop.processTypesChecked,
Prop.functionTypesChecked, Prop.retypesChecked])
occamPasses =
[ occamOnlyPass "Dummy occam pass" [] (Prop.agg_namesDone ++ [Prop.mainTagged]) return
, inferTypes
, foldConstants
, fixConstructorTypes
, checkConstants
, resolveAmbiguities
, checkTypes
]
-- | Fixed the types of array constructors according to the replicator count
fixConstructorTypes :: Data t => t -> PassM t
fixConstructorTypes = applyDepthM doExpression
fixConstructorTypes :: Pass
fixConstructorTypes = occamOnlyPass "Fix the types of array constructors"
[Prop.constantsFolded]
[Prop.arrayConstructorTypesDone]
$ applyDepthM doExpression
where
doExpression :: A.Expression -> PassM A.Expression
doExpression (A.ExprConstr m (A.RepConstr m' _ rep expr))
@ -74,8 +62,11 @@ fixConstructorTypes = applyDepthM doExpression
doExpression e = return e
-- | Handle ambiguities in the occam syntax that the parser can't resolve.
resolveAmbiguities :: Data t => t -> PassM t
resolveAmbiguities = applyDepthM doExpressionList
resolveAmbiguities :: Pass
resolveAmbiguities = occamOnlyPass "Resolve ambiguities"
[Prop.inferredTypesRecorded]
[Prop.ambiguitiesResolved]
$ applyDepthM doExpressionList
where
doExpressionList :: Transform A.ExpressionList
-- A single function call inside an ExpressionList is actually a
@ -85,8 +76,11 @@ resolveAmbiguities = applyDepthM doExpressionList
doExpressionList e = return e
-- | Fold constant expressions.
foldConstants :: Data t => t -> PassM t
foldConstants = applyDepthM2 doExpression doSpecification
foldConstants :: Pass
foldConstants = occamOnlyPass "Fold constants"
[Prop.inferredTypesRecorded]
[Prop.constantsFolded]
$ applyDepthM2 doExpression doSpecification
where
-- Try to fold all expressions we encounter. Since we've recursed into the
-- expression first, this'll also fold subexpressions of non-constant
@ -105,8 +99,11 @@ foldConstants = applyDepthM2 doExpression doSpecification
return s
-- | Check that things that must be constant are.
checkConstants :: Data t => t -> PassM t
checkConstants = applyDepthM2 doDimension doOption
checkConstants :: Pass
checkConstants = occamOnlyPass "Check mandatory constants"
[Prop.constantsFolded, Prop.arrayConstructorTypesDone]
[Prop.constantsChecked]
$ applyDepthM2 doDimension doOption
where
-- Check array dimensions are constant.
doDimension :: A.Dimension -> PassM A.Dimension
@ -125,7 +122,4 @@ checkConstants = applyDepthM2 doDimension doOption
return o
doOption o = return o
-- | A dummy pass for things that haven't been separated out into passes yet.
dummyOccamPass :: Data t => t -> PassM t
dummyOccamPass = return

View File

@ -90,7 +90,7 @@ testFoldConstants = TestList
where
test :: Data a => Int -> a -> a -> Test
test n orig exp = TestCase $ testPass ("testFoldConstants" ++ show n)
exp (OccamPasses.foldConstants orig)
exp OccamPasses.foldConstants orig
startState
testSame :: Int -> A.Expression -> Test
@ -138,13 +138,13 @@ testCheckConstants = TestList
testOK :: (Show a, Data a) => Int -> a -> Test
testOK n orig
= TestCase $ testPass ("testCheckConstants" ++ show n)
orig (OccamPasses.checkConstants orig)
orig OccamPasses.checkConstants orig
(return ())
testFail :: (Show a, Data a) => Int -> a -> Test
testFail n orig
= TestCase $ testPassShouldFail ("testCheckConstants" ++ show n)
(OccamPasses.checkConstants orig)
OccamPasses.checkConstants orig
(return ())
dim10 = A.Dimension $ intLiteral 10

View File

@ -30,6 +30,7 @@ import EvalConstants
import Intrinsics
import Metadata
import Pass
import qualified Properties as Prop
import ShowCode
import Traversal
import Types
@ -602,8 +603,11 @@ inSubscriptedContext m body
--{{{ inferTypes
-- | Infer types.
inferTypes :: PassType
inferTypes = recurse
inferTypes :: Pass
inferTypes = occamOnlyPass "Infer types"
[]
[Prop.inferredTypesRecorded]
$ recurse
where
ops :: Ops
ops = baseOp
@ -999,12 +1003,15 @@ inferTypes = recurse
-- | Check the AST for type consistency.
-- This is actually a series of smaller passes that check particular types
-- inside the AST, but it doesn't really make sense to split it up.
checkTypes :: PassType
checkTypes t =
checkVariables t >>=
checkExpressions >>=
checkSpecTypes >>=
checkProcesses >>=
checkTypes :: Pass
checkTypes = occamOnlyPass "Check types"
[Prop.inferredTypesRecorded, Prop.ambiguitiesResolved]
[Prop.expressionTypesChecked, Prop.processTypesChecked,
Prop.functionTypesChecked, Prop.retypesChecked]
$ checkVariables >.>
checkExpressions >.>
checkSpecTypes >.>
checkProcesses >.>
checkReplicators
--{{{ checkVariables

View File

@ -513,13 +513,13 @@ testOccamTypes = TestList
testOK :: (Show a, Data a) => Int -> a -> Test
testOK n orig
= TestCase $ testPass ("testOccamTypes" ++ show n)
orig (OccamTypes.checkTypes orig)
orig OccamTypes.checkTypes orig
startState
testFail :: (Show a, Data a) => Int -> a -> Test
testFail n orig
= TestCase $ testPassShouldFail ("testOccamTypes" ++ show n)
(OccamTypes.checkTypes orig)
OccamTypes.checkTypes orig
startState
--{{{ expression fragments

View File

@ -28,7 +28,7 @@ import TestUtils
-- | Test 'preprocessOccam' when we're expecting it to succeed.
testPP :: Int -> [TokenType] -> [TokenType] -> Test
testPP n itts etts = TestCase $ testPass ("testPP " ++ show n) (makeTokens etts) pass (return ())
testPP n itts etts = TestCase $ testPass' ("testPP " ++ show n) (makeTokens etts) pass (return ())
where
makeTokens = zip (repeat emptyMeta)
pass = preprocessOccam (makeTokens itts)
@ -47,21 +47,21 @@ testPPCond n = testPPCondAfter n []
-- | Test 'preprocessOccam' when we're expecting it to fail.
testPPFail :: Int -> [TokenType] -> Test
testPPFail n itts = TestCase $ testPassShouldFail ("testPPFail " ++ show n) pass (return ())
testPPFail n itts = TestCase $ testPassShouldFail' ("testPPFail " ++ show n) pass (return ())
where
makeTokens = zip (repeat emptyMeta)
pass = preprocessOccam (makeTokens itts)
-- | Test 'expandIncludes' when we're expecting it to succeed.
testEI :: Int -> [TokenType] -> [TokenType] -> Test
testEI n itts etts = TestCase $ testPass ("testEI " ++ show n) (makeTokens etts) pass (return ())
testEI n itts etts = TestCase $ testPass' ("testEI " ++ show n) (makeTokens etts) pass (return ())
where
makeTokens = zip (repeat emptyMeta)
pass = expandIncludes (makeTokens itts)
-- | Test 'expandIncludes' when we're expecting it to fail.
testEIFail :: Int -> [TokenType] -> Test
testEIFail n itts = TestCase $ testPassShouldFail ("testEIFail " ++ show n) pass (return ())
testEIFail n itts = TestCase $ testPassShouldFail' ("testEIFail " ++ show n) pass (return ())
where
makeTokens = zip (repeat emptyMeta)
pass = expandIncludes (makeTokens itts)

View File

@ -40,7 +40,7 @@ import Types
-- | An ordered list of the Rain-specific passes to be run.
rainPasses :: [Pass]
rainPasses = let f = makePassesDep' ((== FrontendRain) . csFrontend) in
rainPasses =
[ excludeNonRainFeatures
, rainOnlyPass "Dummy Rain pass" [] [Prop.retypesChecked] return
, transformInt

View File

@ -39,12 +39,14 @@ import qualified AST as A
import CompState
import Errors
import Metadata
import Pass
import Pattern
import RainPasses
import RainTypes
import TagAST
import TestUtils
import TreeUtils
import Utils
m :: Meta
m = emptyMeta
@ -65,7 +67,7 @@ makeRange b e = A.Dyadic emptyMeta A.Add (intLiteral 1)
(A.Dyadic emptyMeta A.Subtr (intLiteral e) (intLiteral b))
testEachRangePass0 :: Test
testEachRangePass0 = TestCase $ testPass "testEachRangePass0" exp (transformEachRange orig) (return ())
testEachRangePass0 = TestCase $ testPass "testEachRangePass0" exp transformEachRange orig (return ())
where
orig = A.Par m A.PlainPar $ A.Rep m
(A.ForEach m (simpleName "x") (A.ExprConstr m (A.RangeConstr m
@ -76,7 +78,7 @@ testEachRangePass0 = TestCase $ testPass "testEachRangePass0" exp (transformEach
(A.Only m (makeSimpleAssign "c" "x"))
testEachRangePass1 :: Test
testEachRangePass1 = TestCase $ testPass "testEachRangePass1" exp (transformEachRange orig) (return ())
testEachRangePass1 = TestCase $ testPass "testEachRangePass1" exp transformEachRange orig (return ())
where
orig = A.Par m A.PlainPar $ A.Rep m
(A.ForEach m (simpleName "x") (A.ExprConstr m (A.RangeConstr m undefined
@ -88,7 +90,7 @@ testEachRangePass1 = TestCase $ testPass "testEachRangePass1" exp (transformEach
(A.Only m (makeSimpleAssign "c" "x"))
testEachRangePass2 :: Test
testEachRangePass2 = TestCase $ testPass "testEachRangePass2" exp (transformEachRange orig) (return ())
testEachRangePass2 = TestCase $ testPass "testEachRangePass2" exp transformEachRange orig (return ())
where
orig = A.Seq m $ A.Rep m
(A.ForEach m (simpleName "x") (A.ExprConstr m (A.RangeConstr m undefined
@ -99,7 +101,7 @@ testEachRangePass2 = TestCase $ testPass "testEachRangePass2" exp (transformEach
(A.Only m (makeSimpleAssign "c" "x"))
testEachRangePass3 :: Test
testEachRangePass3 = TestCase $ testPass "testEachRangePass3" exp (transformEachRange orig) (return ())
testEachRangePass3 = TestCase $ testPass "testEachRangePass3" exp transformEachRange orig (return ())
where
orig = A.Seq m $ A.Rep m
(A.ForEach m (simpleName "x") (A.ExprConstr m (A.RangeConstr m undefined
@ -112,7 +114,7 @@ testEachRangePass3 = TestCase $ testPass "testEachRangePass3" exp (transformEach
-- | Test variable is made unique in a declaration:
testUnique0 :: Test
testUnique0 = TestCase $ testPassWithItemsStateCheck "testUnique0" exp (uniquifyAndResolveVars orig) (return ()) check
testUnique0 = TestCase $ testPassWithItemsStateCheck "testUnique0" exp uniquifyAndResolveVars orig (return ()) check
where
orig = A.Spec m (A.Specification m (simpleName "c") $ A.Declaration m A.Byte) skipP
exp = mSpecP (tag3 A.Specification DontCare ("newc"@@DontCare) $ A.Declaration m A.Byte) skipP
@ -124,7 +126,7 @@ testUnique0 = TestCase $ testPassWithItemsStateCheck "testUnique0" exp (uniquify
-- | Tests that two declarations of a variable with the same name are indeed made unique:
testUnique1 :: Test
testUnique1 = TestCase $ testPassWithItemsStateCheck "testUnique1" exp (uniquifyAndResolveVars orig) (return ()) check
testUnique1 = TestCase $ testPassWithItemsStateCheck "testUnique1" exp uniquifyAndResolveVars orig (return ()) check
where
orig = A.Several m [A.Spec m (A.Specification m (simpleName "c") $ A.Declaration m A.Byte ) skipP,
A.Spec m (A.Specification m (simpleName "c") $ A.Declaration m A.Int64 ) skipP]
@ -143,7 +145,7 @@ testUnique1 = TestCase $ testPassWithItemsStateCheck "testUnique1" exp (uniquify
-- | Tests that the unique pass does resolve the variables that are in scope
testUnique2 :: Test
testUnique2 = TestCase $ testPassWithItemsStateCheck "testUnique2" exp (uniquifyAndResolveVars orig) (return ()) check
testUnique2 = TestCase $ testPassWithItemsStateCheck "testUnique2" exp uniquifyAndResolveVars orig (return ()) check
where
orig = A.Spec m (A.Specification m (simpleName "c") $ A.Declaration m A.Byte ) (A.Only m $ makeSimpleAssign "c" "d")
exp = mSpecP (tag3 A.Specification DontCare ("newc"@@DontCare) $ A.Declaration m A.Byte )
@ -153,7 +155,7 @@ testUnique2 = TestCase $ testPassWithItemsStateCheck "testUnique2" exp (uniquify
testUnique2b :: Test
testUnique2b = TestCase $ testPassWithItemsStateCheck "testUnique2b" exp (uniquifyAndResolveVars orig) (return ()) check
testUnique2b = TestCase $ testPassWithItemsStateCheck "testUnique2b" exp uniquifyAndResolveVars orig (return ()) check
where
orig = A.Spec m (A.Specification m (simpleName "c") $ A.Declaration m A.Byte ) $
A.Several m [(A.Only m $ makeSimpleAssign "c" "d"),(A.Only m $ makeSimpleAssign "c" "e")]
@ -168,7 +170,7 @@ testUnique2b = TestCase $ testPassWithItemsStateCheck "testUnique2b" exp (uniqui
-- | Tests that proc names are recorded, but not made unique (because they might be exported), and not resolved either
testUnique3 :: Test
testUnique3 = TestCase $ testPassWithItemsStateCheck "testUnique3" exp (uniquifyAndResolveVars orig) (return ()) check
testUnique3 = TestCase $ testPassWithItemsStateCheck "testUnique3" exp uniquifyAndResolveVars orig (return ()) check
where
orig = A.Spec m (A.Specification m (procName "foo") $ A.Proc m A.PlainSpec [] $ A.Skip m) (A.Only m $ A.ProcCall m (procName "foo") [])
exp = orig
@ -177,7 +179,7 @@ testUnique3 = TestCase $ testPassWithItemsStateCheck "testUnique3" exp (uniquify
-- | Tests that parameters are uniquified and resolved:
testUnique4 :: Test
testUnique4 = TestCase $ testPassWithItemsStateCheck "testUnique4" exp (uniquifyAndResolveVars orig) (return ()) check
testUnique4 = TestCase $ testPassWithItemsStateCheck "testUnique4" exp uniquifyAndResolveVars orig (return ()) check
where
orig = A.Spec m (A.Specification m (procName "foo") $ A.Proc m A.PlainSpec [A.Formal A.ValAbbrev A.Byte $ simpleName "c"] $
A.ProcCall m (procName "foo") [A.ActualExpression $ exprVariable "c"]) (skipP)
@ -207,7 +209,7 @@ testUnique4 = TestCase $ testPassWithItemsStateCheck "testUnique4" exp (uniquify
-- | checks that c's type is recorded in: ***each (c : "hello") {}
testRecordInfNames0 :: Test
testRecordInfNames0 = TestCase $ testPassWithStateCheck "testRecordInfNames0" exp (recordInfNameTypes orig) (return ()) check
testRecordInfNames0 = TestCase $ testPassWithStateCheck "testRecordInfNames0" exp recordInfNameTypes orig (return ()) check
where
orig = (A.Rep m (A.ForEach m (simpleName "c") (makeLiteralStringRain "hello")) skipP)
exp = orig
@ -217,7 +219,7 @@ testRecordInfNames0 = TestCase $ testPassWithStateCheck "testRecordInfNames0" ex
-- | checks that c's type is recorded in: ***each (c : str) {}, where str is known to be of type string
testRecordInfNames1 :: Test
testRecordInfNames1 = TestCase $ testPassWithStateCheck "testRecordInfNames1" exp (recordInfNameTypes orig) (startState') check
testRecordInfNames1 = TestCase $ testPassWithStateCheck "testRecordInfNames1" exp recordInfNameTypes orig (startState') check
where
startState' :: State CompState ()
startState' = do defineName (simpleName "str") $ simpleDef "str" (A.Declaration m (A.List A.Byte) )
@ -229,7 +231,7 @@ testRecordInfNames1 = TestCase $ testPassWithStateCheck "testRecordInfNames1" ex
-- | checks that c's and d's type are recorded in: ***each (c : multi) { seqeach (d : c) {} } where multi is known to be of type [string]
testRecordInfNames2 :: Test
testRecordInfNames2 = TestCase $ testPassWithStateCheck "testRecordInfNames2" exp (recordInfNameTypes orig) (startState') check
testRecordInfNames2 = TestCase $ testPassWithStateCheck "testRecordInfNames2" exp recordInfNameTypes orig (startState') check
where
startState' :: State CompState ()
startState' = do defineName (simpleName "multi") $ simpleDef "multi" (A.Declaration m (A.List $ A.List A.Byte) )
@ -246,8 +248,8 @@ testRecordInfNames2 = TestCase $ testPassWithStateCheck "testRecordInfNames2" ex
"d") A.Abbrev A.Unplaced)
--Easy way to string two passes together; creates a pass-like function that applies the left-hand pass then the right-hand pass. Associative.
(>>>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
(>>>) f0 f1 x = (f0 x) >>= f1
(>>>) :: Pass -> Pass -> Pass
(>>>) f0 f1 = Pass {passCode = passCode f1 <.< passCode f0}
--Normally, process names in Rain are not mangled. And this should be fine in all cases - but not for the main process (which would
--result in a function called main. Therefore we must mangle main. Ideally into a nonce, but for now into ____main
@ -255,7 +257,7 @@ testRecordInfNames2 = TestCase $ testPassWithStateCheck "testRecordInfNames2" ex
--TODO check recursive main function works
testFindMain0 :: Test
testFindMain0 = TestCase $ testPassWithItemsStateCheck "testFindMain0" exp ((uniquifyAndResolveVars >>> findMain) orig) (return ()) check
testFindMain0 = TestCase $ testPassWithItemsStateCheck "testFindMain0" exp (uniquifyAndResolveVars >>> findMain) orig (return ()) check
where
orig = A.Spec m (A.Specification m (A.Name m "main") $ A.Proc m A.PlainSpec [] (A.Skip m)) $ A.Several m [] :: A.AST
exp = mSpecAST (tag3 A.Specification DontCare (tag2 A.Name DontCare ("main"@@DontCare)) $
@ -268,13 +270,13 @@ testFindMain0 = TestCase $ testPassWithItemsStateCheck "testFindMain0" exp ((uni
(tag6 A.NameDef DontCare mainName "main" DontCare A.Original A.Unplaced)
testFindMain1 :: Test
testFindMain1 = TestCase $ testPassWithStateCheck "testFindMain1" orig ((uniquifyAndResolveVars >>> findMain) orig) (return ()) check
testFindMain1 = TestCase $ testPassWithStateCheck "testFindMain1" orig (uniquifyAndResolveVars >>> findMain) orig (return ()) check
where
orig = A.Spec m (A.Specification m (A.Name m "foo") $ A.Proc m A.PlainSpec [] (A.Skip m)) $ A.Several m ([] :: [A.AST])
check state = assertEqual "testFindMain1" [] (csMainLocals state)
testFindMain2 :: Test
testFindMain2 = TestCase $ testPassWithItemsStateCheck "testFindMain2" exp ((uniquifyAndResolveVars >>> findMain) orig) (return ()) check
testFindMain2 = TestCase $ testPassWithItemsStateCheck "testFindMain2" exp (uniquifyAndResolveVars >>> findMain) orig (return ()) check
where
inner = A.Spec m (A.Specification m (A.Name m "foo") $ A.Proc m A.PlainSpec [] (A.Skip m)) $
A.Several m ([] :: [A.AST])
@ -296,10 +298,10 @@ testParamPass ::
testParamPass testName formals params transParams
= case transParams of
Just act -> TestList [TestCase $ testPass (testName ++ "/process") (expProc act) (performTypeUnification origProc) startStateProc,
TestCase $ testPass (testName ++ "/function") (expFunc act) (performTypeUnification origFunc) startStateFunc]
Nothing -> TestList [TestCase $ testPassShouldFail (testName ++ "/process") (performTypeUnification origProc) startStateProc,
TestCase $ testPassShouldFail (testName ++ "/function") (performTypeUnification origFunc) startStateFunc]
Just act -> TestList [TestCase $ testPass (testName ++ "/process") (expProc act) performTypeUnification origProc startStateProc,
TestCase $ testPass (testName ++ "/function") (expFunc act) performTypeUnification origFunc startStateFunc]
Nothing -> TestList [TestCase $ testPassShouldFail (testName ++ "/process") performTypeUnification origProc startStateProc,
TestCase $ testPassShouldFail (testName ++ "/function") performTypeUnification origFunc startStateFunc]
where
startStateProc :: State CompState ()
startStateProc = do defineName (simpleName "x") $ simpleDefDecl "x" (A.UInt16)
@ -378,8 +380,8 @@ testParamPass7 = testParamPass "testParamPass7"
-- | Test calling something that is not a process:
testParamPass8 :: Test
testParamPass8 = TestList [TestCase $ testPassShouldFail "testParamPass8/process" (performTypeUnification origProc) (startState'),
TestCase $ testPassShouldFail "testParamPass8/function" (performTypeUnification origFunc) (startState')]
testParamPass8 = TestList [TestCase $ testPassShouldFail "testParamPass8/process" performTypeUnification origProc (startState'),
TestCase $ testPassShouldFail "testParamPass8/function" performTypeUnification origFunc (startState')]
where
startState' :: State CompState ()
startState' = do defineName (simpleName "x") $ simpleDefDecl "x" (A.UInt16)
@ -390,7 +392,7 @@ testParamPass8 = TestList [TestCase $ testPassShouldFail "testParamPass8/process
-- | Transform an example list
testRangeRepPass0 :: Test
testRangeRepPass0 = TestCase $ testPass "testRangeRepPass0" exp (transformRangeRep orig) (return())
testRangeRepPass0 = TestCase $ testPass "testRangeRepPass0" exp transformRangeRep orig (return())
where
orig = A.ExprConstr m $ A.RangeConstr m A.Byte (intLiteral 0) (intLiteral 1)
exp = tag2 A.ExprConstr DontCare $ mRepConstr A.Byte
@ -399,9 +401,10 @@ testRangeRepPass0 = TestCase $ testPass "testRangeRepPass0" exp (transformRangeR
--TODO consider/test pulling up the definitions of variables involved in return statements in functions
{-
-- | Test a fairly standard function:
testCheckFunction0 :: Test
testCheckFunction0 = TestCase $ testPass "testCheckFunction0" orig (checkFunction orig) (return ())
testCheckFunction0 = TestCase $ testPass "testCheckFunction0" orig checkFunction orig (return ())
where
orig = A.Specification m (procName "id") $
A.Function m A.PlainSpec [A.Byte] [A.Formal A.ValAbbrev A.Byte (simpleName "x")] $ Right
@ -409,26 +412,26 @@ testCheckFunction0 = TestCase $ testPass "testCheckFunction0" orig (checkFunctio
-- | Test a function without a return as the final statement:
testCheckFunction1 :: Test
testCheckFunction1 = TestCase $ testPassShouldFail "testCheckunction1" (checkFunction orig) (return ())
testCheckFunction1 = TestCase $ testPassShouldFail "testCheckFunction1" checkFunction orig (return ())
where
orig = A.Specification m (procName "brokenid") $
A.Function m A.PlainSpec [A.Byte] [A.Formal A.ValAbbrev A.Byte (simpleName "x")] $
(Right $ A.Seq m $ A.Several m [])
-}
testPullUpParDecl0 :: Test
testPullUpParDecl0 = TestCase $ testPass "testPullUpParDecl0" orig (pullUpParDeclarations orig) (return ())
testPullUpParDecl0 = TestCase $ testPass "testPullUpParDecl0" orig pullUpParDeclarations orig (return ())
where
orig = A.Par m A.PlainPar (A.Several m [])
testPullUpParDecl1 :: Test
testPullUpParDecl1 = TestCase $ testPass "testPullUpParDecl1" exp (pullUpParDeclarations orig) (return ())
testPullUpParDecl1 = TestCase $ testPass "testPullUpParDecl1" exp pullUpParDeclarations orig (return ())
where
orig = A.Par m A.PlainPar $
A.Spec m (A.Specification m (simpleName "x") $ A.Declaration m A.Int) (A.Several m [])
exp = A.Seq m $ A.Spec m (A.Specification m (simpleName "x") $ A.Declaration m A.Int) (A.Only m $ A.Par m A.PlainPar $ A.Several m [])
testPullUpParDecl2 :: Test
testPullUpParDecl2 = TestCase $ testPass "testPullUpParDecl2" exp (pullUpParDeclarations orig) (return ())
testPullUpParDecl2 = TestCase $ testPass "testPullUpParDecl2" exp pullUpParDeclarations orig (return ())
where
orig = A.Par m A.PlainPar $
A.Spec m (A.Specification m (simpleName "x") $ A.Declaration m A.Int) $
@ -468,8 +471,8 @@ tests = TestLabel "RainPassesTest" $ TestList
,testParamPass7
,testParamPass8
,testRangeRepPass0
,testCheckFunction0
,testCheckFunction1
-- ,testCheckFunction0
-- ,testCheckFunction1
,testPullUpParDecl0
,testPullUpParDecl1
,testPullUpParDecl2

View File

@ -63,10 +63,10 @@ constantFoldTest = TestList
two63 = 9223372036854775808
foldVar :: Int -> ExprHelper -> Test
foldVar n e = TestCase $ testPass ("constantFoldTest " ++ show n) (buildExprPattern e) (constantFoldPass $ buildExpr e) state
foldVar n e = TestCase $ testPass ("constantFoldTest " ++ show n) (buildExprPattern e) constantFoldPass (buildExpr e) state
foldCon :: Int -> ExprHelper -> ExprHelper -> Test
foldCon n exp orig = TestCase $ testPass ("constantFoldTest " ++ show n) (buildExprPattern exp) (constantFoldPass $ buildExpr orig) state
foldCon n exp orig = TestCase $ testPass ("constantFoldTest " ++ show n) (buildExprPattern exp) constantFoldPass (buildExpr orig) state
state :: State CompState ()
state = defineVariable "x" A.Int64

View File

@ -30,13 +30,13 @@ import TreeUtils
-- | Test 'structureOccam' when we're expecting it to succeed.
testS :: Int -> [Token] -> [Pattern] -> Test
testS n its etts = TestCase $ testPass ("testS " ++ show n) ets (structureOccam its) (return ())
testS n its etts = TestCase $ testPass' ("testS " ++ show n) ets (structureOccam its) (return ())
where
ets = zip (repeat DontCare) etts
-- | Test 'structureOccam' when we're expecting it to fail.
testSFail :: Int -> [Token] -> Test
testSFail n its = TestCase $ testPassShouldFail ("testSFail " ++ show n) (structureOccam its) (return ())
testSFail n its = TestCase $ testPassShouldFail' ("testSFail " ++ show n) (structureOccam its) (return ())
--{{{ 0xxx simple stuff
testSimple :: Test

View File

@ -105,13 +105,6 @@ runPassM cs pass = liftM flatten $ flip runStateT [] $ flip runStateT cs $ runEr
flatten :: ((a, b),c) -> (a, b, c)
flatten ((x, y), z) = (x, y, z)
makePassesDep :: [(String, forall t. Data t => t -> PassM t, [Property], [Property])] -> [Pass]
makePassesDep = map (\(s, p, pre, post) -> Pass p s (Set.fromList pre) (Set.fromList post) (const True))
makePassesDep' :: (CompState -> Bool) -> [(String, forall t. Data t => t -> PassM t, [Property], [Property])] -> [Pass]
makePassesDep' f = map (\(s, p, pre, post) -> Pass p s (Set.fromList pre) (Set.fromList post) f)
enablePassesWhen :: (CompState -> Bool) -> [Pass] -> [Pass]
enablePassesWhen f = map (\p -> p
{passEnabled = \c -> f c && (passEnabled p c)})
@ -158,7 +151,6 @@ pass name pre post code
,passEnabled = const True
}
-- | Compose a list of passes into a single pass by running them in the order given.
runPasses :: [Pass] -> (A.AST -> PassM A.AST)
runPasses [] ast = return ast

View File

@ -48,10 +48,13 @@ commonPasses :: CompState -> [Pass]
commonPasses opts = concat $
-- Rain does simplifyTypes separately:
[ enablePassesWhen ((== FrontendOccam) . csFrontend) simplifyTypes
, makePassesDep' csUsageChecking [("Usage checking", passOnlyOnAST "usageCheckPass"
$ runPassR usageCheckPass, Prop.agg_namesDone, [Prop.parUsageChecked])]
, enablePassesWhen csUsageChecking
[pass "Usage checking" Prop.agg_namesDone [Prop.parUsageChecked]
$ passOnlyOnAST "usageCheckPass" $ runPassR usageCheckPass]
-- If usage checking is turned off, the pass list will break unless we insert this dummy item:
, makePassesDep' (not . csUsageChecking) [("Usage checking turned OFF", return, Prop.agg_namesDone, [Prop.parUsageChecked])]
, enablePassesWhen (not . csUsageChecking)
[pass "Usage checking turned OFF" Prop.agg_namesDone [Prop.parUsageChecked]
return]
, simplifyComms
, simplifyExprs
, simplifyProcs

View File

@ -74,7 +74,7 @@ singleParamSpecExp body = tag4 A.Proc DontCare A.PlainSpec [tag3 A.Formal A.ValA
-- | Tests a function with a single return, and a single parameter.
testFunctionsToProcs0 :: Test
testFunctionsToProcs0 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs0" exp (functionsToProcs orig) (return ()) check
testFunctionsToProcs0 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs0" exp functionsToProcs orig (return ()) check
where
orig = singleParamFunc valof0
exp = tag3 A.Specification DontCare (simpleName "foo") procSpec
@ -91,7 +91,7 @@ testFunctionsToProcs0 = TestCase $ testPassWithItemsStateCheck "testFunctionsToP
-- | Tests a function with multiple returns, and multiple parameters.
testFunctionsToProcs1 :: Test
testFunctionsToProcs1 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs1 A" exp (functionsToProcs orig) (return ()) check
testFunctionsToProcs1 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs1 A" exp functionsToProcs orig (return ()) check
where
orig = A.Specification m (simpleName "foo") (A.Function m A.PlainSpec [A.Int,A.Real32]
[A.Formal A.ValAbbrev A.Byte (simpleName "param0"),A.Formal A.Abbrev A.Real32 (simpleName "param1")] (Left $ valofTwo "param0" "param1"))
@ -121,7 +121,7 @@ testFunctionsToProcs1 = TestCase $ testPassWithItemsStateCheck "testFunctionsToP
-- 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
testFunctionsToProcs2 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs2 A" exp functionsToProcs orig (return ()) check
where
orig = A.Specification m (simpleName "fooOuter") (A.Function m A.PlainSpec [A.Int] [A.Formal A.ValAbbrev A.Byte (simpleName "paramOuter0")] $ Left $
A.Spec m (singleParamFunc valof0) valof0)
@ -152,7 +152,7 @@ testFunctionsToProcs2 = TestCase $ testPassWithItemsStateCheck "testFunctionsToP
-- | 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
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
@ -169,7 +169,7 @@ testFunctionsToProcs3 = TestCase $ testPassWithItemsStateCheck "testFunctionsToP
-- | Tests a function with multiple returns, and multiple parameters.
testFunctionsToProcs4 :: Test
testFunctionsToProcs4 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs4 A" exp (functionsToProcs orig) (return ()) check
testFunctionsToProcs4 = TestCase $ testPassWithItemsStateCheck "testFunctionsToProcs4 A" exp functionsToProcs orig (return ()) check
where
orig = A.Specification m (simpleName "foo") (A.Function m A.PlainSpec [A.Int,A.Real32]
[A.Formal A.ValAbbrev A.Byte (simpleName "param0"),A.Formal A.Abbrev A.Real32 (simpleName "param1")] $
@ -202,7 +202,7 @@ 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
testTransformConstr0 = TestCase $ testPass "transformConstr0" exp transformConstr orig startState
where
startState :: State CompState ()
startState = defineConst "x" A.Int (intLiteral 42)
@ -242,7 +242,7 @@ testOutExprs = TestList
(mOnlyP $ tag3 A.Output emptyMeta chan
[tag2 A.OutExpression emptyMeta (tag2 A.ExprVariable DontCare (tag2 A.Variable DontCare (Named "temp_var" DontCare)))])
)
(outExprs $
outExprs (
A.Output emptyMeta chan [outXM 1]
)
(defineName (xName) $ simpleDefDecl "x" A.Int)
@ -254,7 +254,7 @@ testOutExprs = TestList
(mOnlyP $ tag3 A.Output emptyMeta chan
[outX])
)
(outExprs $
outExprs (
A.Output emptyMeta chan [outX]
)
(return ())
@ -269,7 +269,7 @@ testOutExprs = TestList
]
)
)
(outExprs $
outExprs (
A.Output emptyMeta chan [outXM 1,outX,A.OutExpression emptyMeta $ intLiteral 2]
)
(defineName (xName) $ simpleDefDecl "x" A.Byte)
@ -285,7 +285,7 @@ testOutExprs = TestList
]
)
)
(outExprs $
outExprs (
A.Output emptyMeta chan [A.OutCounted emptyMeta (eXM 1) (exprVariable "x")]
)
(defineName (xName) $ simpleDefDecl "x" A.Byte)
@ -297,7 +297,7 @@ testOutExprs = TestList
(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 $
outExprs (
A.OutputCase emptyMeta chan (simpleName "foo") [outXM 1]
)
(defineName (xName) $ simpleDefDecl "x" A.Int)
@ -309,7 +309,7 @@ testOutExprs = TestList
(tag2 A.Seq DontCare $
(mOnlyP $ A.OutputCase emptyMeta chan (simpleName "foo") [])
)
(outExprs $
outExprs (
A.OutputCase emptyMeta chan (simpleName "foo") []
)
(return ())
@ -354,7 +354,7 @@ testInputCase = TestList
mOnlyO $ tag3 A.Option DontCare [intLiteralPattern 0] p0
]
)
(transformInputCase $
transformInputCase (
A.Input emptyMeta c $ A.InputCase emptyMeta $ A.Only emptyMeta $ A.Variant emptyMeta a0 [] p0
)
(defineMyProtocol >> defineC)
@ -402,7 +402,7 @@ testInputCase = TestList
]
]
)
(transformInputCase $
transformInputCase (
A.Input emptyMeta c $ A.InputCase emptyMeta $ A.Several emptyMeta
[A.Only emptyMeta $ A.Variant emptyMeta a0 [] p0
,A.Only emptyMeta $ A.Variant emptyMeta c1 [A.InVariable emptyMeta z] p1
@ -460,7 +460,7 @@ testInputCase = TestList
]
]
)
(transformInputCase $
transformInputCase (
A.Input emptyMeta c $ A.InputCase emptyMeta $ A.Several emptyMeta
[A.Only emptyMeta $ A.Variant emptyMeta a0 [] p0
,specInt "z" $ A.Only emptyMeta $ A.Variant emptyMeta c1 [A.InVariable emptyMeta z] p1
@ -494,7 +494,7 @@ testInputCase = TestList
tag3 A.Case DontCare (tag2 A.ExprVariable DontCare $ tag2 A.Variable DontCare (Named "tag" DontCare)) $
mOnlyO $ tag3 A.Option DontCare [intLiteralPattern 0] p0
)
(transformInputCase $
transformInputCase (
A.Alt emptyMeta False $ A.Only emptyMeta $ A.Alternative emptyMeta (A.True emptyMeta) c
(A.InputCase emptyMeta $ A.Only emptyMeta $ A.Variant emptyMeta a0 [] p0)
(A.Skip emptyMeta)
@ -529,30 +529,30 @@ testTransformProtocolInput = TestList
[
TestCase $ testPass "testTransformProtocolInput0"
(seqItems [ii0])
(transformProtocolInput $ 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])
transformProtocolInput (seqItems [ii0, ii1, ii2])
(return ())
,TestCase $ testPass "testTransformProtocolInput2"
(A.Alt emptyMeta False $ onlySingleAlt ii0)
(transformProtocolInput $ 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])
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])
transformProtocolInput (A.Alt emptyMeta False $ A.Only emptyMeta $ altItems [ii0, ii1, ii2])
(return ())
]
where
@ -581,7 +581,7 @@ testPullRepCounts = TestList
A.Spec emptyMeta (A.Specification emptyMeta (simpleName "nonce") (A.IsExpr emptyMeta A.ValAbbrev A.Int $ intLiteral 6)) $
A.Rep emptyMeta (A.For emptyMeta (simpleName "i") (intLiteral 0) (exprVariable "nonce")) $ A.Several emptyMeta [])
(pullRepCounts $ A.Seq emptyMeta $ A.Rep emptyMeta (A.For emptyMeta (simpleName "i") (intLiteral 0) (intLiteral 6)) $ A.Several emptyMeta [])
pullRepCounts (A.Seq emptyMeta $ A.Rep emptyMeta (A.For emptyMeta (simpleName "i") (intLiteral 0) (intLiteral 6)) $ A.Several emptyMeta [])
(return ())
,TestCase $ testPass "testPullRepCounts 6"
@ -591,7 +591,7 @@ testPullRepCounts = TestList
A.Spec emptyMeta (A.Specification emptyMeta (simpleName "nonce2") (A.IsExpr emptyMeta A.ValAbbrev A.Int $ intLiteral 8)) $
A.Rep emptyMeta (A.For emptyMeta (simpleName "j") (intLiteral 0) (exprVariable "nonce2")) $ A.Several emptyMeta [])
(pullRepCounts $ A.Seq emptyMeta $ A.Rep emptyMeta (A.For emptyMeta (simpleName "i") (intLiteral 0) (intLiteral 6)) $
pullRepCounts (A.Seq emptyMeta $ A.Rep emptyMeta (A.For emptyMeta (simpleName "i") (intLiteral 0) (intLiteral 6)) $
A.Rep emptyMeta (A.For emptyMeta (simpleName "j") (intLiteral 0) (intLiteral 8)) $ A.Several emptyMeta [])
(return ())
]
@ -600,7 +600,7 @@ testPullRepCounts = TestList
testUnchanged n f = TestCase $ testPass
("testPullRepCounts/testUnchanged " ++ show n)
code
(pullRepCounts code)
pullRepCounts code
(return ())
where
code = (f $ A.Rep emptyMeta (A.For emptyMeta (simpleName "i") (intLiteral 0) (intLiteral 5)) $ A.Several emptyMeta [])

View File

@ -32,14 +32,17 @@ import Types
import Utils
simplifyComms :: [Pass]
simplifyComms = makePassesDep
[ ("Define temporary variables for outputting expressions", outExprs, Prop.agg_namesDone ++ Prop.agg_typesDone, [Prop.outExpressionRemoved])
,("Transform ? CASE statements/guards into plain CASE", transformInputCase, Prop.agg_namesDone ++ Prop.agg_typesDone, [Prop.inputCaseRemoved])
,("Flatten sequential protocol inputs into multiple inputs", transformProtocolInput, Prop.agg_namesDone ++ Prop.agg_typesDone ++ [Prop.inputCaseRemoved], [Prop.seqInputsFlattened])
simplifyComms =
[ outExprs
,transformInputCase
,transformProtocolInput
]
outExprs :: PassType
outExprs = applyDepthM doProcess
outExprs :: Pass
outExprs = pass "Define temporary variables for outputting expressions"
(Prop.agg_namesDone ++ Prop.agg_typesDone)
[Prop.outExpressionRemoved]
$ applyDepthM doProcess
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.Output m c ois)
@ -130,8 +133,11 @@ ALT
-- process D
-}
transformInputCase :: PassType
transformInputCase = applyDepthM doProcess
transformInputCase :: Pass
transformInputCase = pass "Transform ? CASE statements/guards into plain CASE"
(Prop.agg_namesDone ++ Prop.agg_typesDone)
[Prop.inputCaseRemoved]
$ applyDepthM doProcess
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.Input m v (A.InputCase m' s))
@ -174,8 +180,11 @@ transformInputCase = applyDepthM doProcess
-- Leave other guards untouched.
doAlternative m a = return $ A.Only m a
transformProtocolInput :: PassType
transformProtocolInput = applyDepthM2 doProcess doAlternative
transformProtocolInput :: Pass
transformProtocolInput = pass "Flatten sequential protocol inputs into multiple inputs"
(Prop.agg_namesDone ++ Prop.agg_typesDone ++ [Prop.inputCaseRemoved])
[Prop.seqInputsFlattened]
$ applyDepthM2 doProcess doAlternative
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.Input m v (A.InputSimple m' iis@(_:_:_)))

View File

@ -36,21 +36,22 @@ import Types
import Utils
simplifyExprs :: [Pass]
simplifyExprs = makePassesDep
[ ("Convert FUNCTIONs to PROCs", functionsToProcs, Prop.agg_namesDone ++ [Prop.expressionTypesChecked, Prop.parUsageChecked,
Prop.functionTypesChecked], [Prop.functionsRemoved])
, ("Convert AFTER to MINUS", removeAfter, [Prop.expressionTypesChecked], [Prop.afterRemoved])
, ("Expand array literals", expandArrayLiterals, [Prop.expressionTypesChecked, Prop.processTypesChecked], [Prop.arrayLiteralsExpanded])
, ("Pull up replicator counts for SEQs", pullRepCounts, Prop.agg_namesDone ++ Prop.agg_typesDone, [])
, ("Pull up definitions", pullUp False, Prop.agg_namesDone ++ Prop.agg_typesDone ++ [Prop.functionsRemoved, Prop.seqInputsFlattened], [Prop.functionCallsRemoved, Prop.subscriptsPulledUp])
, ("Transform array constructors into initialisation code", transformConstr, Prop.agg_namesDone ++ Prop.agg_typesDone
++ [Prop.subscriptsPulledUp], [Prop.arrayConstructorsRemoved])
simplifyExprs =
[ functionsToProcs
, removeAfter
, expandArrayLiterals
, pullRepCounts
, pullUp False
, transformConstr
]
-- ++ makePassesDep' ((== BackendCPPCSP) . csBackend) [("Pull up definitions (C++)", pullUp True, Prop.agg_namesDone ++ [Prop.expressionTypesChecked, Prop.functionsRemoved, Prop.processTypesChecked,Prop.seqInputsFlattened], [Prop.functionCallsRemoved, Prop.subscriptsPulledUp])]
-- | Convert FUNCTION declarations to PROCs.
functionsToProcs :: PassType
functionsToProcs = applyDepthM doSpecification
functionsToProcs :: Pass
functionsToProcs = pass "Convert FUNCTIONs to PROCs"
(Prop.agg_namesDone ++ [Prop.expressionTypesChecked, Prop.parUsageChecked,
Prop.functionTypesChecked])
[Prop.functionsRemoved]
$ applyDepthM doSpecification
where
doSpecification :: A.Specification -> PassM A.Specification
doSpecification (A.Specification m n (A.Function mf sm rts fs evp))
@ -98,8 +99,11 @@ functionsToProcs = applyDepthM doSpecification
-- | Convert AFTER expressions to the equivalent using MINUS (which is how the
-- occam 3 manual defines AFTER).
removeAfter :: PassType
removeAfter = applyDepthM doExpression
removeAfter :: Pass
removeAfter = pass "Convert AFTER to MINUS"
[Prop.expressionTypesChecked]
[Prop.afterRemoved]
$ applyDepthM doExpression
where
doExpression :: A.Expression -> PassM A.Expression
doExpression (A.Dyadic m A.After a b)
@ -114,8 +118,11 @@ removeAfter = applyDepthM doExpression
-- | For array literals that include other arrays, burst them into their
-- elements.
expandArrayLiterals :: PassType
expandArrayLiterals = applyDepthM doArrayElem
expandArrayLiterals :: Pass
expandArrayLiterals = pass "Expand array literals"
[Prop.expressionTypesChecked, Prop.processTypesChecked]
[Prop.arrayLiteralsExpanded]
$ applyDepthM doArrayElem
where
doArrayElem :: A.ArrayElem -> PassM A.ArrayElem
doArrayElem ae@(A.ArrayElemExpr e)
@ -148,8 +155,11 @@ expandArrayLiterals = applyDepthM doArrayElem
-- Therefore, we only need to pull up the counts for sequential replicators
--
-- TODO for simplification, we could avoid pulling up replication counts that are known to be constants
pullRepCounts :: PassType
pullRepCounts = applyDepthM doProcess
pullRepCounts :: Pass
pullRepCounts = pass "Pull up replicator counts for SEQs"
(Prop.agg_namesDone ++ Prop.agg_typesDone)
[]
$ applyDepthM doProcess
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.Seq m s) = pullRepCountSeq s >>* A.Seq m
@ -174,8 +184,11 @@ pullRepCounts = applyDepthM doProcess
= do s' <- pullRepCountSeq s
return $ A.Rep m rep s'
transformConstr :: PassType
transformConstr = applyDepthSM doStructured
transformConstr :: Pass
transformConstr = pass "Transform array constructors into initialisation code"
(Prop.agg_namesDone ++ Prop.agg_typesDone ++ [Prop.subscriptsPulledUp])
[Prop.arrayConstructorsRemoved]
$ applyDepthSM doStructured
where
-- For arrays, this takes a constructor expression:
-- VAL type name IS [i = rep | expr]:
@ -245,8 +258,11 @@ transformConstr = applyDepthSM doStructured
-- | Find things that need to be moved up to their enclosing Structured, and do
-- so.
pullUp :: Bool -> PassType
pullUp pullUpArraysInsideRecords = recurse
pullUp :: Bool -> Pass
pullUp pullUpArraysInsideRecords = pass "Pull up definitions"
(Prop.agg_namesDone ++ Prop.agg_typesDone ++ [Prop.functionsRemoved, Prop.seqInputsFlattened])
[Prop.functionCallsRemoved, Prop.subscriptsPulledUp]
recurse
where
ops :: Ops
ops = baseOp

View File

@ -32,15 +32,18 @@ import Traversal
import Types
simplifyProcs :: [Pass]
simplifyProcs = makePassesDep
[ ("Wrap PAR subprocesses in PROCs", parsToProcs, [Prop.parUsageChecked], [Prop.parsWrapped])
, ("Remove parallel assignment", removeParAssign, [Prop.parUsageChecked, Prop.functionsRemoved, Prop.functionCallsRemoved], [Prop.assignParRemoved])
, ("Flatten assignment", flattenAssign, Prop.agg_typesDone ++ [Prop.assignParRemoved], [Prop.assignFlattened])
simplifyProcs =
[ parsToProcs
, removeParAssign
, flattenAssign
]
-- | Wrap the subprocesses of PARs in no-arg PROCs.
parsToProcs :: PassType
parsToProcs = applyDepthM doProcess
parsToProcs :: Pass
parsToProcs = pass "Wrap PAR subprocesses in PROCs"
[Prop.parUsageChecked]
[Prop.parsWrapped]
$ applyDepthM doProcess
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.Par m pm s)
@ -58,8 +61,11 @@ parsToProcs = applyDepthM doProcess
return $ A.Spec m s (A.Only m (A.ProcCall m n []))
-- | Turn parallel assignment into multiple single assignments through temporaries.
removeParAssign :: PassType
removeParAssign = applyDepthM doProcess
removeParAssign :: Pass
removeParAssign = pass "Remove parallel assignment"
[Prop.parUsageChecked, Prop.functionsRemoved, Prop.functionCallsRemoved]
[Prop.assignParRemoved]
$ applyDepthM doProcess
where
doProcess :: A.Process -> PassM A.Process
doProcess (A.Assign m vs@(_:_:_) (A.ExpressionList _ es))
@ -72,8 +78,11 @@ removeParAssign = applyDepthM doProcess
doProcess p = return p
-- | Turn assignment of arrays and records into multiple assignments.
flattenAssign :: PassType
flattenAssign = makeRecurse ops
flattenAssign :: Pass
flattenAssign = pass "Flatten assignment"
(Prop.agg_typesDone ++ [Prop.assignParRemoved])
[Prop.assignFlattened]
$ makeRecurse ops
where
ops :: Ops
ops = extOpD (extOpSD baseOp ops doStructured) ops doProcess

View File

@ -37,9 +37,9 @@ import Traversal
import Types
unnest :: [Pass]
unnest = makePassesDep
[ ("Convert free names to arguments", removeFreeNames, [Prop.mainTagged, Prop.parsWrapped, Prop.functionCallsRemoved], [Prop.freeNamesToArgs])
, ("Pull nested definitions to top level", removeNesting, [Prop.freeNamesToArgs], [Prop.nestedPulled])
unnest =
[ removeFreeNames
, removeNesting
]
type NameMap = Map.Map String A.Name
@ -94,8 +94,11 @@ replaceNames map v = runIdentity $ applyDepthM doName v
doName n = return $ Map.findWithDefault n (A.nameName n) smap
-- | Turn free names in PROCs into arguments.
removeFreeNames :: PassType
removeFreeNames = applyDepthM2 doSpecification doProcess
removeFreeNames :: Pass
removeFreeNames = pass "Convert free names to arguments"
[Prop.mainTagged, Prop.parsWrapped, Prop.functionCallsRemoved]
[Prop.freeNamesToArgs]
$ applyDepthM2 doSpecification doProcess
where
doSpecification :: A.Specification -> PassM A.Specification
doSpecification spec = case spec of
@ -181,8 +184,11 @@ removeFreeNames = applyDepthM2 doSpecification doProcess
doProcess p = return p
-- | Pull nested declarations to the top level.
removeNesting :: Data t => Transform t
removeNesting = passOnlyOnAST "removeNesting" $ \s ->
removeNesting :: Pass
removeNesting = pass "Pull nested definitions to top level"
[Prop.freeNamesToArgs]
[Prop.nestedPulled]
$ passOnlyOnAST "removeNesting" $ \s ->
do pushPullContext
s' <- (makeRecurse ops) s >>= applyPulled
popPullContext