diff --git a/backends/BackendPasses.hs b/backends/BackendPasses.hs index b3c6567..6351251 100644 --- a/backends/BackendPasses.hs +++ b/backends/BackendPasses.hs @@ -17,7 +17,7 @@ with this program. If not, see . -} -- | 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) diff --git a/backends/BackendPassesTest.hs b/backends/BackendPassesTest.hs index 4b7f47e..1e56b41 100644 --- a/backends/BackendPassesTest.hs +++ b/backends/BackendPassesTest.hs @@ -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 diff --git a/backends/GenerateC.hs b/backends/GenerateC.hs index 6ad8c00..7128f54 100644 --- a/backends/GenerateC.hs +++ b/backends/GenerateC.hs @@ -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] diff --git a/backends/GenerateCPPCSP.hs b/backends/GenerateCPPCSP.hs index 8652923..c819194 100644 --- a/backends/GenerateCPPCSP.hs +++ b/backends/GenerateCPPCSP.hs @@ -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 diff --git a/checks/ArrayUsageCheckTest.hs b/checks/ArrayUsageCheckTest.hs index 1155745..8526b0f 100644 --- a/checks/ArrayUsageCheckTest.hs +++ b/checks/ArrayUsageCheckTest.hs @@ -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 diff --git a/checks/UsageCheckTest.hs b/checks/UsageCheckTest.hs index 6e70096..a71a0e0 100644 --- a/checks/UsageCheckTest.hs +++ b/checks/UsageCheckTest.hs @@ -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 diff --git a/common/TestUtils.hs b/common/TestUtils.hs index 8d0d972..18332d6 100644 --- a/common/TestUtils.hs +++ b/common/TestUtils.hs @@ -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 diff --git a/frontends/OccamPasses.hs b/frontends/OccamPasses.hs index 5f1b40e..d2caa67 100644 --- a/frontends/OccamPasses.hs +++ b/frontends/OccamPasses.hs @@ -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 diff --git a/frontends/OccamPassesTest.hs b/frontends/OccamPassesTest.hs index a718872..9fe694d 100644 --- a/frontends/OccamPassesTest.hs +++ b/frontends/OccamPassesTest.hs @@ -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 diff --git a/frontends/OccamTypes.hs b/frontends/OccamTypes.hs index 380734a..54d4e35 100644 --- a/frontends/OccamTypes.hs +++ b/frontends/OccamTypes.hs @@ -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 diff --git a/frontends/OccamTypesTest.hs b/frontends/OccamTypesTest.hs index 2083fd9..b020430 100644 --- a/frontends/OccamTypesTest.hs +++ b/frontends/OccamTypesTest.hs @@ -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 diff --git a/frontends/PreprocessOccamTest.hs b/frontends/PreprocessOccamTest.hs index c66dd82..c80bab8 100644 --- a/frontends/PreprocessOccamTest.hs +++ b/frontends/PreprocessOccamTest.hs @@ -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) diff --git a/frontends/RainPasses.hs b/frontends/RainPasses.hs index 1aff273..3f5fa25 100644 --- a/frontends/RainPasses.hs +++ b/frontends/RainPasses.hs @@ -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 diff --git a/frontends/RainPassesTest.hs b/frontends/RainPassesTest.hs index d21d62e..3542157 100644 --- a/frontends/RainPassesTest.hs +++ b/frontends/RainPassesTest.hs @@ -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 diff --git a/frontends/RainTypesTest.hs b/frontends/RainTypesTest.hs index ac18045..3fd166b 100644 --- a/frontends/RainTypesTest.hs +++ b/frontends/RainTypesTest.hs @@ -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 diff --git a/frontends/StructureOccamTest.hs b/frontends/StructureOccamTest.hs index 6a6402d..77e0a57 100644 --- a/frontends/StructureOccamTest.hs +++ b/frontends/StructureOccamTest.hs @@ -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 diff --git a/pass/Pass.hs b/pass/Pass.hs index b1e96b0..3f5d6db 100644 --- a/pass/Pass.hs +++ b/pass/Pass.hs @@ -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 diff --git a/pass/PassList.hs b/pass/PassList.hs index 1b03c9e..196bf19 100644 --- a/pass/PassList.hs +++ b/pass/PassList.hs @@ -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 diff --git a/transformations/PassTest.hs b/transformations/PassTest.hs index c6f0363..578394c 100644 --- a/transformations/PassTest.hs +++ b/transformations/PassTest.hs @@ -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 []) diff --git a/transformations/SimplifyComms.hs b/transformations/SimplifyComms.hs index 24afd17..84a3586 100644 --- a/transformations/SimplifyComms.hs +++ b/transformations/SimplifyComms.hs @@ -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@(_:_:_))) diff --git a/transformations/SimplifyExprs.hs b/transformations/SimplifyExprs.hs index 47d3bb9..bb5feb0 100644 --- a/transformations/SimplifyExprs.hs +++ b/transformations/SimplifyExprs.hs @@ -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 diff --git a/transformations/SimplifyProcs.hs b/transformations/SimplifyProcs.hs index 81b0610..36d7130 100644 --- a/transformations/SimplifyProcs.hs +++ b/transformations/SimplifyProcs.hs @@ -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 diff --git a/transformations/Unnest.hs b/transformations/Unnest.hs index 68854e7..e59113c 100644 --- a/transformations/Unnest.hs +++ b/transformations/Unnest.hs @@ -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