{-# 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,
-- 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.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
= KeepMain
| DoNoops
| NoSemantics
| AllowEmptyDeclarations
| DisallowVariableInlining
deriving (Show, Read, Enum, Eq, Ord)
type Lab = (String, C.Position)
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 [KeepMain]
, 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
| KeepMain `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
split
("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 -> Just do
case me of
Just e -> do
e' <- reduceCExprOrZero e ctx
pure $ C.CReturn (Just e') ni
Nothing ->
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'
case me1' of
Nothing -> do
split ("remove the for loop", C.posOf smt) (pure s') 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
pure $ C.CFor (C.CForInitializing Nothing) e2' e3' s' ni
Just e1' -> 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
pure $ C.CFor e1' e2' e3' s' ni
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
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 ->
fail "could not reduce right hand side"
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))