content: module ADropDefs(aDropDefs) where
  
  import ASyntax
  import ASyntaxUtil
  import qualified Data.Map as M
  import qualified Data.Set as S
  import Control.Monad.State
  import AConv(isLocalAId)
  import Id
  
  -- get all of the ASDef usage in a "thing"
  dVars :: (AExprs a) => a -> [AId]
  dVars = findAExprs dVarsE
    where dVarsE (ASDef _ i) = [i]
          dVarsE (APrim { ae_args = es }) = dVars es
          dVarsE (AMethCall { ae_args = es}) = dVars es
          dVarsE (ANoInlineFunCall { ae_args = es }) = dVars es
          dVarsE (AFunCall { ae_args = es }) = dVars es
          dVarsE _ = []
  
  aDropDefs :: ASPackage -> ASPackage
  aDropDefs aspkg = aspkg { aspkg_values = defs' }
    where roots = dVars (aspkg_state_instances aspkg) ++
                  map fst (aspkg_outputs aspkg) ++
                  dVars (aspkg_foreign_calls aspkg) ++
                  aspkg_inlined_ports aspkg ++
                  fires ++ meth_ids ++ unusedKeeps
          unusedKeeps = [i | ADef i _ e _ <- defs,
                         hasIdProp i IdP_keepEvenUnused
                         || isKeepId i
                           ]
          defs  = aspkg_values aspkg
          dmap  = M.fromList [(i, dVars e) | ADef i _ e _ <- defs ]
          used  = execState (mapM_ (addUsed dmap) roots) S.empty
          -- isKeepId must be in the roots or else it can result in a
          -- parent getting kept but not a child.
          keepId i | isKeepId i = True
          keepId i | isLocalAId i = i `S.member` used
          keepId i = True
          fires = [ i | d@(ADef i _ _ _) <- defs, isFire i]
          meth_ids = [i | d@(ADef i _ _ _) <- defs, isMethId i]
          defs' = [ d | d@(ADef i _ _ _) <- defs, keepId i]
  
  addUsed :: M.Map AId [AId] -> AId -> State (S.Set AId) ()
  addUsed dmap i = do
    s <- get
    if (i `S.member` s) then return ()
     else do put (S.insert i s)
             let is = M.findWithDefault [] i dmap
             mapM_ (addUsed dmap) is
  