Defined types for tree traversals, and moved them to their own file.

We now have three kinds of canned tree traversals, all of which are smart about
which types they're applied to: explicit-descent transformations,
implicit-descent transformations, and implicit-descent checks. I've only
provided depth-first application of the latter two, but we could do
breadth-first in the future if necessary.
This commit is contained in:
Adam Sampson 2008-04-01 12:01:09 +00:00
parent 40bf42e5ea
commit 7525138c96
6 changed files with 112 additions and 50 deletions

View File

@ -116,6 +116,7 @@ tock_SOURCES_hs += frontends/StructureOccam.hs
tock_SOURCES_hs += pass/Pass.hs
tock_SOURCES_hs += pass/PassList.hs
tock_SOURCES_hs += pass/Properties.hs
tock_SOURCES_hs += pass/Traversal.hs
tock_SOURCES_hs += transformations/SimplifyComms.hs
tock_SOURCES_hs += transformations/SimplifyExprs.hs
tock_SOURCES_hs += transformations/SimplifyProcs.hs

View File

@ -31,6 +31,7 @@ import OccamTypes
import Pass
import qualified Properties as Prop
import ShowCode
import Traversal
import Types
-- | Occam-specific frontend passes.

View File

@ -32,6 +32,7 @@ import Intrinsics
import Metadata
import Pass
import ShowCode
import Traversal
import Types
-- | A successful check.
@ -162,11 +163,11 @@ checkExpressionType :: A.Type -> A.Expression -> PassM ()
checkExpressionType et e = typeOfExpression e >>= checkType (findMeta e) et
-- | Check that an expression is of integer type.
checkExpressionInt :: A.Expression -> PassM ()
checkExpressionInt :: Check A.Expression
checkExpressionInt e = checkExpressionType A.Int e
-- | Check that an expression is of boolean type.
checkExpressionBool :: A.Expression -> PassM ()
checkExpressionBool :: Check A.Expression
checkExpressionBool e = checkExpressionType A.Bool e
--}}}
@ -293,6 +294,7 @@ checkAbbrev m orig new
(A.ValAbbrev, _) -> bad
_ -> ok
where
bad :: PassM ()
bad = dieP m $ "You can't abbreviate " ++ showAM orig ++ " as " ++ showAM new
showAM :: A.AbbrevMode -> String
@ -360,7 +362,7 @@ checkAllocMobile m rawT me
_ -> diePC m $ formatCode "Expected mobile type in allocation; found %" t
-- | Check that a variable is writable.
checkWritable :: A.Variable -> PassM ()
checkWritable :: Check A.Variable
checkWritable v
= do am <- abbrevModeOfVariable v
case am of
@ -478,7 +480,7 @@ checkNamesDistinct m ns
dupes = nub (ns \\ nub ns)
-- | Check a 'Replicator'.
checkReplicator :: A.Replicator -> PassM ()
checkReplicator :: Check A.Replicator
checkReplicator (A.For _ _ start count)
= do checkExpressionInt start
checkExpressionInt count
@ -489,7 +491,7 @@ checkReplicator (A.ForEach _ _ e)
-- | Check a 'Structured', applying the given check to each item found inside
-- it. This assumes that processes and specifications will be checked
-- elsewhere.
checkStructured :: Data t => (t -> PassM ()) -> A.Structured t -> PassM ()
checkStructured :: Data t => Check t -> Check (A.Structured t)
checkStructured doInner (A.Rep _ rep s)
= checkReplicator rep >> checkStructured doInner s
checkStructured doInner (A.Spec _ spec s)
@ -552,7 +554,7 @@ checkTypes t =
checkVariables :: Data t => t -> PassM t
checkVariables = checkDepthM doVariable
where
doVariable :: A.Variable -> PassM ()
doVariable :: Check A.Variable
doVariable (A.SubscriptedVariable m s v)
= do t <- typeOfVariable v
checkSubscript m s t
@ -574,7 +576,7 @@ checkVariables = checkDepthM doVariable
checkExpressions :: Data t => t -> PassM t
checkExpressions = checkDepthM doExpression
where
doExpression :: A.Expression -> PassM ()
doExpression :: Check A.Expression
doExpression (A.Monadic _ op e) = checkMonadicOp op e
doExpression (A.Dyadic _ op le re) = checkDyadicOp op le re
doExpression (A.MostPos m t) = checkNumeric m t
@ -629,7 +631,7 @@ checkExpressions = checkDepthM doExpression
checkSpecTypes :: Data t => t -> PassM t
checkSpecTypes = checkDepthM doSpecType
where
doSpecType :: A.SpecType -> PassM ()
doSpecType :: Check A.SpecType
doSpecType (A.Place _ e) = checkExpressionInt e
doSpecType (A.Declaration _ _) = ok
doSpecType (A.Is m am t v)
@ -700,7 +702,7 @@ checkSpecTypes = checkDepthM doSpecType
= do fromT <- typeOfExpression e
checkRetypes m fromT t
unexpectedAM :: Meta -> PassM ()
unexpectedAM :: Check Meta
unexpectedAM m = dieP m "Unexpected abbreviation mode"
--}}}
@ -709,7 +711,7 @@ checkSpecTypes = checkDepthM doSpecType
checkProcesses :: Data t => t -> PassM t
checkProcesses = checkDepthM doProcess
where
doProcess :: A.Process -> PassM ()
doProcess :: Check A.Process
doProcess (A.Assign m vs el)
= do vts <- mapM (typeOfVariable) vs
mapM_ checkWritable vs
@ -748,7 +750,7 @@ checkProcesses = checkDepthM doProcess
checkActuals m (A.Name m A.ProcName n) fs as
Nothing -> dieP m $ n ++ " is not an intrinsic procedure"
doAlternative :: A.Alternative -> PassM ()
doAlternative :: Check A.Alternative
doAlternative (A.Alternative m v im _)
= case im of
A.InputTimerRead _ _ ->
@ -760,7 +762,7 @@ checkProcesses = checkDepthM doProcess
doAlternative (A.AlternativeSkip _ e _)
= checkExpressionBool e
doChoice :: A.Choice -> PassM ()
doChoice :: Check A.Choice
doChoice (A.Choice _ e _) = checkExpressionBool e
doInput :: A.Variable -> A.InputMode -> PassM ()

View File

@ -28,6 +28,7 @@ import EvalConstants
import Metadata
import Pass
import ShowCode
import Traversal
import Types

View File

@ -28,7 +28,6 @@ import System.IO
import qualified AST as A
import CompState
import Errors
import GenericUtils
import Metadata
import PrettyShow
import TreeUtils
@ -150,7 +149,6 @@ runPasses (p:ps) ast
debug $ "}}}"
runPasses ps ast'
-- | Print a message if above the given verbosity level.
verboseMessage :: (CSM m, MonadIO m) => Int -> String -> m ()
verboseMessage n s
@ -195,42 +193,6 @@ makeGeneric top
`extM` (return :: String -> m String)
`extM` (return :: Meta -> m Meta)
-- | Apply a monadic operation everywhere that it matches, going depth-first.
applyDepthM :: forall a t. (Data a, Data t) => (a -> PassM a) -> t -> PassM t
applyDepthM f = doGeneric `extM` (doSpecific f)
where
doGeneric :: Data t1 => t1 -> PassM t1
doGeneric = gmapMFor (undefined :: a) (applyDepthM f)
doSpecific :: Data t2 => (t2 -> PassM t2) -> t2 -> PassM t2
doSpecific f x = (doGeneric x >>= f)
-- | Apply two monadic operations everywhere they match in the AST, going
-- depth-first.
applyDepthM2 :: forall a b t. (Data a, Data b, Data t) =>
(a -> PassM a) -> (b -> PassM b) -> t -> PassM t
applyDepthM2 f1 f2 = doGeneric `extM` (doSpecific f1) `extM` (doSpecific f2)
where
doGeneric :: Data t1 => t1 -> PassM t1
doGeneric = gmapMFor2 (undefined :: a) (undefined :: b) (applyDepthM2 f1 f2)
doSpecific :: Data t2 => (t2 -> PassM t2) -> t2 -> PassM t2
doSpecific f x = (doGeneric x >>= f)
-- | Apply a check (a monadic operation that returns nothing, but can succeed
-- or fail) everywhere it matches in the AST, going depth-first.
checkDepthM :: forall a t. (Data a, Data t) => (a -> PassM ()) -> t -> PassM t
checkDepthM f = doGeneric `extM` (doSpecific f)
where
doGeneric :: Data t1 => t1 -> PassM t1
doGeneric = gmapMFor (undefined :: a) (checkDepthM f)
doSpecific :: Data t2 => (t2 -> PassM ()) -> t2 -> PassM t2
doSpecific f x
= do x' <- doGeneric x
f x'
return x'
excludeConstr :: (Data a, CSMR m) => [Constr] -> a -> m a
excludeConstr cons x
= if null items then return x else dieInternal (Nothing, "Excluded item still remains in source tree: " ++ (show $ head items) ++ " tree is: " ++ pshow x)

95
pass/Traversal.hs Normal file
View File

@ -0,0 +1,95 @@
{-
Tock: a compiler for parallel languages
Copyright (C) 2008 University of Kent
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
-}
-- | Traversal strategies over the AST and other data types.
module Traversal (
ExplicitTrans, Transform, Check
, transformToExplicitDepth, checkToTransform
, applyExplicitM, applyExplicitM2
, applyDepthM, applyDepthM2
, checkDepthM
) where
import Data.Generics
import GenericUtils
import Pass
-- | A transformation for a single 'Data' type with explicit descent.
-- The first argument passed is a function that can be called to explicitly
-- descend into a generic value.
type ExplicitTrans t = Data t =>
(forall s. Data s => s -> PassM s) -> t -> PassM t
-- | A transformation for a single 'Data' type with implicit descent.
-- This can be applied recursively throughout a data structure.
type Transform t = Data t => t -> PassM t
-- | A check for a single 'Data' type with implicit descent.
-- This is like 'Transform', but it doesn't change the value; it may fail or
-- modify the state, though.
type Check t = Data t => t -> PassM ()
-- | Make an 'ExplicitTrans' that applies a 'Transform', recursing depth-first.
transformToExplicitDepth :: Data t => Transform t -> ExplicitTrans t
transformToExplicitDepth f descend x = descend x >>= f
-- | Make a 'Transform' that applies a 'Check'.
checkToTransform :: Data t => Check t -> Transform t
checkToTransform f x = f x >> return x
-- | Apply an explicit transformation.
applyExplicitM :: forall t1 s. (Data t1, Data s) =>
ExplicitTrans t1 -> s -> PassM s
applyExplicitM f1 = doGeneric `extM` (doSpecific f1)
where
doGeneric :: Data t => t -> PassM t
doGeneric = gmapMFor (undefined :: t1) (applyExplicitM f1)
doSpecific :: Data t => ExplicitTrans t -> t -> PassM t
doSpecific f x = f doGeneric x
-- | Apply two explicit transformations.
applyExplicitM2 :: forall t1 t2 s. (Data t1, Data t2, Data s) =>
ExplicitTrans t1 -> ExplicitTrans t2 -> s -> PassM s
applyExplicitM2 f1 f2 = doGeneric `extM` (doSpecific f1)
`extM` (doSpecific f2)
where
doGeneric :: Data t => t -> PassM t
doGeneric = gmapMFor2 (undefined :: t1) (undefined :: t2)
(applyExplicitM2 f1 f2)
doSpecific :: Data t => ExplicitTrans t -> t -> PassM t
doSpecific f x = f doGeneric x
-- | Apply a transformation, recursing depth-first.
applyDepthM :: forall t1 s. (Data t1, Data s) =>
Transform t1 -> s -> PassM s
applyDepthM f = applyExplicitM (transformToExplicitDepth f)
-- | Apply two transformations, recursing depth-first.
applyDepthM2 :: forall t1 t2 s. (Data t1, Data t2, Data s) =>
Transform t1 -> Transform t2 -> s -> PassM s
applyDepthM2 f1 f2 = applyExplicitM2 (transformToExplicitDepth f1)
(transformToExplicitDepth f2)
-- | Apply a check, recursing depth-first.
checkDepthM :: forall t1 s. (Data t1, Data s) =>
Check t1 -> s -> PassM s
checkDepthM f = applyDepthM (checkToTransform f)