diff --git a/Makefile.am b/Makefile.am index d282dcc..39bbfb7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -106,7 +106,7 @@ modulesdir=$(TOCKMODDIR) tockincdir=$(TOCKINCDIR) tocklibdir=$(TOCKLIBDIR) -config/Paths.hs: config/Paths.hs.in +config/Paths.hs: config/Paths.hs.in Makefile @sed -e 's,@@pkgincludedir@@,$(pkgincludedir),g' config/Paths.hs.in \ | sed -e 's,@@tockdir@@,$(TOCKDIR),g' \ | sed -e 's,@@tockmoddir@@,$(TOCKMODDIR),g' \ @@ -114,10 +114,7 @@ config/Paths.hs: config/Paths.hs.in | sed -e 's,@@tocklibdir@@,$(TOCKLIBDIR),g' >config/Paths.hs data/NavAST.hs: GenNavAST$(EXEEXT) - ./GenNavAST$(EXEEXT) data/NavAST.hs data/NavASTSpine.hs - -data/NavASTSpine.hs: GenNavAST$(EXEEXT) - ./GenNavAST$(EXEEXT) data/NavAST.hs data/NavASTSpine.hs + ./GenNavAST$(EXEEXT) data/NavAST.hs data/OrdAST.hs: GenOrdAST$(EXEEXT) ./GenOrdAST$(EXEEXT) > data/OrdAST.hs @@ -130,7 +127,6 @@ config_sources += config/Paths.hs config_sources += config/TypeSizes.hs BUILT_SOURCES = data/NavAST.hs -BUILT_SOURCES += data/NavASTSpine.hs BUILT_SOURCES += data/OrdAST.hs BUILT_SOURCES += data/TagAST.hs BUILT_SOURCES += frontends/LexOccam.hs @@ -233,7 +229,7 @@ tocktest_SOURCES += transformations/PassTest.hs tocktest_SOURCES += transformations/SimplifyAbbrevsTest.hs tocktest_SOURCES += transformations/SimplifyTypesTest.hs -pregen_sources = data/AST.hs data/CompState.hs +pregen_sources = data/AST.hs data/CompState.hs config/Paths.hs pregen_sources += pregen/PregenUtils.hs pregen_sources += polyplate/Data/Generics/Polyplate/GenInstances.hs diff --git a/backends/GenerateC.hs b/backends/GenerateC.hs index 0465f7c..905ad29 100644 --- a/backends/GenerateC.hs +++ b/backends/GenerateC.hs @@ -182,11 +182,11 @@ cgenTopLevel headerName s = A.nameName n `elem` (csOriginalTopLevelProcs cs) tellToHeader $ sequence_ $ map (call genForwardDeclaration) - (listifyDepth isTopLevelSpec s) + (listifyTopDown isTopLevelSpec s) -- Things like lifted wrapper_procs we still need to forward-declare, -- but we do it in the C file, not in the header: sequence_ $ map (call genForwardDeclaration) - (listifyDepth (not . isTopLevelSpec) s) + (listifyTopDown (not . isTopLevelSpec) s) tell ["#include \"", dropPath headerName, "\"\n"] diff --git a/backends/GenerateCPPCSP.hs b/backends/GenerateCPPCSP.hs index 2917af0..d7038d0 100644 --- a/backends/GenerateCPPCSP.hs +++ b/backends/GenerateCPPCSP.hs @@ -144,11 +144,11 @@ cppgenTopLevel headerName s = A.nameName n `elem` (csOriginalTopLevelProcs cs) tellToHeader $ sequence_ $ map (call genForwardDeclaration) - (listifyDepth isTopLevelSpec s) + (listifyTopDown isTopLevelSpec s) -- Things like lifted wrapper_procs we still need to forward-declare, -- but we do it in the C file, not in the header: sequence_ $ map (call genForwardDeclaration) - (listifyDepth (\sp@(A.Specification _ n _) + (listifyTopDown (\sp@(A.Specification _ n _) -> not (isTopLevelSpec sp) && A.nameName n `notElem` map fst (csExternals cs)) s) diff --git a/checks/Check.hs b/checks/Check.hs index 19b4666..df9bad4 100644 --- a/checks/Check.hs +++ b/checks/Check.hs @@ -107,12 +107,12 @@ followBK = map followBK' next = Set.fromList $ map Var $ concatMap allVarsInBK bk allVarsInBK :: BackgroundKnowledge -> [A.Variable] -allVarsInBK (Equal a b) = listifyDepth (const True) a - ++ listifyDepth (const True) b -allVarsInBK (LessThanOrEqual a b) = listifyDepth (const True) a - ++ listifyDepth (const True) b -allVarsInBK (RepBoundsIncl v a b) = v : (listifyDepth (const True) a - ++ listifyDepth (const True) b) +allVarsInBK (Equal a b) = listifyTopDown (const True) a + ++ listifyTopDown (const True) b +allVarsInBK (LessThanOrEqual a b) = listifyTopDown (const True) a + ++ listifyTopDown (const True) b +allVarsInBK (RepBoundsIncl v a b) = v : (listifyTopDown (const True) a + ++ listifyTopDown (const True) b) data And a = And [a] data Or a = Or [a] diff --git a/checks/UsageCheckAlgorithms.hs b/checks/UsageCheckAlgorithms.hs index 67f1219..cb0ee46 100644 --- a/checks/UsageCheckAlgorithms.hs +++ b/checks/UsageCheckAlgorithms.hs @@ -204,7 +204,7 @@ findConstraints graph startNode processNode (n, e) nodeVal curAgg = case fmap getNodeData $ lab graph n of Just u -> let overlapsWithWritten e = not $ null $ intersect - (listifyDepth (const True) $ snd e) + (listifyTopDown (const True) $ snd e) [v | Var v <- Map.keys $ writtenVars $ nodeVars u] valFilt = filter (not . overlapsWithWritten) $ nub $ nodeVal ++ (case e of diff --git a/frontends/OccamTypes.hs b/frontends/OccamTypes.hs index 941fd74..578211c 100644 --- a/frontends/OccamTypes.hs +++ b/frontends/OccamTypes.hs @@ -1307,10 +1307,14 @@ inferTypes = occamOnlyPass "Infer types" -- 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 :: - (PolyplateSpine t (OneOpQ (PassM ()) A.Variable) () (PassM ()) - ,PolyplateSpine t (OneOpQ (PassM ()) A.Expression) () (PassM ()) - ,PolyplateSpine t (OneOpQ (PassM ()) A.SpecType) () (PassM ()) - ,PolyplateSpine t (OneOpQ (PassM ()) A.Process) () (PassM ()) + (PolyplateM t (OneOpM PassM A.Variable) () PassM + ,PolyplateM t (OneOpM PassM A.Expression) () PassM + ,PolyplateM t (OneOpM PassM A.SpecType) () PassM + ,PolyplateM t (OneOpM PassM A.Process) () PassM + ,PolyplateM t () (OneOpM PassM A.Variable) PassM + ,PolyplateM t () (OneOpM PassM A.Expression) PassM + ,PolyplateM t () (OneOpM PassM A.SpecType) PassM + ,PolyplateM t () (OneOpM PassM A.Process) PassM ) => Pass t checkTypes = occamOnlyPass "Check types" [Prop.inferredTypesRecorded, Prop.ambiguitiesResolved] @@ -1326,8 +1330,8 @@ checkTypes = occamOnlyPass "Check types" --{{{ checkVariables -checkVariables :: PlainCheckOn A.Variable -checkVariables = checkDepthM doVariable +checkVariables :: PassTypeOn A.Variable +checkVariables x = checkDepthM doVariable x >> return x where doVariable :: Check A.Variable doVariable (A.SubscriptedVariable m s v) @@ -1357,8 +1361,8 @@ checkVariables = checkDepthM doVariable --}}} --{{{ checkExpressions -checkExpressions :: PlainCheckOn A.Expression -checkExpressions = checkDepthM doExpression +checkExpressions :: PassTypeOn A.Expression +checkExpressions x = checkDepthM doExpression x >> return x where doExpression :: Check A.Expression doExpression (A.MostPos m t) = checkNumeric m t @@ -1409,8 +1413,8 @@ checkExpressions = checkDepthM doExpression --}}} --{{{ checkSpecTypes -checkSpecTypes :: PlainCheckOn A.SpecType -checkSpecTypes = checkDepthM doSpecType +checkSpecTypes :: PassTypeOn A.SpecType +checkSpecTypes x = checkDepthM doSpecType x >> return x where doSpecType :: Check A.SpecType doSpecType (A.Place _ e) = checkExpressionInt e @@ -1532,8 +1536,8 @@ checkSpecTypes = checkDepthM doSpecType --}}} --{{{ checkProcesses -checkProcesses :: PlainCheckOn A.Process -checkProcesses = checkDepthM doProcess +checkProcesses :: PassTypeOn A.Process +checkProcesses x = checkDepthM doProcess x >> return x where doProcess :: Check A.Process doProcess (A.Assign m vs el) diff --git a/frontends/OccamTypesTest.hs b/frontends/OccamTypesTest.hs index 0a950af..fc46888 100644 --- a/frontends/OccamTypesTest.hs +++ b/frontends/OccamTypesTest.hs @@ -502,20 +502,28 @@ testOccamTypes = TestList --}}} ] where - testOK :: (PolyplateSpine a (OneOpQ (PassM ()) A.Variable) () (PassM ()) - ,PolyplateSpine a (OneOpQ (PassM ()) A.Expression) () (PassM ()) - ,PolyplateSpine a (OneOpQ (PassM ()) A.SpecType) () (PassM ()) - ,PolyplateSpine a (OneOpQ (PassM ()) A.Process) () (PassM ()) + testOK :: (PolyplateM a (OneOpM PassM A.Variable) () PassM + ,PolyplateM a (OneOpM PassM A.Expression) () PassM + ,PolyplateM a (OneOpM PassM A.SpecType) () PassM + ,PolyplateM a (OneOpM PassM A.Process) () PassM + ,PolyplateM a () (OneOpM PassM A.Variable) PassM + ,PolyplateM a () (OneOpM PassM A.Expression) PassM + ,PolyplateM a () (OneOpM PassM A.SpecType) PassM + ,PolyplateM a () (OneOpM PassM A.Process) PassM ,Show a, Data a) => Int -> a -> Test testOK n orig = TestCase $ testPass ("testOccamTypes " ++ show n) orig OccamTypes.checkTypes orig startState - testFail :: (PolyplateSpine a (OneOpQ (PassM ()) A.Variable) () (PassM ()) - ,PolyplateSpine a (OneOpQ (PassM ()) A.Expression) () (PassM ()) - ,PolyplateSpine a (OneOpQ (PassM ()) A.SpecType) () (PassM ()) - ,PolyplateSpine a (OneOpQ (PassM ()) A.Process) () (PassM ()) + testFail :: (PolyplateM a (OneOpM PassM A.Variable) () PassM + ,PolyplateM a (OneOpM PassM A.Expression) () PassM + ,PolyplateM a (OneOpM PassM A.SpecType) () PassM + ,PolyplateM a (OneOpM PassM A.Process) () PassM + ,PolyplateM a () (OneOpM PassM A.Variable) PassM + ,PolyplateM a () (OneOpM PassM A.Expression) PassM + ,PolyplateM a () (OneOpM PassM A.SpecType) PassM + ,PolyplateM a () (OneOpM PassM A.Process) PassM ,Show a, Data a) => Int -> a -> Test testFail n orig = TestCase $ testPassShouldFail ("testOccamTypes " ++ show n) diff --git a/frontends/RainTypes.hs b/frontends/RainTypes.hs index 11d62f7..61dbb98 100644 --- a/frontends/RainTypes.hs +++ b/frontends/RainTypes.hs @@ -61,11 +61,11 @@ type RainTypeM = StateT RainTypeState PassM type RainTypePassType = forall t. t -> StateT RainTypeState PassM t -type RainTypeCheckOn a = forall t. PolyplateSpine t (OneOpQ (RainTypeM ()) a) () - (RainTypeM ()) => t -> RainTypeM () +type RainTypeCheckOn a = forall t. PolyplateM t (OneOpM RainTypeM a) () RainTypeM + => t -> RainTypeM () type RainTypeCheckOn2 a b = forall t. - (PolyplateSpine t (TwoOpQ (RainTypeM ()) a b) () (RainTypeM ()) + (PolyplateM t (TwoOpM RainTypeM a b) () RainTypeM ) => t -> RainTypeM () @@ -128,12 +128,12 @@ markUnify x y performTypeUnification :: -- | A shorthand for prerequisites when you need to spell them out: - (PolyplateSpine t (OneOpQ (RainTypeM ()) A.Specification) () (RainTypeM ()) - ,PolyplateSpine t (OneOpQ (RainTypeM ()) A.Process) () (RainTypeM ()) - ,PolyplateSpine t (OneOpQ (RainTypeM ()) A.Expression) () (RainTypeM ()) - ,PolyplateSpine t (TwoOpQ (RainTypeM ()) A.Process A.Expression) () (RainTypeM ()) - ,PolyplateSpine t (TwoOpQ (RainTypeM ()) A.Process A.Choice) () (RainTypeM ()) - ,PolyplateSpine t (TwoOpQ (RainTypeM ()) A.Process A.Alternative) () (RainTypeM ()) + (PolyplateM t (OneOpM RainTypeM A.Specification) () RainTypeM + ,PolyplateM t (OneOpM RainTypeM A.Process) () RainTypeM + ,PolyplateM t (OneOpM RainTypeM A.Expression) () RainTypeM + ,PolyplateM t (TwoOpM RainTypeM A.Process A.Expression) () RainTypeM + ,PolyplateM t (TwoOpM RainTypeM A.Process A.Choice) () RainTypeM + ,PolyplateM t (TwoOpM RainTypeM A.Process A.Alternative) () RainTypeM ,PolyplateM t () (OneOpM PassM A.Type) PassM ,PolyplateM t (OneOpM PassM A.Type) () PassM ) => Pass t diff --git a/pass/Pass.hs b/pass/Pass.hs index dc6a621..0be4ac3 100644 --- a/pass/Pass.hs +++ b/pass/Pass.hs @@ -61,12 +61,6 @@ type PassOnOpsM m ops type PassOnOps ops = PassOnOpsM PassM ops -type CheckOnOps ops - = (PolyplateSpine t ops () (PassM ())) => Pass t - -type PlainCheckOnOps ops - = (PolyplateSpine t ops () (PassM ())) => t -> PassM () - type PassASTOnOps ops = (PolyplateM A.AST ops () PassM, PolyplateM A.AST () ops PassM) => Pass A.AST @@ -76,8 +70,6 @@ type PassTypeOnOps ops type PassOn t = PassOnOps (OneOpM PassM t) type PassOn2 s t = PassOnOps (TwoOpM PassM s t) type PassTypeOn t = PassTypeOnOps (OneOpM PassM t) -type CheckOn t = CheckOnOps (OneOpQ (PassM ()) t) -type PlainCheckOn t = PlainCheckOnOps (OneOpQ (PassM ()) t) -- | A description of an AST-mangling pass. data Pass t = Pass { diff --git a/pass/Traversal.hs b/pass/Traversal.hs index 68eac0e..50c1480 100644 --- a/pass/Traversal.hs +++ b/pass/Traversal.hs @@ -22,7 +22,6 @@ module Traversal ( TransformM, Transform, TransformStructured, TransformStructured', TransformStructuredM' , CheckM, Check , ExtOpMP, ExtOpMS, ExtOpMSP, extOpMS, PassOnStruct, PassASTOnStruct - , ExtOpQS, extOpQS , applyBottomUpMS, ASTStructured , module Data.Generics.Polyplate , module Data.Generics.Polyplate.Schemes @@ -36,7 +35,6 @@ import Data.Generics.Polyplate.Schemes import qualified AST as A import NavAST() -import NavASTSpine() import Pass -- | A transformation for a single 'Data' type. @@ -71,52 +69,36 @@ type PassASTOnStruct = PassASTOnOps (ExtOpMSP BaseOp) class (PolyplateM (A.Structured a) () opsM m ,PolyplateM (A.Structured a) opsM () m - ,PolyplateSpine (A.Structured a) opsQ () r - ,PolyplateSpine (A.Structured a) () opsQ r ,Data a ,Monad m ) => ASTStructured a opsM m opsQ r instance (PolyplateM (A.Structured ()) () opsM m ,PolyplateM (A.Structured ()) opsM () m - ,PolyplateSpine (A.Structured ()) opsQ () r - ,PolyplateSpine (A.Structured ()) () opsQ r ,Monad m) => ASTStructured () opsM m opsQ r instance (PolyplateM (A.Structured A.Alternative) () opsM m ,PolyplateM (A.Structured A.Alternative) opsM () m - ,PolyplateSpine (A.Structured A.Alternative) opsQ () r - ,PolyplateSpine (A.Structured A.Alternative) () opsQ r ,Monad m) => ASTStructured A.Alternative opsM m opsQ r instance (PolyplateM (A.Structured A.Choice) () opsM m ,PolyplateM (A.Structured A.Choice) opsM () m - ,PolyplateSpine (A.Structured A.Choice) opsQ () r - ,PolyplateSpine (A.Structured A.Choice) () opsQ r ,Monad m) => ASTStructured A.Choice opsM m opsQ r instance (PolyplateM (A.Structured A.ExpressionList) () opsM m ,PolyplateM (A.Structured A.ExpressionList) opsM () m - ,PolyplateSpine (A.Structured A.ExpressionList) opsQ () r - ,PolyplateSpine (A.Structured A.ExpressionList) () opsQ r ,Monad m) => ASTStructured A.ExpressionList opsM m opsQ r instance (PolyplateM (A.Structured A.Option) () opsM m ,PolyplateM (A.Structured A.Option) opsM () m - ,PolyplateSpine (A.Structured A.Option) opsQ () r - ,PolyplateSpine (A.Structured A.Option) () opsQ r ,Monad m) => ASTStructured A.Option opsM m opsQ r instance (PolyplateM (A.Structured A.Process) () opsM m ,PolyplateM (A.Structured A.Process) opsM () m - ,PolyplateSpine (A.Structured A.Process) opsQ () r - ,PolyplateSpine (A.Structured A.Process) () opsQ r ,Monad m) => ASTStructured A.Process opsM m opsQ r instance (PolyplateM (A.Structured A.Variant) () opsM m ,PolyplateM (A.Structured A.Variant) opsM () m - ,PolyplateSpine (A.Structured A.Variant) opsQ () r - ,PolyplateSpine (A.Structured A.Variant) () opsQ r ,Monad m) => ASTStructured A.Variant opsM m opsQ r @@ -150,47 +132,6 @@ extOpMS ops (_, f) `extOpM` (f :: A.Structured A.Alternative -> m (A.Structured A.Alternative)) `extOpM` (f :: A.Structured () -> m (A.Structured ())) -type ExtOpQS r opT = - (A.Structured () -> r, - (A.Structured A.Alternative -> r, - (A.Structured A.Choice -> r, - (A.Structured A.ExpressionList -> r, - (A.Structured A.Option -> r, - (A.Structured A.Process -> r, - (A.Structured A.Variant -> r, - opT))))))) - -extOpQS :: forall m opT op0T r. - (PolyplateSpine (A.Structured ()) () op0T r, - PolyplateSpine (A.Structured A.Alternative) () op0T r, - PolyplateSpine (A.Structured A.Choice) () op0T r, - PolyplateSpine (A.Structured A.ExpressionList) () op0T r, - PolyplateSpine (A.Structured A.Option) () op0T r, - PolyplateSpine (A.Structured A.Process) () op0T r, - PolyplateSpine (A.Structured A.Variant) () op0T r, - PolyplateSpine (A.Structured ()) op0T () r, - PolyplateSpine (A.Structured A.Alternative) op0T () r, - PolyplateSpine (A.Structured A.Choice) op0T () r, - PolyplateSpine (A.Structured A.ExpressionList) op0T () r, - PolyplateSpine (A.Structured A.Option) op0T () r, - PolyplateSpine (A.Structured A.Process) op0T () r, - PolyplateSpine (A.Structured A.Variant) op0T () r) => - opT -> - -- Pairing the next two arguments allows us to apply this function infix: - (op0T, -- just a type witness - forall t. ASTStructured t () PassM op0T r => A.Structured t -> r) -> - ExtOpQS r opT -extOpQS ops (_, f) - = ops - `extOpQ` (f :: A.Structured A.Variant -> r) - `extOpQ` (f :: A.Structured A.Process -> r) - `extOpQ` (f :: A.Structured A.Option -> r) - `extOpQ` (f :: A.Structured A.ExpressionList -> r) - `extOpQ` (f :: A.Structured A.Choice -> r) - `extOpQ` (f :: A.Structured A.Alternative -> r) - `extOpQ` (f :: A.Structured () -> r) - - applyBottomUpMS :: (PolyplateM t (ExtOpMSP BaseOp) () PassM) => (forall a. (Data a, PolyplateM (A.Structured a) () (ExtOpMSP BaseOp) PassM) => (A.Structured a -> PassM (A.Structured a))) diff --git a/polyplate/Data/Generics/Polyplate.hs b/polyplate/Data/Generics/Polyplate.hs index 2941914..f25ab60 100644 --- a/polyplate/Data/Generics/Polyplate.hs +++ b/polyplate/Data/Generics/Polyplate.hs @@ -124,14 +124,13 @@ with this program. If not, see . -- -- TODO include an example with routes module Data.Generics.Polyplate (PolyplateMRoute(..), PolyplateM(..), Polyplate(..), - PolyplateSpine(..), {-FullSpine(..),-} transformSpine, {-transformSpineFull,-} trimTree, makeRecurseM, RecurseM, makeRecurse, Recurse, makeDescendM, DescendM, makeDescend, Descend, -- makeRecurseQ, RecurseQ, -- makeDescendQ, DescendQ, BaseOp, baseOp, - ExtOpM, extOpM, ExtOpMRoute, extOpMRoute, ExtOp, extOp, OneOpM, OneOp, TwoOpM, TwoOp, - ExtOpQ, extOpQ, OneOpQ, TwoOpQ) where + ExtOpM, extOpM, ExtOpMRoute, extOpMRoute, ExtOp, extOp, OneOpM, OneOp, TwoOpM, TwoOp + ) where import Control.Monad.Identity import Data.Maybe @@ -232,77 +231,6 @@ instance (Monad m fakeRoute :: t -> Route t () fakeRoute = const $ error "transformM" - -- List of use cases for the Polyplate type-class, to try to decide best on its - -- necessary functions: - -- - -- 1. To perform a monadic modification on specific types in the ops across a - -- whole structure. - -- 2. As #1, but non-monadic (use Identity monad to adapt the above) - -- 3. To perform a query across the whole tree that returns a rose-tree that reflects - -- the (spine-view) structure of the data. - -- 4. As #3, but to return a flattened list (use flatten to adapt the above) - -- 5. To perform a monadic modification that also uses modification wrappers, - -- (a more general case of #1) - -- - -- So I think there are two classes needed: - -- - -- 1. One to apply monadic transformations that takes routes (covers #5, #2, #1) - -- - -- 2. One to apply tree-based queries that transform a whole data structure into - -- its tree spine-view, with optional methods for flattening into a depth-first - -- or breadth-first order. - --- | A class for transforming a data structure into its spine-view rose tree based --- on query functions. --- --- The first parameter is the item being processed. The fourth parameter is the --- return type of the query functions, which is used in the returned tree. --- --- The second and third parameters are the usual ops sets, but of the form: --- --- > (s -> a, (t -> a, ())) -class PolyplateSpine t o o' a where - -- | You are unlikely to need to use this function directly at all. See 'transformSpine' - -- or 'applyQuery' and 'listifyDepth' (and friends). - -- - -- The third parameter, which transformSpine passes as Nothing, is the value - -- to be used for the current node. Because this value is set somewhere in the - -- middle of the ops set, not necessarily at the end, this must be passed along - -- the sideways calls (while processing the first ops set). - transformSpineSparse :: o -> o' -> Maybe a -> t -> Tree (Maybe a) - -transformSpine :: PolyplateSpine t o o' a => o -> o' -> t -> Tree (Maybe a) -transformSpine o o' = transformSpineSparse o o' Nothing - -{- --- | Used at the type-level by this library to force a full traversal of a data --- structure. You are unlikely to need to use this directly. -data FullSpine a = FullSpine a --- TODO make this work - -transformSpineFull :: (ConvertSpineOpsToFull a o co, ConvertSpineOpsToFull a o' co', - PolyplateSpine t co co' a) => - a -> o -> o' -> t -> Tree a -transformSpineFull def o o' x - = fmap fromJust' $ - transformSpineSparse - (convertSpineOpsToFull def o) - (convertSpineOpsToFull def o') - Nothing x - where - fromJust' (Just x) = x - fromJust' _ = error "transformSpineFull: internal error" --} - --- | A function for pruning rose trees of maybe values. All trees where the node --- value (and the node value of all its children) is Nothing are discarded (Nothing --- is returned). -trimTree :: Tree (Maybe a) -> Maybe (Tree (Maybe a)) -trimTree tr | isNothing (rootLabel tr) && null trimmedChildren = Nothing - | otherwise = Just (Node (rootLabel tr) trimmedChildren) - where - trimmedChildren = mapMaybe trimTree (subForest tr) - -- | A non-monadic equivalent of PolyplateM. All ops sets are of the form: -- -- > (a -> a, (b -> b, ())) @@ -383,11 +311,6 @@ type ExtOpMRoute m opT t outer = ((t, Route t outer) -> m t, opT) -- for use with the 'Polyplate' class. type ExtOp opT t = (t -> t, opT) --- | The type that extends a query-ops set to be applied to the given type (t). --- Not to be mixed with modification operations. This is for use with the 'PolyplateSpine' --- class. -type ExtOpQ a opQ t = (t -> a, opQ) - -- | The function that extends an ops set (opT) in the given monad (m) to be applied to -- the given type (t). You cannot mix monadic and non-monadic operations in the -- same list. This is for use with the 'PolyplateM' class. @@ -406,26 +329,15 @@ extOpMRoute ops f = (f, ops) extOp :: opT -> (t -> t) -> ExtOp opT t extOp ops f = (f, ops) --- | The function that extends a query-ops set to be applied to the given type (t). --- Not to be mixed with modification operations. This is for use with the 'PolyplateSpine' --- class. -extOpQ :: opQ -> (t -> a) -> ExtOpQ a opQ t -extOpQ ops f = (f, ops) - - -- | A handy synonym for a monadic ops set with only one item, to use with 'PolyplateM'. type OneOpM m t = ExtOpM m BaseOp t -- | A handy synonym for an ops set with only one item, to use with 'Polyplate'. type OneOp t = ExtOp BaseOp t --- | A handy synonym for a query ops set with only one item, to use with 'PolyplateSpine'. -type OneOpQ a t = ExtOpQ a BaseOp t -- | A handy synonym for a monadic ops set with only two items, to use with 'PolyplateM'. type TwoOpM m s t = ExtOpM m (ExtOpM m BaseOp s) t -- | A handy synonym for an ops set with only two items, to use with 'Polyplate'. type TwoOp s t = ExtOp (ExtOp BaseOp s) t --- | A handy synonym for a monadic ops set with only two items, to use with 'PolyplateSpine'. -type TwoOpQ a s t = ExtOpQ a (ExtOpQ a BaseOp s) t -- {{{ Various type-level programming ops conversions: diff --git a/polyplate/Data/Generics/Polyplate/GenInstances.hs b/polyplate/Data/Generics/Polyplate/GenInstances.hs index c763ba3..3b4cc44 100644 --- a/polyplate/Data/Generics/Polyplate/GenInstances.hs +++ b/polyplate/Data/Generics/Polyplate/GenInstances.hs @@ -38,7 +38,7 @@ with this program. If not, see . module Data.Generics.Polyplate.GenInstances (GenOverlappedOption(..), GenClassOption(..), GenInstance, genInstance, genMapInstance, genSetInstance, genInstances, - writeInstances, writeInstancesTo, writeInstancesToSep) where + writeInstances, writeInstancesTo) where import Control.Monad.State import Data.Char @@ -440,231 +440,31 @@ instancesFrom genOverlapped genClass boxes w -- This is covered by one big overlapping instance: | otherwise = (False,[],[]) --- | Instances for a particular data type (i.e. where that data type is the --- first argument to 'Polyplate'). -spineInstancesFrom :: forall t. Data t => GenOverlappedOption -> GenClassOption -> [Witness] -> t -> IO [String] --- This method is similar to instancesFrom in terms of general behaviour, but still --- different enough that very little code could be shared, so it's clearer to pull --- it out to its own method: -spineInstancesFrom genOverlapped genClass boxes w - = do (specialProcessChildren, containedTypes) <- - case find (== Plain (DataBox w)) boxes of - Just (Detailed _ containedTypes _ doChildrenSpine) -> - -- It's a special case, use the detailed info: - do eachContained <- sequence [findTypesIn' c | DataBox c <- containedTypes] - return (Just (containedTypes, doChildrenSpine), foldl Map.union Map.empty eachContained) - -- It's a normal case, use findTypesIn' directly: - _ -> do ts <- findTypesIn' w - return (Nothing, ts) - containedKeys <- liftM Set.fromList - (sequence [typeKey c | DataBox c <- map witness $ justBoxes containedTypes]) - wKey <- typeKey w - otherInsts <- sequence [do ck <- typeKey c - return (otherInst wKey containedKeys c ck) - | DataBox c <- map witness boxes] - return $ baseInst specialProcessChildren ++ concat otherInsts - where - wName = show $ typeOf w - wMunged = mungeName wName - wDType = dataTypeOf w - wCtrs = if isAlgType wDType then dataTypeConstrs wDType else [] - - -- The module prefix of this type, so we can use it in constructor names. - modPrefix - = if '.' `elem` (takeWhile (\c -> isAlphaNum c || c == '.') wName) - then takeWhile (/= '.') wName ++ "." - else "" - - ctrArgs ctr - = gmapQ DataBox (fromConstr ctr :: t) - ctrArgTypes types - = [show $ typeOf w | DataBox w <- types] - - -- Given the context (a list of instance requirements), the left-hand ops, - -- the right-hand ops, and a list of lines for the body of the class, generates - -- an instance. - -- - -- For GenOneClass this will be an instance of PolyplateM. - -- - -- For GenClassPerType this will be an instance of PolyplateMFoo (or whatever) - -- - -- For GenSlowDelegate this will be an instance of PolyplateM', with the first - -- and last arguments swapped. - genInst :: [String] -> String -> String -> [String] -> [String] - genInst context ops0 ops1 body - = ["instance (" ++ concat (intersperse ", " context) ++ ") =>" - ," " ++ contextSameType ops0 ops1 ++ " where" - ] ++ map (" " ++) body - - -- Generates the name of an instance for the same type with the given two ops - -- sets. The class name will be the same as genInst. - contextSameType :: String -> String -> String - contextSameType ops0 ops1 = case genClass of - GenOneClass -> "PolyplateSpine (" ++ wName ++ ") " ++ ops0 ++ " " ++ ops1 ++ " a" - GenClassPerType -> "PolyplateSpine" ++ wMunged ++" " ++ ops0 ++ " " ++ ops1 ++ " a" - GenSlowDelegate -> "PolyplateSpine' a " ++ ops0 ++ " " ++ ops1 ++ " (" ++ wName ++ ")" - - -- Generates the name of an instance for a different type (for processing children). - -- This will be PolyplateM or PolyplateM'. - contextNewType :: String -> String -> String -> String - contextNewType cName ops0 ops1 = case genClass of - GenOneClass -> "PolyplateSpine (" ++ cName ++ ") " ++ ops0 ++ " " ++ ops1 ++ " a" - GenClassPerType -> "PolyplateSpine (" ++ cName ++ ") " ++ ops0 ++ " " ++ ops1 ++ " a" - GenSlowDelegate -> "PolyplateSpine' a " ++ ops0 ++ " " ++ ops1 ++ " (" ++ cName ++ ")" - - - -- The function to define in the body, and also to use for processing the same - -- type. - funcSameType :: String - funcSameType = case genClass of - GenClassPerType -> "transformSpineSparse" ++ wMunged - GenOneClass -> "transformSpineSparse" - GenSlowDelegate -> "transformSpineSparse'" - - -- The function to use for processing other types - funcNewType :: String - funcNewType = case genClass of - GenClassPerType -> "transformSpineSparse" - GenOneClass -> "transformSpineSparse" - GenSlowDelegate -> "transformSpineSparse'" - - -- | An instance that describes what to do when we have no transformations - -- left to apply. You can pass it an override for the case of processing children - -- (and the types that make up the children). - baseInst :: Maybe ([DataBox], (String, String) -> [String]) -> [String] - baseInst mdoChildren - = concat - [genInst context "()" "(f, ops)" $ - maybe - (if isAlgType wDType - -- An algebraic type: apply to each child if we're following. - then (concatMap constrCase wCtrs) - -- A primitive (or non-represented) type: just return it. - else [funcSameType ++ " () _ _ _ = Node Nothing []"]) - (\(_,f) -> f (funcSameType, funcNewType)) mdoChildren - ,genInst [] "()" "()" [funcSameType ++ " () () q _ = Node q []"] - --,genInst (contextNewType "(FullSpine a)" "()") "(FullSpine a)" "()" [funcSameType ++ " () () v = return v"] - ,if genOverlapped == GenWithoutOverlapped then [] else - genInst - [ contextSameType "r" "ops" ] - "(b -> a, r)" "ops" - [funcSameType ++ " (_, rest) ops = " ++ funcSameType ++ " rest ops"] - ,if genClass == GenClassPerType - then ["class PolyplateSpine" ++ wMunged ++ " o o' a where" - ," " ++ funcSameType ++ " :: o -> o' -> Maybe a -> (" ++ wName ++ - ") -> Tree (Maybe a)" - ,"" - ,"instance (" ++ contextSameType "o0" "o1" ++ ") =>" - ," PolyplateSpine (" ++ wName ++ ") o0 o1 a where" - ," transformSpineSparse = " ++ funcSameType - ] - else [] - ] - where - -- | Class context for 'baseInst'. - -- We need an instance of Polyplate for each of the types directly contained within - -- this type, so we can recurse into them. - context :: [String] - context - = [ contextNewType argType "(f,ops)" "()" - | argType <- nub $ sort $ concatMap ctrArgTypes $ - maybe (map ctrArgs wCtrs) ((:[]) . fst) mdoChildren] - - -- | A 'transformM' case for a particular constructor of this (algebraic) - -- data type: pull the value apart, apply 'transformM' to each part of it, - -- then stick it back together. - constrCase :: Constr -> [String] - constrCase ctr - = [ funcSameType ++ " () " ++ (if argNums == [] then "_" else "ops") ++ - " q (" ++ ctrInput ++ ")" - , " = Node q $ mapMaybe trimTree [" - ] ++ - intersperse - " ," - [ " " ++ funcNewType ++ " ops () Nothing a" ++ show i - | i <- argNums] ++ - [ " ]" - ] - where - argNums = [0 .. ((length $ ctrArgs ctr) - 1)] - ctrS = show ctr - ctrName = modPrefix ++ ctrS - makeCtr vs = ctrName ++ concatMap (" " ++) vs - ctrInput = makeCtr ["a" ++ show i | i <- argNums] - ctrResult = makeCtr ["r" ++ show i | i <- argNums] - - - -- | An instance that describes how to apply -- or not apply -- a - -- transformation. - otherInst :: Data s => Int -> Set.Set Int -> s -> Int -> [String] - otherInst wKey containedKeys c cKey - = if not shouldGen then [] else - genInst context - ("((" ++ cName ++ ") -> a, r)") - "ops" - impl - where - cName = show $ typeOf c - (shouldGen, context, impl) - -- This type might contain the type that the transformation acts - -- upon - | cKey `Set.member` containedKeys - = (True - ,[contextSameType "r" ("((" ++ cName ++ ") -> a, ops)")] - ,[if wKey == cKey - then funcSameType ++ " (f, rest) ops _ v = " - ++ funcSameType ++ " rest (f, ops) (Just (f v)) v" - else funcSameType ++ " (f, rest) ops = " ++ funcSameType ++ " rest (f, ops)"]) - -- This type can't contain the transformed type; just move on to the - -- next transformation. - | genOverlapped == GenWithoutOverlapped - = (True - ,[contextSameType "r" "ops"] - ,[funcSameType ++ " (_, rest) ops = " ++ funcSameType ++ " rest ops"]) - -- This is covered by one big overlapping instance: - | otherwise = (False,[],[]) - - - -- | Generates all the given instances (eliminating any duplicates) -- with the given options. The return is a pair of a list of instances of PolyplateMRoute, -- and a list of instances of PolyplateSpine genInstances :: GenOverlappedOption -> GenClassOption -> [GenInstance] -> - IO ([String], [String]) + IO [String] genInstances op1 op2 insts = do typeMap <- flip execStateT Map.empty (sequence [g | GenInstance g <- insts]) - let (inst, spineInst) = unzip [ - (instancesFrom op1 op2 (justBoxes typeMap) w - ,spineInstancesFrom op1 op2 (justBoxes typeMap) w) - | DataBox w <- map witness $ justBoxes typeMap] + let inst = [instancesFrom op1 op2 (justBoxes typeMap) w + | DataBox w <- map witness $ justBoxes typeMap] inst' <- sequence inst - spineInst' <- sequence spineInst - return (concat inst', concat spineInst') + return $ concat inst' -- | Generates the instances according to the options and writes it to stdout with -- the given header (the header is a list of lines without newline characters). writeInstances :: GenOverlappedOption -> GenClassOption -> [GenInstance] -> [String] -> IO () writeInstances op1 op2 inst header - = do (instLines, spineInstLines) <- genInstances op1 op2 inst - putStr (unlines (header ++ instLines ++ spineInstLines)) - --- | Generates the instances according to the options and writes the PolyplateMRoute --- instances with the first header (the header is a list of lines without newline characters) --- to the first filename, and the PolyplateSpine instances with the second header --- to the second filename. -writeInstancesToSep :: GenOverlappedOption -> GenClassOption -> [GenInstance] -> ([String], - [String]) -> (FilePath, FilePath) -> IO () -writeInstancesToSep op1 op2 inst (header1, header2) (fileName1, fileName2) - = do (instLines, spineInstLines) <- genInstances op1 op2 inst - writeFile fileName1 (unlines (header1 ++ instLines)) - writeFile fileName2 (unlines (header2 ++ spineInstLines)) + = do instLines <- genInstances op1 op2 inst + putStr (unlines (header ++ instLines)) -- | Generates the instances according to the options and writes it to a file with -- the given header (the header is a list of lines without newline characters). writeInstancesTo :: GenOverlappedOption -> GenClassOption -> [GenInstance] -> [String] -> FilePath -> IO () writeInstancesTo op1 op2 inst header fileName - = do (instLines, spineInstLines) <- genInstances op1 op2 inst - writeFile fileName (unlines (header ++ instLines ++ spineInstLines)) + = do instLines <- genInstances op1 op2 inst + writeFile fileName (unlines (header ++ instLines)) --{{{ Various SYB-based functions that we don't export, for discovering contained types: diff --git a/polyplate/Data/Generics/Polyplate/Schemes.hs b/polyplate/Data/Generics/Polyplate/Schemes.hs index e2e7c35..ac9f489 100644 --- a/polyplate/Data/Generics/Polyplate/Schemes.hs +++ b/polyplate/Data/Generics/Polyplate/Schemes.hs @@ -19,8 +19,7 @@ with this program. If not, see . module Data.Generics.Polyplate.Schemes where -import Data.Maybe -import Data.Tree +import Control.Monad.State import Data.Generics.Polyplate import Data.Generics.Polyplate.Route @@ -81,52 +80,17 @@ makeCheckM ops f v descend = makeDescend ops -} --- * Query functions that return rose-trees of results - --- | Given a query function that turns all items of type \"s\" into results of --- type \"a\", applies the function to every instance of \"s\" inside a larger --- structure of type \"t\", and gives the resulting values of type \"a\" back in --- a rose-tree. A node in the tree will be generated for every constructor in --- the larger item (of type \"t\"). If the constructor was of type \"s\", the --- corresponding tree node will contain Just (the result of the query function). --- If the constructor was any other type, the corresponding tree node will contain --- Nothing. --- --- Also note that the result is trimmed. If a particular sub-tree has no items --- of the target type, instead of getting a whole sub-tree with Nothing values, --- you will get one node (at the top of the sub-tree) with a Nothing value. This --- is to make the traversal more efficient, in terms of time and space. -applyQuery :: PolyplateSpine t (OneOpQ a s) () a => (s -> a) -> t -> Tree (Maybe a) -applyQuery qf = transformSpine ops () - where - ops = baseOp `extOpQ` qf - --- | As 'applyQuery', but takes two query functions that act on different types --- (\"sA\" and \"sB\") but return the same result type (\"a\"). -applyQuery2 :: PolyplateSpine t (TwoOpQ a sA sB) () a => (sA -> a) -> (sB -> a) -> t -> Tree (Maybe a) -applyQuery2 qfA qfB = transformSpine ops () - where - ops = baseOp `extOpQ` qfA `extOpQ` qfB - -- * Listify functions that return lists of items that satisfy given criteria -- | Given a function that examines a type \"s\" and gives an answer (True to include -- the item in the list, False to drop it), finds all items of type \"s\" in some -- larger item (of type \"t\") that satisfy this function, listed in depth-first -- order. -listifyDepth :: PolyplateSpine t (OneOpQ (Maybe s) s) () (Maybe s) => (s -> Bool) -> t -> [s] -listifyDepth qf = catMaybes . flatten . fmap (fromMaybe Nothing) . transformSpine ops () +listifyTopDown :: (PolyplateM t (OneOpM (State [s]) s) () (State [s]) + ,PolyplateM s () (OneOpM (State [s]) s) (State [s])) => (s -> Bool) -> t -> [s] +listifyTopDown qf = flip execState [] . applyBottomUpM qf' where - qf' x = if qf x then Just x else Nothing - ops = baseOp `extOpQ` qf' - --- | As 'listifyDepth', but the returned list is in breadth-first order. -listifyBreadth :: PolyplateSpine t (OneOpQ (Maybe s) s) () (Maybe s) => (s -> Bool) -> t -> [s] -listifyBreadth qf = catMaybes . (concat . levels) . fmap (fromMaybe Nothing) . transformSpine ops () - where - qf' x = if qf x then Just x else Nothing - ops = baseOp `extOpQ` qf' - + qf' x = if qf x then modify (x:) >> return x else return x -- * Check functions to apply monadic checks throughout a data structure @@ -136,23 +100,19 @@ listifyBreadth qf = catMaybes . (concat . levels) . fmap (fromMaybe Nothing) . t -- -- This can be used, for example, to perform checks on items in an error monad, -- or to accumulate information in a state monad. -checkDepthM :: (Monad m, PolyplateSpine t (OneOpQ (m ()) s) () (m ())) => (s -> m ()) -> t -> m () -checkDepthM f = sequence_ . catMaybes . flatten . applyQuery f +checkDepthM :: (Monad m, PolyplateM t (OneOpM m s) () m + , PolyplateM s () (OneOpM m s) m) => (s -> m ()) -> t -> m () +checkDepthM f x = applyBottomUpM (\x -> f x >> return x) x >> return () -- | As 'checkDepthM', but takes two functions (one operating on type \"r\", the -- other on type \"s\"). -checkDepthM2 :: (Monad m, PolyplateSpine t (TwoOpQ (m ()) r s) () (m ())) => +checkDepthM2 :: (Monad m, PolyplateM t (TwoOpM m r s) () m + , PolyplateM r () (TwoOpM m r s) m + , PolyplateM s () (TwoOpM m r s) m + ) => (r -> m ()) -> (s -> m ()) -> t -> m () -checkDepthM2 f g = sequence_ . catMaybes . flatten . applyQuery2 f g - --- | As 'checkDepthM', but applies the checks in breadth-first order. -checkBreadthM :: (Monad m, PolyplateSpine t (OneOpQ (m ()) s) () (m ())) => (s -> m ()) -> t -> m () -checkBreadthM f = sequence_ . catMaybes . concat . levels . applyQuery f - --- | As 'checkDepthM2', but applies the checks in breadth-first order. -checkBreadthM2 :: (Monad m, PolyplateSpine t (TwoOpQ (m ()) r s) () (m ())) => - (r -> m ()) -> (s -> m ()) -> t -> m () -checkBreadthM2 f g = sequence_ . catMaybes . concat . levels . applyQuery2 f g +checkDepthM2 f g x = applyBottomUpM2 (\x -> f x >> return x) + (\y -> g y >> return y) x >> return () -- * Functions to easily apply transformations throughout a data structure diff --git a/pregen/GenNavAST.hs b/pregen/GenNavAST.hs index 08bf12f..435c1db 100644 --- a/pregen/GenNavAST.hs +++ b/pregen/GenNavAST.hs @@ -31,8 +31,8 @@ import qualified Errors main :: IO () main = do - [instFileName, spineInstFileName] <- getArgs - writeInstancesToSep GenWithOverlapped GenClassPerType + [instFileName] <- getArgs + writeInstancesTo GenWithOverlapped GenOneClass [ genInstance (undefined :: AST.AST) , genInstance (undefined :: CompState.CompState) -- All the maps that are in CompState: @@ -48,8 +48,8 @@ main = do , genSetInstance (undefined :: AST.Name) , genSetInstance (undefined :: CompState.NameAttr) ] - (header False (findModuleName instFileName), header True (findModuleName spineInstFileName)) - (instFileName, spineInstFileName) + (header False (findModuleName instFileName)) + instFileName where findModuleName moduleFileName | not (".hs" `isSuffixOf` moduleFileName) diff --git a/transformations/SimplifyAbbrevs.hs b/transformations/SimplifyAbbrevs.hs index fece9c6..096d046 100644 --- a/transformations/SimplifyAbbrevs.hs +++ b/transformations/SimplifyAbbrevs.hs @@ -263,7 +263,7 @@ abbrevCheckPass checkNotWritten (A.Variable m n) "VAL-abbreviated variable % written-to inside the scope of the abbreviation" sequence_ [checkNotWritten v "Abbreviated variable % used inside the scope of the abbreviation" - | A.ExprVariable _ v <- listifyDepth (const True) e] + | A.ExprVariable _ v <- listifyTopDown (const True) e] pop return s doStructured s = descend s @@ -288,7 +288,7 @@ abbrevCheckPass checkAbbreved v@(A.Variable {}) msg = checkNone v msg checkAbbreved v@(A.DirectedVariable {}) msg = checkNone v msg checkAbbreved (A.SubscriptedVariable _ sub v) msg - = sequence_ [checkNotWritten subV msg | subV <- listifyDepth (const True) sub] + = sequence_ [checkNotWritten subV msg | subV <- listifyTopDown (const True) sub] checkNone :: A.Variable -> String -> StateT [Map.Map Var Bool] PassM () checkNone v msg