CSPM-Frontend-0.9.0.6: src/Language/CSPM/AstUtils.hs
-----------------------------------------------------------------------------
-- |
-- Module : Language.CSPM.AstUtils
-- Copyright : (c) Fontaine 2008 - 2011
-- License : BSD3
--
-- Maintainer : Fontaine@cs.uni-duesseldorf.de
-- Stability : experimental
-- Portability : GHC-only
--
-- Some utility functions for converting the AST
module Language.CSPM.AstUtils
(
removeSourceLocations
,removeParens
,removeModuleAsserts
,unUniqueIdent
,computeFreeNames
,getModuleAsserts
,setNodeIdsZero
)
where
import Language.CSPM.AST hiding (prologMode)
import qualified Language.CSPM.SrcLoc as SrcLoc
import qualified Data.IntMap as IntMap
import Data.Data
import Data.Maybe
import Data.Generics.Schemes (everywhere,listify)
import Data.Generics.Aliases (mkT)
-- | 'removeSourceLocations' sets all locationsInfos to 'NoLocation'
removeSourceLocations :: Data a => a -> a
removeSourceLocations ast
= everywhere (mkT patchLabel) ast
where
patchLabel :: SrcLoc.SrcLoc -> SrcLoc.SrcLoc
patchLabel _ = SrcLoc.NoLocation
-- | 'removeParens' removes all occurences of of Parens,
-- i.e. explicit parentheses from the AST
removeParens :: Data a => a -> a
removeParens ast
= everywhere (mkT patchExp) ast
where
patchExp :: LExp -> LExp
patchExp x = case unLabel x of
Parens e -> e
_ -> x
-- | Set all NodeIds to zero.
setNodeIdsZero :: Data a => a -> a
setNodeIdsZero ast
= everywhere (mkT nID) ast
where
nID :: NodeId -> NodeId
nID _ = NodeId { unNodeId = 0 }
-- | unUniqueIdent replaces the all UIdent with the Ident of the the new name,
-- thus forgetting additional information like the bindingside, etc.
-- Usefull to get a smaller AST.
unUniqueIdent :: Data a => a -> a
unUniqueIdent ast
= everywhere (mkT patchIdent) ast
where
patchIdent :: Ident -> Ident
patchIdent (UIdent u) = Ident $ newName u
patchIdent _ = error "unUniqueIdent : did not expect and 'Ident' in the AST"
-- | Compute the "FreeNames" of an Expression.
-- This function does only work after renaming has been done.
-- This implementation is inefficient.
computeFreeNames :: Data a => a -> FreeNames
computeFreeNames syntax
= IntMap.difference (IntMap.fromList used) (IntMap.fromList def)
where
used :: [(Int, UniqueIdent)]
used = map (getIdent . unUse) $ listify isUse syntax
def :: [(Int, UniqueIdent)]
def = (map (getIdent . unDef) $ listify isDef syntax)
++ (map (getIdent . unDecl) $ listify isDecl syntax)
getIdent :: LIdent -> (Int, UniqueIdent)
getIdent x = (uniqueIdentId h, h)
where h = unUIdent $ unLabel x
isUse :: Exp -> Bool
isUse (Var {}) = True
isUse _ = False
unUse (Var x) = x
unUse _ = error "computeFreeNames : expecting Var"
isDef :: Pattern -> Bool
isDef (VarPat {}) = True
isDef _ = False
isDecl (FunBind {}) = True
isDecl _ = False
unDef (VarPat x) = x
unDef _ = error "computeFreeNames : expecting VarPar"
unDecl (FunBind x _) = x
unDecl _ = error "computeFreeNames : expecting FunBind"
-- | Get the assert declarations of a module.
getModuleAsserts :: Module a -> [LAssertDecl]
getModuleAsserts = mapMaybe justAssert . moduleDecls
where
justAssert decl = case unLabel decl of
Assert a -> Just a
_ -> Nothing
-- | Remove assert declarations from a module.
removeModuleAsserts :: Module a -> Module a
removeModuleAsserts m = m { moduleDecls = mapMaybe notAssert $ moduleDecls m}
where
notAssert decl = case unLabel decl of
Assert _ -> Nothing
_ -> Just decl