content: module Language.C.Syntax.Utils (
    -- * Generic operations
    getSubStmts,
    mapSubStmts,
    mapBlockItemStmts,
    -- * Concrete operations
    getLabels
  ) where
  
  import Data.List
  import Language.C.Data.Ident
  import Language.C.Syntax.AST
  
  -- XXX: This is should be generalized !!!
  --      Data.Generics sounds attractive, but we really need to control the evaluation order
  -- XXX: Expression statements (which are somewhat problematic anyway), aren't handled yet
  getSubStmts :: CStat -> [CStat]
  getSubStmts (CLabel _ s _ _)      = [s]
  getSubStmts (CCase _ s _)         = [s]
  getSubStmts (CCases _ _ s _)      = [s]
  getSubStmts (CDefault s _)        = [s]
  getSubStmts (CExpr _ _)           = []
  getSubStmts (CCompound _ body _)  = concatMap compoundSubStmts body
  getSubStmts (CIf _ sthen selse _) = maybe [sthen] (\s -> [sthen,s]) selse
  getSubStmts (CSwitch _ s _)       = [s]
  getSubStmts (CWhile _ s _ _)      = [s]
  getSubStmts (CFor _ _ _ s _)      = [s]
  getSubStmts (CGoto _ _)           = []
  getSubStmts (CGotoPtr _ _)        = []
  getSubStmts (CCont _)             = []
  getSubStmts (CBreak _)            = []
  getSubStmts (CReturn _ _)         = []
  getSubStmts (CAsm _ _)            = []
  
  mapSubStmts :: (CStat -> Bool) -> (CStat -> CStat) -> CStat -> CStat
  mapSubStmts stop _ s | stop s = s
  mapSubStmts stop f (CLabel i s attrs ni) =
    f (CLabel i (mapSubStmts stop f s) attrs ni)
  mapSubStmts stop f (CCase e s ni) =
    f (CCase e (mapSubStmts stop f s) ni)
  mapSubStmts stop f (CCases e1 e2 s ni) =
    f (CCases e1 e2 (mapSubStmts stop f s) ni)
  mapSubStmts stop f (CDefault s ni) =
    f (CDefault (mapSubStmts stop f s) ni)
  mapSubStmts stop f (CCompound ls body ni) =
    f (CCompound ls (map (mapBlockItemStmts stop f) body) ni)
  mapSubStmts stop f (CIf e sthen selse ni) =
    f (CIf e
       (mapSubStmts stop f sthen)
       (maybe Nothing (Just . mapSubStmts stop f) selse)
       ni)
  mapSubStmts stop f (CSwitch e s ni) =
    f (CSwitch e (mapSubStmts stop f s) ni)
  mapSubStmts stop f (CWhile e s isdo ni) =
    f (CWhile e (mapSubStmts stop f s) isdo ni)
  mapSubStmts stop f (CFor i t a s ni) =
    f (CFor i t a (mapSubStmts stop f s) ni)
  mapSubStmts _ f s  = f s
  
  mapBlockItemStmts :: (CStat -> Bool)
                    -> (CStat -> CStat)
                    -> CBlockItem
                    -> CBlockItem
  mapBlockItemStmts stop f (CBlockStmt s) = CBlockStmt (mapSubStmts stop f s)
  mapBlockItemStmts _ _ bi                = bi
  
  compoundSubStmts :: CBlockItem -> [CStat]
  compoundSubStmts (CBlockStmt s)    = [s]
  compoundSubStmts (CBlockDecl _)    = []
  compoundSubStmts (CNestedFunDef _) = []
  
  getLabels :: CStat -> [Ident]
  getLabels (CLabel l s _ _)      = l : getLabels s
  getLabels (CCompound ls body _) =
    concatMap (concatMap getLabels . compoundSubStmts) body \\ ls
  getLabels stmt                  = concatMap getLabels (getSubStmts stmt)
  