{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BlockArguments #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE NoMonomorphismRestriction #-} module ReduceC ( defaultReduceC, defaultReduceCWithKeywords, -- reduceCTranslUnit, -- * Context Context (..), defaultContext, -- * Helpers prettyIdent, ) where import Control.Monad.Reduce import Data.Data import Data.Foldable import Data.Function import Data.Functor import qualified Data.List as List import qualified Data.Map.Strict as Map import Data.Maybe import qualified Data.Set as Set import Data.Vector.Internal.Check (HasCallStack) -- import Debug.Trace -- -- Todo stuckt names import Control.Applicative import Control.Monad import qualified Control.Monad.IRTree as IRTree import Data.Monoid import qualified Language.C as C import qualified Language.C.Data.Ident as C data Context = Context { keywords :: !(Set.Set Keyword) , typeDefs :: !(Map.Map C.Ident InlineType) , inlineExprs :: !(Map.Map C.Ident InlineExpr) , fields :: !(Map.Map C.Ident (Maybe C.Ident)) , structs :: !(Map.Map C.Ident (Maybe C.CStructUnion)) } deriving (Show) data InlineType = ITKeep | ITInline ![C.CDeclarationSpecifier C.NodeInfo] deriving (Show, Eq) data InlineExpr = IEDelete | IEInline !C.CExpr | IEKeep deriving (Show, Eq) data Keyword = LoseMain | DoNoops | InlineTypeDefs | NoSemantics | AllowEmptyDeclarations | DisallowVariableInlining | AllowInfiniteForLoops deriving (Show, Read, Enum, Eq, Ord) type Lab = (String, C.Position) defaultReduceCWithKeywords :: (MonadReduce (String, C.Position) m) => [Keyword] -> C.CTranslUnit -> m C.CTranslUnit defaultReduceCWithKeywords keywords a = reduceCTranslUnit a (defaultContext{keywords = Set.fromList keywords}) {-# SPECIALIZE defaultReduceCWithKeywords :: [Keyword] -> C.CTranslUnit -> IRTree.IRTree (String, C.Position) C.CTranslUnit #-} defaultReduceC :: (MonadReduce (String, C.Position) m) => C.CTranslUnit -> m C.CTranslUnit defaultReduceC a = reduceCTranslUnit a defaultContext {-# SPECIALIZE defaultReduceC :: C.CTranslUnit -> IRTree.IRTree (String, C.Position) C.CTranslUnit #-} addTypeDefs :: [C.Ident] -> InlineType -> Context -> Context addTypeDefs ids cs Context{..} = Context { typeDefs = foldl' (\a i -> Map.insert i cs a) typeDefs ids , .. } addInlineExpr :: C.Ident -> InlineExpr -> Context -> Context addInlineExpr i e Context{..} = Context { inlineExprs = Map.insert i e inlineExprs , .. } addKeyword :: Keyword -> Context -> Context addKeyword k Context{..} = Context { keywords = Set.insert k keywords , .. } addStruct :: StructDef -> Context -> Context addStruct (StructDef k fs _) Context{..} = Context { structs = Map.insert k Nothing structs , fields = foldr (`Map.insert` Just k) fields fs , .. } removeStruct :: StructDef -> Context -> Context removeStruct (StructDef k fs un) Context{..} = Context { structs = Map.insert k (Just un) structs , fields = foldr (`Map.insert` Nothing) fields fs , .. } -- deleteKeyword :: Keyword -> Context -> Context -- deleteKeyword k Context{..} = -- Context -- { keywords = Set.delete k keywords -- , .. -- } defaultContext :: Context defaultContext = Context { keywords = Set.fromList [] , typeDefs = Map.empty , inlineExprs = Map.fromList [ (C.builtinIdent "fabsf", IEKeep) , (C.builtinIdent "fabs", IEKeep) , (C.builtinIdent "__PRETTY_FUNCTION__", IEKeep) , (C.builtinIdent "__FUNCTION__", IEKeep) ] , fields = Map.empty , structs = Map.empty } isIn :: Keyword -> Context -> Bool isIn k = Set.member k . keywords prettyIdent :: C.Identifier C.NodeInfo -> [Char] prettyIdent (C.Ident s _ a) = s ++ " at " ++ show (C.posOfNode a) reduceCTranslUnit :: (MonadReduce Lab m) => C.CTranslationUnit C.NodeInfo -> Context -> m (C.CTranslationUnit C.NodeInfo) reduceCTranslUnit (C.CTranslUnit es ni) ctx = do res' <- foldr reduceCExternalDeclaration (\_ -> pure []) es ctx es' <- sequence res' pure $ C.CTranslUnit es' ni reduceCExternalDeclaration :: (MonadReduce Lab m) => C.CExternalDeclaration C.NodeInfo -> (Context -> m [m (C.CExternalDeclaration C.NodeInfo)]) -> Context -> m [m (C.CExternalDeclaration C.NodeInfo)] reduceCExternalDeclaration r cont ctx = do -- TODO This is slow case r of C.CFDefExt fun | not (LoseMain `isIn` ctx) && maybe False (("main" ==) . C.identToString) (functionName fun) -> do ((C.CFDefExt <$> reduceCFunDef fun ctx) :) <$> cont ctx | otherwise -> case functionName fun of Just fid -> do split ("remove function " <> C.identToString fid, C.posOf r) (cont (addInlineExpr fid IEDelete ctx)) do ((C.CFDefExt <$> reduceCFunDef fun ctx) :) <$> cont (addInlineExpr fid IEKeep ctx) Nothing -> do split ("remove function", C.posOf r) (cont ctx) (((C.CFDefExt <$> reduceCFunDef fun ctx) :) <$> cont ctx) C.CDeclExt decl -> do (decl', ctx') <- handleDecl decl ctx case decl' of Just d -> ((C.CDeclExt <$> d) :) <$> cont ctx' Nothing -> cont ctx' _r -> don'tHandle r data StructDef = StructDef { structId :: !C.Ident , fieldIds :: ![C.Ident] , structDef :: !C.CStructUnion } deriving (Show, Eq) structIds :: (Foldable f) => f (C.CDeclarationSpecifier C.NodeInfo) -> [StructDef] structIds = concatMap \case C.CTypeSpec (C.CSUType (C.CStruct a (Just n) (Just ma) b c) _) -> [ StructDef n [ x | C.CDecl _ itms _ <- ma , C.CDeclarationItem (C.CDeclr (Just x) _ _ _ _) _ _ <- itms ] (C.CStruct a (Just n) (Just ma) b c) ] _ow -> [] trySplit :: (MonadReduce l m, Eq a) => l -> a -> (a -> a) -> m a trySplit l a action = do let a' = action a if a /= a' then split l (pure a') (pure a) else pure a reduceCFunDef :: (MonadReduce Lab m, HasCallStack) => C.CFunctionDef C.NodeInfo -> Context -> m (C.CFunctionDef C.NodeInfo) reduceCFunDef (C.CFunDef spc dec cdecls smt ni) ctx = do spc1 <- trySplit ("remove static", C.posOf ni) spc $ filter \case C.CStorageSpec (C.CStatic _) -> False _ow -> True spc2 <- trySplit ("remove inline", C.posOf ni) spc1 $ filter \case C.CFunSpec (C.CInlineQual _) -> False _ow -> True smt' <- reduceCStatementOrEmptyBlock smt ctx' pure $ C.CFunDef (inlineTypeDefsSpecs spc2 ctx) (inlineTypeDefsCDeclarator dec ctx) (map (`inlineTypeDefsCDeclaration` ctx) cdecls) smt' ni where !ctx' = foldr (`addInlineExpr` IEKeep) ctx ids ids = params dec params :: C.CDeclarator C.NodeInfo -> [C.Ident] params (C.CDeclr _ declrs _ _ _) = declrs & concatMap \case C.CFunDeclr (C.CFunParamsNew decls _) _ _ -> decls & concatMap \case C.CDecl _ items _ -> items & concatMap \case C.CDeclarationItem (C.CDeclr (Just idx) _ _ _ _) _ _ -> [idx] _ow -> [] a -> don'tHandleWithPos a _ow -> [] reduceCCompoundBlockItem :: (MonadReduce Lab m, HasCallStack) => C.CCompoundBlockItem C.NodeInfo -> (Context -> m [C.CCompoundBlockItem C.NodeInfo]) -> Context -> m [C.CCompoundBlockItem C.NodeInfo] reduceCCompoundBlockItem r cont ctx = do case r of C.CBlockStmt smt -> do case reduceCStatement smt ctx of Just rsmt -> split ("remove statement", C.posOf r) (cont ctx) do smt' <- rsmt case smt' of C.CCompound [] ss _ -> do split ("expand compound statment", C.posOf r) ((ss <>) <$> cont ctx) do (C.CBlockStmt smt' :) <$> cont ctx _ow -> do (C.CBlockStmt smt' :) <$> cont ctx Nothing -> cont ctx C.CBlockDecl declr -> do (declr', ctx') <- handleDecl declr ctx case declr' of Just d -> do d' <- (C.CBlockDecl <$> d) (d' :) <$> cont ctx' Nothing -> cont ctx' a -> don'tHandle a handleDecl :: (MonadReduce Lab m) => C.CDeclaration C.NodeInfo -> Context -> m (Maybe (m (C.CDeclaration C.NodeInfo)), Context) handleDecl d ctx = case inlineTypeDefsCDeclaration d ctx of -- A typedef C.CDecl (C.CStorageSpec (C.CTypedef _) : rst) decl _ -> do let [ids] = identifiers decl whenSplit (InlineTypeDefs `isIn` ctx) ("inline typedef " <> C.identToString ids, C.posOf d) (pure (Nothing, addTypeDefs [ids] (ITInline rst) ctx)) (pure (Just (pure d), addTypeDefs [ids] ITKeep ctx)) -- A const C.CDecl spc decl ni' -> do (decl', ctx') <- foldr reduceCDeclarationItem (pure ([], ctx)) decl let fn = do spc1 <- trySplit ("remove static", C.posOf ni') spc $ filter \case C.CStorageSpec (C.CStatic _) -> False _ow -> True pure $ C.CDecl spc1 decl' ni' case (decl', structIds spc) of ([], []) | AllowEmptyDeclarations `isIn` ctx' -> split ("remove empty declaration", C.posOf d) (pure (Nothing, ctx')) do pure (Just fn, ctx') | otherwise -> pure (Nothing, ctx') ([], stcts) -> split ("remove declaration", C.posOf d) (pure (Nothing, foldr removeStruct ctx' stcts)) do pure (Just fn, foldr addStruct ctx' stcts) (_, stcts) -> pure (Just fn, foldr addStruct ctx' stcts) a -> don'tHandleWithPos a reduceCDeclarationItem :: (MonadReduce Lab m) => C.CDeclarationItem C.NodeInfo -> m ([C.CDeclarationItem C.NodeInfo], Context) -> m ([C.CDeclarationItem C.NodeInfo], Context) reduceCDeclarationItem d ma = case d of C.CDeclarationItem dr@(C.CDeclr (Just i) [] Nothing [] ni) (Just (C.CInitExpr c ni')) Nothing -> do (ds, ctx) <- ma c' <- fromMaybe (pure zeroExpr) (reduceCExpr c ctx) split ("inline variable " <> C.identToString i, C.posOf ni) (pure (ds, addInlineExpr i (IEInline c') ctx)) ( pure ( inlineTypeDefsCDI (C.CDeclarationItem dr (Just (C.CInitExpr c' ni')) Nothing) ctx : ds , addInlineExpr i IEKeep ctx ) ) C.CDeclarationItem (C.CDeclr (Just i) a Nothing b ni) ex Nothing -> do (ds, ctx) <- ma ex' <- case ex of Just ix -> maybeSplit ("remove initializer", C.posOf ni) (reduceCInitializer ix ctx) Nothing -> pure Nothing let d' = C.CDeclarationItem (C.CDeclr (Just i) a Nothing b ni) ex' Nothing split ("remove variable " <> C.identToString i, C.posOf ni) (pure (ds, addInlineExpr i IEDelete ctx)) (pure (inlineTypeDefsCDI d' ctx : ds, addInlineExpr i IEKeep ctx)) a@(C.CDeclarationItem (C.CDeclr _ _ _ _ ni) _ _) -> do don'tHandleWithNodeInfo a ni a -> don'tHandle a reduceCInitializer :: (MonadReduce Lab m) => C.CInitializer C.NodeInfo -> Context -> Maybe (m (C.CInitializer C.NodeInfo)) reduceCInitializer a ctx = case a of C.CInitExpr e ni' -> do rm <- reduceCExpr e ctx Just $ (`C.CInitExpr` ni') <$> rm C.CInitList (C.CInitializerList items) ni -> do ritems <- forM items \case ([], it) -> fmap ([],) <$> reduceCInitializer it ctx (as, _) -> notSupportedYet (fmap noinfo as) ni Just $ (`C.CInitList` ni) . C.CInitializerList <$> sequence ritems reduceCStatementOrEmptyBlock :: (MonadReduce Lab m, HasCallStack) => C.CStatement C.NodeInfo -> Context -> m (C.CStatement C.NodeInfo) reduceCStatementOrEmptyBlock stmt ctx = do case reduceCStatement stmt ctx of Just ex -> do ex Nothing -> do pure emptyBlock emptyBlock :: C.CStatement C.NodeInfo emptyBlock = C.CCompound [] [] C.undefNode reduceCStatement :: (MonadReduce Lab m, HasCallStack) => C.CStatement C.NodeInfo -> Context -> Maybe (m (C.CStatement C.NodeInfo)) reduceCStatement smt ctx = case smt of C.CCompound is cbi ni -> Just do cbi' <- foldr reduceCCompoundBlockItem (\_ -> pure []) cbi ctx pure $ C.CCompound is cbi' ni C.CWhile e s dow ni -> do rs <- reduceCStatement s ctx Just do e' <- reduceCExprOrZero e ctx s' <- rs pure $ C.CWhile e' s' dow ni C.CExpr me ni -> do case me of Just e -> do if DoNoops `isIn` ctx then Just do e' <- maybeSplit ("change to noop", C.posOf smt) $ reduceCExpr e ctx pure $ C.CExpr e' ni else do re <- reduceCExpr e ctx Just do e' <- re pure $ C.CExpr (Just e') ni Nothing -> Just $ pure $ C.CExpr Nothing ni C.CReturn me ni -> do -- TODO: If function returntype is not struct return 0 case me of Just e -> do re <- reduceCExpr e ctx Just $ do e' <- re pure $ C.CReturn (Just e') ni Nothing -> Just . pure $ C.CReturn Nothing ni C.CIf e s els ni -> Just do e' <- maybeSplit ("remove condition", C.posOf e) $ reduceCExpr e ctx els' <- case els of Just els' -> do maybeSplit ("remove else branch", C.posOf els') do reduceCStatement els' ctx Nothing -> pure Nothing ms' <- maybeSplit ("remove if branch", C.posOf s) do reduceCStatement s ctx case (e', ms', els') of (Nothing, Nothing, Nothing) -> pure emptyBlock (Just e'', Just s', Nothing) -> pure $ C.CIf e'' s' Nothing ni (Nothing, Just s', Just x) -> pure $ C.CIf zeroExpr s' (Just x) ni (Just e'', Just s', Just x) -> pure $ C.CIf e'' s' (Just x) ni (Just e'', Nothing, Nothing) -> pure $ C.CExpr (Just e'') C.undefNode (Nothing, Nothing, Just x) -> pure x (Just e'', Nothing, Just x) -> pure $ C.CIf e'' emptyBlock (Just x) ni (Nothing, Just s', Nothing) -> pure s' C.CFor e1 e2 e3 s ni -> Just $ do (me1', ctx') <- case e1 of C.CForDecl (C.CDecl rec decl ni') -> do (decl', ctx') <- foldr reduceCDeclarationItem (pure ([], ctx)) decl res <- if null decl' then whenSplit (AllowEmptyDeclarations `isIn` ctx') ("remove empty declaration", C.posOf ni') (pure Nothing) (pure $ Just $ C.CForDecl (C.CDecl rec decl' ni')) else pure $ Just $ C.CForDecl (C.CDecl rec decl' ni') pure (res, ctx') C.CForInitializing e -> do e' <- maybeSplit ("remove initializer", C.posOf ni) (e >>= \e' -> reduceCExpr e' ctx) whenSplit (AllowEmptyDeclarations `isIn` ctx) ("remove empty declaration", C.posOf ni) (pure (Nothing, ctx)) (pure (Just $ C.CForInitializing e', ctx)) d -> don'tHandle d s' <- reduceCStatementOrEmptyBlock s ctx' let forloop n = do e2' <- case e2 of Just e2' -> maybeSplit ("remove check", C.posOf e2') (reduceCExpr e2' ctx') Nothing -> pure Nothing e3' <- case e3 of Just e3' -> maybeSplit ("remove iterator", C.posOf e3') (reduceCExpr e3' ctx') Nothing -> pure Nothing let e2'' = if AllowInfiniteForLoops `isIn` ctx || isNothing e2 then e2' else e2' <|> Just zeroExpr pure $ C.CFor n e2'' e3' s' ni case me1' of Nothing -> do split ("remove the for loop", C.posOf smt) (pure s') do forloop (C.CForInitializing Nothing) Just e1' -> do forloop e1' C.CBreak ni -> Just do pure (C.CBreak ni) C.CCont ni -> Just do pure (C.CCont ni) C.CLabel i s [] ni -> Just do s' <- reduceCStatementOrEmptyBlock s ctx pure $ C.CLabel i s' [] ni C.CGoto i ni -> Just do pure $ C.CGoto i ni a -> don'tHandleWithPos a -- | If the condition is statisfied try to reduce to the a. whenSplit :: (MonadReduce Lab m) => Bool -> Lab -> m a -> m a -> m a whenSplit cn lab a b | cn = split lab a b | otherwise = b maybeSplit :: (MonadReduce Lab m) => Lab -> Maybe (m a) -> m (Maybe a) maybeSplit lab = \case Just r -> do split lab (pure Nothing) (Just <$> r) Nothing -> do pure Nothing zeroExpr :: C.CExpression C.NodeInfo zeroExpr = C.CConst (C.CIntConst (C.cInteger 0) C.undefNode) reduceCExprOrZero :: (MonadReduce Lab m, HasCallStack) => C.CExpr -> Context -> m C.CExpr reduceCExprOrZero expr ctx = do case reduceCExpr expr ctx of Just ex -> do r <- ex if r == zeroExpr then pure r else split ("replace by zero", C.posOf expr) (pure zeroExpr) (pure r) Nothing -> do pure zeroExpr {-# INLINE reduceCExprOrZero #-} reduceCExpr :: (MonadReduce Lab m, HasCallStack) => C.CExpr -> Context -> Maybe (m C.CExpr) reduceCExpr expr ctx = case expr of C.CBinary o elhs erhs ni -> do if o `elem` [C.CNeqOp, C.CEqOp, C.CGeqOp, C.CLeqOp, C.CGrOp, C.CLeOp] then do -- in this case we change type, so we need to keep the operation rl <- reduceCExpr elhs ctx rr <- reduceCExpr erhs ctx Just $ do l' <- rl r' <- rr pure $ C.CBinary o l' r' ni else do case reduceCExpr elhs ctx of Just elhs' -> case reduceCExpr erhs ctx of Just erhs' -> pure do split ("reduce to left", C.posOf elhs) elhs' do split ("reduce to right", C.posOf erhs) erhs' do l' <- elhs' r' <- erhs' pure $ C.CBinary o l' r' ni Nothing -> pure elhs' Nothing | otherwise -> fail "could not reduce left hand side" C.CAssign o elhs erhs ni -> case reduceCExpr elhs (addKeyword DisallowVariableInlining ctx) of Just elhs' -> case reduceCExpr erhs ctx of Just erhs' -> pure do split ("reduce to left", C.posOf elhs) elhs' do split ("reduce to right", C.posOf erhs) erhs' do l' <- elhs' r' <- erhs' pure $ C.CAssign o l' r' ni Nothing -> fail "could not reduce right hand side" Nothing | otherwise -> fail "could not reduce left hand side" C.CVar i _ -> case Map.lookup i . inlineExprs $ ctx of Just mx -> case mx of IEKeep -> Just (pure expr) IEInline mx' | DisallowVariableInlining `isIn` ctx -> Nothing | otherwise -> Just (pure mx') IEDelete -> Nothing Nothing -> error ("Could not find " <> show i <> " at " <> show (C.posOf expr) <> "\n" <> show (inlineExprs ctx)) C.CConst x -> Just do pure $ C.CConst x C.CUnary o elhs ni -> do elhs' <- reduceCExpr elhs (addKeyword DisallowVariableInlining ctx) Just $ split ("reduce to operant", C.posOf expr) elhs' do e <- elhs' pure $ C.CUnary o e ni C.CCall e es ni -> do let re = reduceCExpr e (addKeyword DisallowVariableInlining ctx) res = map (`reduceCExpr` ctx) es case (re, catMaybes res) of (Nothing, []) -> Nothing (Nothing, [r]) -> Just r (_, _) -> Just do e' <- maybeSplit ("do without function", C.posOf e) re es' <- res & traverse (maybeSplit ("do without pram", C.posOf e)) case (e', catMaybes es') of (Nothing, []) -> pure zeroExpr (Nothing, [e'']) -> pure e'' (Nothing, es'') -> pure $ C.CComma es'' C.undefNode (Just f, _) -> pure $ C.CCall f (map (fromMaybe zeroExpr) es') ni C.CCond ec et ef ni -> do -- TODO: More fine grained reduction is possible here. Just $ do ec' <- reduceCExprOrZero ec ctx ef' <- reduceCExprOrZero ef ctx et' <- case et of Just et' -> Just <$> reduceCExprOrZero et' ctx Nothing -> pure Nothing pure $ C.CCond ec' et' ef' ni C.CCast decl e ni -> do re <- reduceCExpr e ctx Just do split ("don't cast", C.posOf ni) re do e' <- re pure (C.CCast (inlineTypeDefsCDeclaration decl ctx) e' ni) C.CIndex e1 e2 ni -> do -- TODO: Better reduction is posisble here. re1 <- reduceCExpr e1 ctx Just do e1' <- re1 e2' <- reduceCExprOrZero e2 ctx pure $ C.CIndex e1' e2' ni C.CComma items ni -> do let Just (x, rst) = List.uncons (reverse items) rx <- reduceCExpr x ctx Just do rst' <- foldr ( \e cc -> do maybeSplit ("remove expression", C.posOf e) (reduceCExpr e ctx) >>= \case Just e' -> (e' :) <$> cc Nothing -> cc ) (pure []) rst x' <- rx if List.null rst' then pure x' else pure $ C.CComma (reverse (x' : rst')) ni C.CMember e i l ni -> do re <- reduceCExpr e ctx Just do e' <- re pure (C.CMember e' i l ni) a -> don'tHandleWithPos a inlineTypeDefsCDeclaration :: C.CDeclaration C.NodeInfo -> Context -> C.CDeclaration C.NodeInfo inlineTypeDefsCDeclaration decl ctx = case decl of C.CDecl items decli ni -> C.CDecl (inlineTypeDefsSpecs items ctx) (map (`inlineTypeDefsCDI` ctx) decli) ni a -> don'tHandle a inlineTypeDefsSpecs :: [C.CDeclarationSpecifier C.NodeInfo] -> Context -> [C.CDeclarationSpecifier C.NodeInfo] inlineTypeDefsSpecs r ctx = r & concatMap \case a@(C.CTypeSpec (C.CTypeDef idx _)) -> do case Map.lookup idx . typeDefs $ ctx of Just ITKeep -> [a] Just (ITInline res) -> res Nothing -> error ("could not find typedef:" <> show idx) a@(C.CTypeSpec (C.CSUType (C.CStruct _ (Just idx) Nothing _ _) _)) -> case Map.lookup idx . structs $ ctx of Just (Just def) -> [C.CTypeSpec (C.CSUType def C.undefNode)] Just Nothing -> [a] Nothing -> error ("could not find struct:" <> show idx) C.CTypeSpec (C.CSUType (C.CStruct a b (Just c) d e) f) -> [C.CTypeSpec (C.CSUType (C.CStruct a b (Just $ map (`inlineTypeDefsCDeclaration` ctx) c) d e) f)] a -> [a] {-# NOINLINE inlineTypeDefsSpecs #-} inlineTypeDefsCDeclarator :: C.CDeclarator C.NodeInfo -> Context -> C.CDeclarator C.NodeInfo inlineTypeDefsCDeclarator (C.CDeclr idn derivedd st atr ni) ctx = C.CDeclr idn (map (inlineTypeDefsX ctx) derivedd) st atr ni inlineTypeDefsX :: Context -> C.CDerivedDeclarator C.NodeInfo -> C.CDerivedDeclarator C.NodeInfo inlineTypeDefsX ctx = \case C.CFunDeclr (C.CFunParamsNew x y) b c -> C.CFunDeclr (C.CFunParamsNew (map (`inlineTypeDefsCDeclaration` ctx) x) y) b c C.CArrDeclr a b c -> C.CArrDeclr a b c C.CPtrDeclr a b -> C.CPtrDeclr a b a -> don'tHandle a inlineTypeDefsCDI :: C.CDeclarationItem C.NodeInfo -> Context -> C.CDeclarationItem C.NodeInfo inlineTypeDefsCDI di ctx = case di of C.CDeclarationItem a b ni -> C.CDeclarationItem (inlineTypeDefsCDeclarator a ctx) b ni a -> don'tHandle a identifiers :: forall a. (Data a) => a -> [C.Ident] identifiers d = appEndo (go d) [] where go :: forall a'. (Data a') => a' -> Endo [C.Ident] go d' = case cast d' of Just l -> Endo (l :) Nothing -> gmapQl (<>) mempty go d' functionName :: C.CFunctionDef C.NodeInfo -> Maybe C.Ident functionName = \case C.CFunDef _ (C.CDeclr ix _ _ _ _) _ _ _ -> ix notSupportedYet :: (HasCallStack, Show a) => a -> C.NodeInfo -> b notSupportedYet a ni = error (show a <> " at " <> show (C.posOf ni)) noinfo :: (Functor f) => f C.NodeInfo -> f () noinfo a = a $> () don'tHandle :: (HasCallStack, Functor f, Show (f ())) => f C.NodeInfo -> b don'tHandle f = error (show (f $> ())) don'tHandleWithPos :: (HasCallStack, Functor f, Show (f ()), C.Pos (f C.NodeInfo)) => f C.NodeInfo -> b don'tHandleWithPos f = error (show (f $> ()) <> " at " <> show (C.posOf f)) don'tHandleWithNodeInfo :: (HasCallStack, Functor f, Show (f ())) => f C.NodeInfo -> C.NodeInfo -> b don'tHandleWithNodeInfo f ni = error (show (f $> ()) <> " at " <> show (C.posOf ni))