{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-} module Language.C2ATS.Process ( flatGlobal , injectForwardDecl , sortFlatGlobal , injectIncludes , FlatGlobalDecl (..) , FlatG (..) ) where import Data.Maybe import Data.List import Data.Set (Set) import qualified Data.Set as Set import Data.Map (Map) import qualified Data.Map as Map import Text.Regex.Posix import Debug.Trace {- for warnings -} import Language.C import Language.C.Analysis import Language.C.Data.Ident data FlatGlobalDecl = FGObj IdentDecl | FGTag TagDef | FGType TypeDef | FGRaw String instance CNode FlatGlobalDecl where nodeInfo (FGObj d) = nodeInfo d nodeInfo (FGTag d) = nodeInfo d nodeInfo (FGType d) = nodeInfo d nodeInfo (FGRaw _) = undefNode type FlatG = (SUERef, FlatGlobalDecl) flatGlobal :: GlobalDecls -> [FlatG] flatGlobal gmap = theTags ++ theObjs ++ theTypeDefs where theTags = Map.assocs $ Map.map FGTag $ gTags gmap theObjs = Map.assocs $ Map.map FGObj $ Map.mapKeys NamedRef $ gObjs gmap theTypeDefs = Map.assocs $ Map.map FGType $ Map.mapKeys NamedRef $ gTypeDefs gmap injectIncludes :: [String] -> [String] -> [FlatG] -> [FlatG] injectIncludes includes excludes m = concat . map incl . map reverse . sortElems . foldl go ([], Map.empty) $ m where f :: String -> Maybe FilePath f ('<':_) = Nothing f xs = Just . filter (\c -> c /= '"' && c /= ':' && c /= '(') . head . words $ xs getFile :: FlatG -> Maybe FilePath getFile = f . show . posOfNode . nodeInfo . snd sortElems :: ([Maybe FilePath], Map (Maybe FilePath) [FlatG]) -> [[FlatG]] sortElems (file:files,mp) = sortElems (files, Map.delete file mp) ++ [fromJust $ Map.lookup file mp] sortElems ([], _) = [] go :: ([Maybe FilePath], Map (Maybe FilePath) [FlatG]) -> FlatG -> ([Maybe FilePath], Map (Maybe FilePath) [FlatG]) go (files,mp) fg = let file = getFile fg files' = if file `elem` files then files else file:files in (files', Map.insertWith (++) file [fg] mp) incl :: [FlatG] -> [FlatG] incl fgs@((s,fg):_) = case getFile (s,fg) of Nothing -> (s, FGRaw $ "// No file"):fgs (Just file) | (or $ map (=~ file) includes) || (not . or $ map ((=~) file) excludes) -> (s, FGRaw $ init $ unlines [ "// File: " ++ file, "%{#", "#include \"" ++ file ++ "\"", "%}" ]):fgs (Just file) -> (s, FGRaw $ "// File: " ++ file):fgs -------------------------------------------------------------------------------- sortFlatGlobal :: [FlatG] -> [FlatG] sortFlatGlobal = (\(a,_,_,b) -> reverse a ++ b) . foldl go ([], Set.empty, Set.empty, []) . sortBy order where order :: FlatG -> FlatG -> Ordering order (_, a) (_, b) = nodeInfo a `compare` nodeInfo b go :: ([FlatG], Set Int, Set Int, [FlatG]) -> FlatG -> ([FlatG], Set Int, Set Int, [FlatG]) go (out, knowns, deps, ks) fg@(s,_) = let knowns' = Set.insert (nodeSUERef s) knowns deps' = Set.difference (Set.union deps $ anons fg) knowns' out' = (if Set.null deps' then reverse ks ++ [fg] else []) ++ out ks' = if Set.null deps' then [] else fg : ks in (out', knowns', deps', ks') anons :: FlatG -> Set Int anons (_, g) = anonRefs g nodeSUERef :: SUERef -> Int nodeSUERef (AnonymousRef n) = nameId n nodeSUERef (NamedRef (Ident _ _ (NodeInfo _ _ n))) = nameId n nodeSUERef _ = -1 class AnonRefs p where anonRefs :: p -> Set Int instance AnonRefs FlatGlobalDecl where anonRefs (FGObj d) = anonRefs d anonRefs (FGTag d) = anonRefs d anonRefs (FGType d) = anonRefs d instance AnonRefs IdentDecl where anonRefs (Declaration (Decl v _)) = anonRefs v anonRefs (ObjectDef (ObjDef v _ _)) = anonRefs v anonRefs (FunctionDef (FunDef v _ _)) = anonRefs v anonRefs (EnumeratorDef _) = Set.empty -- ATS does not have enum instance AnonRefs MemberDecl where anonRefs (MemberDecl v _ _) = anonRefs v anonRefs (AnonBitField t _ _) = anonRefs t instance AnonRefs VarDecl where anonRefs (VarDecl _ _ t) = anonRefs t instance AnonRefs TagDef where anonRefs (EnumDef _) = Set.empty -- ATS does not have enum anonRefs (CompDef (CompType _ _ m _ _)) = Set.unions $ map anonRefs m instance AnonRefs TypeDef where anonRefs (TypeDef _ t _ _) = anonRefs t instance AnonRefs Type where anonRefs (PtrType t _ _) = anonRefs t anonRefs (ArrayType t _ _ _) = anonRefs t anonRefs (FunctionType ft _) = anonRefs ft anonRefs (DirectType tn _ _) = anonRefs tn anonRefs _ = Set.empty instance AnonRefs TypeName where anonRefs (TyComp (CompTypeRef s _ _)) = anonRefs s anonRefs _ = Set.empty instance AnonRefs FunType where anonRefs (FunTypeIncomplete t) = anonRefs t anonRefs (FunType t p _) = Set.union (anonRefs t) (Set.unions $ map anonRefs p) instance AnonRefs ParamDecl where anonRefs (ParamDecl v _) = anonRefs v anonRefs (AbstractParamDecl v _) = anonRefs v instance AnonRefs SUERef where anonRefs s@(AnonymousRef _) = Set.singleton $ nodeSUERef s anonRefs (NamedRef _) = Set.empty -------------------------------------------------------------------------------- type IndentsMap = (Maybe String, Set String) injectForwardDecl :: [FlatG] -> [FlatG] injectForwardDecl = reverse . fst . foldl f ([], Set.empty) where f :: ([FlatG], Set String) -> FlatG -> ([FlatG], Set String) f (fgs, is) fg@(s,g) = let (i, is') = idents g knownis = maybe is (\a -> Set.insert a is) i fds = forwardDecls $ Set.elems $ Set.difference is' knownis is'' = Set.union is' knownis in (fg : fds ++ fgs, is'') forwardDecls :: [String] -> [FlatG] forwardDecls = map f where f i = (NamedRef $ mkIdent nopos i (Name (-1)), FGRaw $ "abst@ype " ++ i ++ " // FIXME! Forward declaration.") identsAppend :: IndentsMap -> IndentsMap -> IndentsMap identsAppend (i_a@(Just _), is_a) (i_b, is_b) = (i_a, Set.union is_a is_b) identsAppend (Nothing, is_a) (i_b, is_b) = (i_b, Set.union is_a is_b) class Idents p where idents :: p -> IndentsMap instance Idents FlatGlobalDecl where idents (FGObj d) = idents d idents (FGTag d) = idents d idents (FGType d) = idents d idents (FGRaw _) = (Nothing, Set.empty) instance Idents IdentDecl where idents (Declaration (Decl v _)) = idents v idents (ObjectDef (ObjDef v _ _)) = idents v idents (FunctionDef (FunDef v _ _)) = idents v idents _ = (Nothing, Set.empty) instance Idents MemberDecl where idents (MemberDecl v _ _) = idents v idents (AnonBitField t _ _) = idents t instance Idents VarDecl where idents (VarDecl _ _ t) = idents t instance Idents TagDef where idents (CompDef (CompType (NamedRef i) k m _ _)) = foldl (\a b -> a `identsAppend` idents b) (Just $ show k ++ "_c2ats_" ++ identToString i, Set.empty) m idents (CompDef (CompType (AnonymousRef _) _ m _ _)) = foldl (\a b -> a `identsAppend` idents b) (Nothing, Set.empty) m idents _ = (Nothing, Set.empty) instance Idents TypeDef where idents (TypeDef i t _ _) = (Just $ "type_c2ats_" ++ identToString i, Set.empty) `identsAppend` idents t instance Idents Type where idents (PtrType t _ _) = idents t idents (ArrayType t _ _ _) = idents t idents (FunctionType ft _) = idents ft idents (DirectType (TyComp (CompTypeRef (NamedRef i) k _)) _ _) = (Nothing, Set.singleton $ show k ++ "_c2ats_" ++ identToString i) idents (TypeDefType (TypeDefRef i _ _) _ _) = (Nothing, Set.singleton $ "type_c2ats_" ++ identToString i) idents _ = (Nothing, Set.empty) instance Idents FunType where idents (FunTypeIncomplete t) = idents t idents (FunType t pd _) = foldl (\a b -> a `identsAppend` idents b) (idents t) pd instance Idents ParamDecl where idents (ParamDecl v _) = idents v idents (AbstractParamDecl v _) = idents v