Made the doTree and similar functions more polymorphic, and added forAnyASTStruct

This commit is contained in:
Neil Brown 2008-11-13 20:10:43 +00:00
parent 048bd26be3
commit 16a2be40b4

View File

@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>. with this program. If not, see <http://www.gnu.org/licenses/>.
-} -}
module CheckFramework (CheckOptM, CheckOptM', forAnyAST, substitute, restartForAnyAST, module CheckFramework (CheckOptM, CheckOptM', forAnyAST, forAnyASTStruct, substitute, restartForAnyAST,
runChecks, runChecksPass, getFlowGraph, withChild, varsTouchedAfter, runChecks, runChecksPass, getFlowGraph, withChild, varsTouchedAfter,
getCachedAnalysis, getCachedAnalysis') where getCachedAnalysis, getCachedAnalysis') where
@ -30,6 +30,7 @@ import qualified Data.Map as Map
import Data.Maybe import Data.Maybe
import qualified Data.Set as Set import qualified Data.Set as Set
import Control.Exception import Control.Exception
import GHC.Base (unsafeCoerce#)
import qualified AST as A import qualified AST as A
import CompState import CompState
@ -131,7 +132,7 @@ deCheckOptM' (CheckOptM' x) = x
-- | The idea is this: in normal operation you use the Right return value. When -- | The idea is this: in normal operation you use the Right return value. When
-- you want to restart the forAnyAST operation from a given point, you use the -- you want to restart the forAnyAST operation from a given point, you use the
-- Left constructor, supplying the route to use on the new tree (which you must -- Left constructor, supplying the route to use on the new tree (which you must
-- have put in the CheckOptM state) and the continuation to apply. If you wish -- have put in the CheckOptM state). If you wish
-- to start again from the top, supply routeIdentity, and your original function. -- to start again from the top, supply routeIdentity, and your original function.
data Monad m => RestartT m a data Monad m => RestartT m a
= RestartT { getRestartT :: m (Either (Maybe [Int]) a) } = RestartT { getRestartT :: m (Either (Maybe [Int]) a) }
@ -177,19 +178,68 @@ liftCheckOptM = CheckOptM' . lift . lift
forAnyParItems :: (ParItems a -> CheckOptM ()) -> CheckOptM () forAnyParItems :: (ParItems a -> CheckOptM ()) -> CheckOptM ()
forAnyParItems = undefined forAnyParItems = undefined
-- Like mkM, but with no return value, and this funny monad with routes, but also
-- we give an error if the plain function is ever triggered (given the typeset
-- stuff, it shouldn't be)
mkM_ :: forall a. Data a => (a -> CheckOptM' a ()) -> (forall b. Data b => b -> CheckOptM'
b ())
mkM_ f = plain `extM_` f
where
plain :: (forall c. Data c => c -> CheckOptM' c ())
plain _ = dieP emptyMeta "Unexpected call of mkM_.plain"
-- Like extM, but with no return value, and this funny monad with routes:
extM_ :: forall b. Data b => (forall a. Data a => a -> CheckOptM' a ()) -> (b -> CheckOptM' b ())
-> (forall c. Data c => c -> CheckOptM' c ())
extM_ generalF specificF x = case cast x of
Nothing -> generalF x
Just y -> let CheckOptM' z = specificF y in CheckOptM' $ ask >>= (lift . runReaderT z . unsafeCoerce#)
-- | This function currently only supports one type -- | This function currently only supports one type
forAnyAST :: forall a. Data a => (a -> CheckOptM' a ()) -> CheckOptM () forAnyAST :: forall a. Data a => (a -> CheckOptM' a ()) -> CheckOptM ()
forAnyAST origF = CheckOptM $ do forAnyAST origF = CheckOptM $ do
tr <- get >>* ast tr <- get >>* ast
doTree typeSet origF [] tr doTree typeSet (mkM_ origF) [] tr
where where
typeSet :: TypeSet typeSet :: TypeSet
typeSet = makeTypeSet [typeKey (undefined :: a)] typeSet = makeTypeSet [typeKey (undefined :: a)]
forAnyASTStruct :: (forall a. Data a => A.Structured a -> CheckOptM' (A.Structured
a) ()) -> CheckOptM ()
forAnyASTStruct origF = CheckOptM $ do
tr <- get >>* ast
doTree typeSet allF [] tr
where
allF :: (forall c. Data c => c -> CheckOptM' c ())
allF
= mkM_ (origF :: A.Structured A.Variant -> CheckOptM' (A.Structured A.Variant) ())
`extM_` (origF :: A.Structured A.Process -> CheckOptM' (A.Structured A.Process) ())
`extM_` (origF :: A.Structured A.Option -> CheckOptM' (A.Structured A.Option) ())
`extM_` (origF :: A.Structured A.ExpressionList -> CheckOptM' (A.Structured A.ExpressionList) ())
`extM_` (origF :: A.Structured A.Choice -> CheckOptM' (A.Structured A.Choice) ())
`extM_` (origF :: A.Structured A.Alternative -> CheckOptM' (A.Structured A.Alternative) ())
`extM_` (origF :: A.Structured () -> CheckOptM' (A.Structured ()) ())
typeSet :: TypeSet
typeSet = makeTypeSet
[typeKey (undefined :: A.Structured A.Variant)
,typeKey (undefined :: A.Structured A.Process)
,typeKey (undefined :: A.Structured A.Option)
,typeKey (undefined :: A.Structured A.ExpressionList)
,typeKey (undefined :: A.Structured A.Choice)
,typeKey (undefined :: A.Structured A.Alternative)
,typeKey (undefined :: A.Structured ())
]
-- | Given a TypeSet, a function to apply to everything of type a, a route -- | Given a TypeSet, a function to apply to everything of type a, a route
-- location to begin at and an AST, transforms the tree. Handles any restarts -- location to begin at and an AST, transforms the tree. Handles any restarts
-- that are requested. -- that are requested.
doTree :: forall a. Data a => TypeSet -> (a -> CheckOptM' a ()) -> doTree :: TypeSet -> (forall a. Data a => a -> CheckOptM' a ()) ->
[Int] -> A.AST -> StateT CheckOptData PassM () [Int] -> A.AST -> StateT CheckOptData PassM ()
doTree typeSet f route tr doTree typeSet f route tr
= do x <- traverse typeSet f (Just route) tr = do x <- traverse typeSet f (Just route) tr
@ -203,14 +253,14 @@ doTree typeSet f route tr
-- location to begin at and an AST, transforms the tree. If any restarts are -- location to begin at and an AST, transforms the tree. If any restarts are
-- requested, that is indicated in the return value. If an AST is returned, -- requested, that is indicated in the return value. If an AST is returned,
-- it is ignored (all changes are done in the state) -- it is ignored (all changes are done in the state)
traverse :: forall a. Data a => TypeSet -> (a -> CheckOptM' a ()) -> Maybe [Int] -> A.AST -> traverse :: TypeSet -> (forall a. Data a => a -> CheckOptM' a ()) -> Maybe [Int] -> A.AST ->
StateT CheckOptData PassM (Either (Maybe [Int]) ()) StateT CheckOptData PassM (Either (Maybe [Int]) ())
traverse typeSet f route tr traverse typeSet f route tr
= deCheckOptM . getRestartT $ = deCheckOptM . getRestartT $
(flip evalStateT (case route of (flip evalStateT (case route of
Just r -> Just r Just r -> Just r
Nothing -> Just [] -- No route, means start from the beginning Nothing -> Just [] -- No route, means start from the beginning
) $ gen tr) ) (gen tr))
where where
-- We can't use routeModify with the route to jump to the right place, -- We can't use routeModify with the route to jump to the right place,
-- because then applying gen gets much more difficult, and I can't find -- because then applying gen gets much more difficult, and I can't find
@ -223,9 +273,10 @@ traverse typeSet f route tr
-- below) if we are past the point we are meant to start at, or otherwise -- below) if we are past the point we are meant to start at, or otherwise
-- just skips this node -- just skips this node
gen :: A.AST -> StateT (Maybe [Int]) (RestartT CheckOptM) () gen :: A.AST -> StateT (Maybe [Int]) (RestartT CheckOptM) ()
gen x = gmapMForRoute typeSet (baseTransformRoute `extTransformRoute` f') x >> return () gen x = gmapMForRoute typeSet f' x >> return ()
f' :: (a, Route a A.AST) -> StateT (Maybe [Int]) (RestartT CheckOptM) a f' :: forall a. Data a => (a, Route a A.AST) -> StateT (Maybe [Int]) (RestartT
CheckOptM) a
f' (y, route) = f' (y, route) =
do st <- get do st <- get
case st of case st of