module Camfort.Transformation.DeadCode where
import Camfort.Analysis.Annotations
import qualified Language.Fortran.Analysis.DataFlow as FAD
import qualified Language.Fortran.Analysis.Renaming as FAR
import qualified Language.Fortran.Analysis.BBlocks as FAB
import qualified Language.Fortran.AST as F
import qualified Language.Fortran.Util.Position as FU
import qualified Language.Fortran.Analysis as FA
import Camfort.Helpers
import Camfort.Helpers.Syntax
import qualified Data.IntMap as IM
import qualified Data.Set as S
import Data.Generics.Uniplate.Operations
import Data.Maybe
import GHC.Generics
import Debug.Trace
deadCode :: Bool -> (Filename, F.ProgramFile A)
                 -> (Report, (Filename, F.ProgramFile A))
deadCode flag (fname, pf) = (report, (fname, fmap FA.prevAnnotation pf'))
  where
    (report, pf'') = deadCode' flag lva pf'
    
    pf'   = FAB.analyseBBlocks . FAR.analyseRenames . FA.initAnalysis $ pf
    
    bbm   = FAB.genBBlockMap pf'
    
    sgr   = FAB.genSuperBBGr bbm
    
    gr    = FAB.superBBGrGraph sgr
    
    lva   = FAD.liveVariableAnalysis gr
deadCode' :: Bool -> FAD.InOutMap (S.Set F.Name)
                  -> F.ProgramFile (FA.Analysis A)
                  -> (Report, F.ProgramFile (FA.Analysis A))
deadCode' flag lva pf =
    if null report
      then (report, pf')
      else (report, pf') >>= deadCode' flag lva
  where
    (report, pf') = transformBiM (perStmt flag lva) pf
perStmt :: Bool
        -> FAD.InOutMap (S.Set F.Name)
        -> F.Statement (FA.Analysis A) -> (Report, F.Statement (FA.Analysis A))
perStmt flag lva x@(F.StExpressionAssign a sp@(FU.SrcSpan s1 s2) e1 e2)
     | pRefactored (FA.prevAnnotation a) == flag =
  fromMaybe ("", x) $
    do label <- FA.insLabel a
       (_, out) <- IM.lookup label lva
       assignedName <- extractVariable e1
       if assignedName `S.member` out
         then Nothing
         else 
           Just (report, F.StExpressionAssign a' (dropLine sp) e1 e2)
             where report =  "o" ++ show s1 ++ ": removed dead code\n"
                   
                   
                   a' = onPrev (\ap -> ap {refactored = Just s1}) a
perStmt _ _ x = return x