{-
   Copyright 2016, Dominic Orchard, Andrew Rice, Mistral Contrastin, Matthew Danish

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}

module Camfort.Transformation.EquivalenceElim
  ( refactorEquivalences
  ) where

import           Camfort.Analysis
import           Camfort.Analysis.Annotations
import           Camfort.Helpers.Syntax
import           Camfort.Transformation.DeadCode
import           Control.Monad.State.Lazy hiding (ap)
import           Data.Generics.Uniplate.Operations
import           Data.List
import qualified Data.Map as M
import           Data.Void (Void)
import qualified Language.Fortran.AST as F
import qualified Language.Fortran.Analysis as FA
import qualified Language.Fortran.Analysis.Renaming as FAR
import qualified Language.Fortran.Analysis.Types as FAT (analyseTypes, TypeEnv)
import qualified Language.Fortran.Util.Position as FU

type EquivalenceRefactoring = PureAnalysis Void Void

type A1 = FA.Analysis Annotation
type RmEqState = ([[F.Expression A1]], Int)

refactorEquivalences :: F.ProgramFile A -> EquivalenceRefactoring (F.ProgramFile A)
refactorEquivalences :: ProgramFile A -> EquivalenceRefactoring (ProgramFile A)
refactorEquivalences ProgramFile A
pf = do
  let
    -- initialise analysis
    pf' :: ProgramFile (Analysis A)
pf'             = ProgramFile (Analysis A) -> ProgramFile (Analysis A)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
FAR.analyseRenames (ProgramFile (Analysis A) -> ProgramFile (Analysis A))
-> (ProgramFile A -> ProgramFile (Analysis A))
-> ProgramFile A
-> ProgramFile (Analysis A)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> ProgramFile (Analysis A)
forall (b :: * -> *) a. Functor b => b a -> b (Analysis a)
FA.initAnalysis (ProgramFile A -> ProgramFile (Analysis A))
-> ProgramFile A -> ProgramFile (Analysis A)
forall a b. (a -> b) -> a -> b
$ ProgramFile A
pf
    -- calculate types
    (ProgramFile (Analysis A)
pf'', TypeEnv
typeEnv) = ProgramFile (Analysis A) -> (ProgramFile (Analysis A), TypeEnv)
forall a.
Data a =>
ProgramFile (Analysis a) -> (ProgramFile (Analysis a), TypeEnv)
FAT.analyseTypes ProgramFile (Analysis A)
pf'
    -- Remove equivalences and add appropriate copy statements
  ProgramFile (Analysis A)
pf''' <- TypeEnv
-> ProgramFile (Analysis A)
-> EquivalenceRefactoring (ProgramFile (Analysis A))
refactoring TypeEnv
typeEnv ProgramFile (Analysis A)
pf''
  -- Lastly deadcode eliminate any redundant copy statements
  -- generated by the refactoring (but don't dead code elim
  -- existing code)
  Bool -> ProgramFile A -> EquivalenceRefactoring (ProgramFile A)
deadCode Bool
True ((Analysis A -> A) -> ProgramFile (Analysis A) -> ProgramFile A
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Analysis A -> A
forall a. Analysis a -> a
FA.prevAnnotation ProgramFile (Analysis A)
pf''')
  where
    refactoring
      :: FAT.TypeEnv -> F.ProgramFile A1
      -> EquivalenceRefactoring (F.ProgramFile A1)
    refactoring :: TypeEnv
-> ProgramFile (Analysis A)
-> EquivalenceRefactoring (ProgramFile (Analysis A))
refactoring TypeEnv
tenv ProgramFile (Analysis A)
pf' = do
      (ProgramFile (Analysis A)
pf'', RmEqState
_) <- StateT RmEqState EquivalenceRefactoring (ProgramFile (Analysis A))
-> RmEqState
-> EquivalenceRefactoring (ProgramFile (Analysis A), RmEqState)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT StateT RmEqState EquivalenceRefactoring (ProgramFile (Analysis A))
equiv ([], Int
0)
      ProgramFile (Analysis A)
-> EquivalenceRefactoring (ProgramFile (Analysis A))
forall (m :: * -> *) a. Monad m => a -> m a
return ProgramFile (Analysis A)
pf''
      where
         equiv :: StateT RmEqState EquivalenceRefactoring (ProgramFile (Analysis A))
equiv = do ProgramFile (Analysis A)
pf'' <- (Block (Analysis A)
 -> StateT RmEqState EquivalenceRefactoring (Block (Analysis A)))
-> ProgramFile (Analysis A)
-> StateT
     RmEqState EquivalenceRefactoring (ProgramFile (Analysis A))
forall (m :: * -> *) from to.
(Monad m, Applicative m, Biplate from to) =>
(to -> m to) -> from -> m from
transformBiM Block (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Block (Analysis A))
perBlockRmEquiv ProgramFile (Analysis A)
pf'
                    ([Block (Analysis A)]
 -> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)])
-> ProgramFile (Analysis A)
-> StateT
     RmEqState EquivalenceRefactoring (ProgramFile (Analysis A))
forall from to (m :: * -> *).
(Biplate from to, Applicative m) =>
(to -> m to) -> from -> m from
descendBiM (TypeEnv
-> [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
addCopysPerBlockGroup TypeEnv
tenv) ProgramFile (Analysis A)
pf''

addCopysPerBlockGroup
  :: FAT.TypeEnv -> [F.Block A1]
  -> StateT RmEqState EquivalenceRefactoring [F.Block A1]
addCopysPerBlockGroup :: TypeEnv
-> [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
addCopysPerBlockGroup TypeEnv
tenv [Block (Analysis A)]
blocks = do
    [[Block (Analysis A)]]
blockss <- (Block (Analysis A)
 -> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)])
-> [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [[Block (Analysis A)]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (TypeEnv
-> Block (Analysis A)
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
addCopysPerBlock TypeEnv
tenv) [Block (Analysis A)]
blocks
    [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Block (Analysis A)]
 -> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)])
-> [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
forall a b. (a -> b) -> a -> b
$ [[Block (Analysis A)]] -> [Block (Analysis A)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Block (Analysis A)]]
blockss

addCopysPerBlock
  :: FAT.TypeEnv -> F.Block A1
  -> StateT RmEqState EquivalenceRefactoring [F.Block A1]
addCopysPerBlock :: TypeEnv
-> Block (Analysis A)
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
addCopysPerBlock TypeEnv
tenv b :: Block (Analysis A)
b@(F.BlStatement Analysis A
_ SrcSpan
_ Maybe (Expression (Analysis A))
_
                 (F.StExpressionAssign Analysis A
a sp :: SrcSpan
sp@(FU.SrcSpan Position
s1 Position
_) Expression (Analysis A)
dstE Expression (Analysis A)
_))
  | Bool -> Bool
not (A -> Bool
pRefactored (A -> Bool) -> A -> Bool
forall a b. (a -> b) -> a -> b
$ Analysis A -> A
forall a. Analysis a -> a
FA.prevAnnotation Analysis A
a) = do
    -- Find all variables/cells that are equivalent to the target
    -- of this assignment
    [Expression (Analysis A)]
eqs <- Expression (Analysis A)
-> StateT
     RmEqState EquivalenceRefactoring [Expression (Analysis A)]
equivalentsToExpr Expression (Analysis A)
dstE
    -- If there is only one, then it must refer to itself, so do nothing
    if [Expression (Analysis A)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Expression (Analysis A)]
eqs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
1
      then [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
forall (m :: * -> *) a. Monad m => a -> m a
return [Block (Analysis A)
b]
    -- If there are more than one, copy statements must be generated
      else do
        ([[Expression (Analysis A)]]
equivs, Int
n) <- StateT RmEqState EquivalenceRefactoring RmEqState
forall s (m :: * -> *). MonadState s m => m s
get

        -- Remove the destination from the equivalents
        let eqs' :: [Expression (Analysis A)]
eqs' = (Expression (Analysis A) -> Expression (Analysis A) -> Bool)
-> Expression (Analysis A)
-> [Expression (Analysis A)]
-> [Expression (Analysis A)]
forall a. (a -> a -> Bool) -> a -> [a] -> [a]
deleteBy (\ Expression (Analysis A)
x Expression (Analysis A)
y -> Expression (Analysis A) -> AnnotationFree (Expression (Analysis A))
forall t. t -> AnnotationFree t
af Expression (Analysis A)
x AnnotationFree (Expression (Analysis A))
-> AnnotationFree (Expression (Analysis A)) -> Bool
forall a. Eq a => a -> a -> Bool
== Expression (Analysis A) -> AnnotationFree (Expression (Analysis A))
forall t. t -> AnnotationFree t
af Expression (Analysis A)
y) Expression (Analysis A)
dstE [Expression (Analysis A)]
eqs

        -- Make copy statements
        let pos :: Position
pos = SrcSpan -> Position
afterAligned SrcSpan
sp
        let copies :: [Block (Analysis A)]
copies = (Expression (Analysis A) -> Block (Analysis A))
-> [Expression (Analysis A)] -> [Block (Analysis A)]
forall a b. (a -> b) -> [a] -> [b]
map (TypeEnv
-> Position
-> Expression (Analysis A)
-> Expression (Analysis A)
-> Block (Analysis A)
mkCopy TypeEnv
tenv Position
pos Expression (Analysis A)
dstE) [Expression (Analysis A)]
eqs'

        let (FU.Position Int
ao Int
c Int
l String
f Maybe (Int, String)
p) = Position
s1
            reportSpan :: Int -> SrcSpan
reportSpan Int
i =
              let pos' :: Position
pos' = Int -> Int -> Int -> String -> Maybe (Int, String) -> Position
FU.Position (Int
ao Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i) Int
c (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i) String
f Maybe (Int, String)
p
              in (Position -> Position -> SrcSpan
FU.SrcSpan Position
pos' Position
pos')

        [Int]
-> (Int -> StateT RmEqState EquivalenceRefactoring ())
-> StateT RmEqState EquivalenceRefactoring ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
n..(Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Block (Analysis A)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Block (Analysis A)]
copies Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)] ((Int -> StateT RmEqState EquivalenceRefactoring ())
 -> StateT RmEqState EquivalenceRefactoring ())
-> (Int -> StateT RmEqState EquivalenceRefactoring ())
-> StateT RmEqState EquivalenceRefactoring ()
forall a b. (a -> b) -> a -> b
$ \Int
i -> do
          Origin
origin <- SrcSpan -> StateT RmEqState EquivalenceRefactoring Origin
forall e w (m :: * -> *) a.
(MonadLogger e w m, Spanned a) =>
a -> m Origin
atSpanned (Int -> SrcSpan
reportSpan Int
i)
          Origin -> Text -> StateT RmEqState EquivalenceRefactoring ()
forall e w (m :: * -> *).
MonadLogger e w m =>
Origin -> Text -> m ()
logInfo Origin
origin (Text -> StateT RmEqState EquivalenceRefactoring ())
-> Text -> StateT RmEqState EquivalenceRefactoring ()
forall a b. (a -> b) -> a -> b
$ Text
"added copy due to refactored equivalence"

        -- Update refactoring state
        RmEqState -> StateT RmEqState EquivalenceRefactoring ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put ([[Expression (Analysis A)]]
equivs, Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Expression (Analysis A)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Expression (Analysis A)]
eqs')
        -- Sequence original assignment with new assignments
        [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Block (Analysis A)]
 -> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)])
-> [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
forall a b. (a -> b) -> a -> b
$ Block (Analysis A)
b Block (Analysis A) -> [Block (Analysis A)] -> [Block (Analysis A)]
forall a. a -> [a] -> [a]
: [Block (Analysis A)]
copies

addCopysPerBlock TypeEnv
tenv Block (Analysis A)
x = do
   Block (Analysis A)
x' <- ([Block (Analysis A)]
 -> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)])
-> Block (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Block (Analysis A))
forall from to (m :: * -> *).
(Biplate from to, Applicative m) =>
(to -> m to) -> from -> m from
descendBiM (TypeEnv
-> [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
addCopysPerBlockGroup TypeEnv
tenv) Block (Analysis A)
x
   [Block (Analysis A)]
-> StateT RmEqState EquivalenceRefactoring [Block (Analysis A)]
forall (m :: * -> *) a. Monad m => a -> m a
return [Block (Analysis A)
x']

-- see if two expressions have the same type
equalTypes :: FAT.TypeEnv -> F.Expression A1 -> F.Expression A1 -> Maybe FA.IDType
equalTypes :: TypeEnv
-> Expression (Analysis A)
-> Expression (Analysis A)
-> Maybe IDType
equalTypes TypeEnv
tenv Expression (Analysis A)
e Expression (Analysis A)
e' = do
    String
v1 <- Expression (Analysis A) -> Maybe String
forall a. Expression a -> Maybe String
extractVariable Expression (Analysis A)
e
    String
v2 <- Expression (Analysis A) -> Maybe String
forall a. Expression a -> Maybe String
extractVariable Expression (Analysis A)
e'
    IDType
t1 <- String -> TypeEnv -> Maybe IDType
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
v1 TypeEnv
tenv
    IDType
t2 <- String -> TypeEnv -> Maybe IDType
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
v2 TypeEnv
tenv
    if IDType
t1 IDType -> IDType -> Bool
forall a. Eq a => a -> a -> Bool
== IDType
t2 then IDType -> Maybe IDType
forall a. a -> Maybe a
Just IDType
t1 else Maybe IDType
forall a. Maybe a
Nothing

-- Create copy statements. Parameters:
--    * A type environment to find out if a type cast is needed
--    * A SrcPos where the copy statements are going to inserted at
--    * The source expression
--    * The number of copies to increment the line by
--           paired with the destination expression
mkCopy :: FAT.TypeEnv
       -> FU.Position
       -> F.Expression A1 -> F.Expression A1 -> F.Block A1
mkCopy :: TypeEnv
-> Position
-> Expression (Analysis A)
-> Expression (Analysis A)
-> Block (Analysis A)
mkCopy TypeEnv
tenv Position
pos Expression (Analysis A)
srcE Expression (Analysis A)
dstE = Block A -> Block (Analysis A)
forall (b :: * -> *) a. Functor b => b a -> b (Analysis a)
FA.initAnalysis (Block A -> Block (Analysis A)) -> Block A -> Block (Analysis A)
forall a b. (a -> b) -> a -> b
$
   A -> SrcSpan -> Maybe (Expression A) -> Statement A -> Block A
forall a.
a -> SrcSpan -> Maybe (Expression a) -> Statement a -> Block a
F.BlStatement A
a SrcSpan
sp Maybe (Expression A)
forall a. Maybe a
Nothing (Statement A -> Block A) -> Statement A -> Block A
forall a b. (a -> b) -> a -> b
$
     case TypeEnv
-> Expression (Analysis A)
-> Expression (Analysis A)
-> Maybe IDType
equalTypes TypeEnv
tenv Expression (Analysis A)
srcE Expression (Analysis A)
dstE of
       -- Types not equal, so create a transfer
       Maybe IDType
Nothing -> A -> SrcSpan -> Expression A -> Expression A -> Statement A
forall a.
a -> SrcSpan -> Expression a -> Expression a -> Statement a
F.StExpressionAssign A
a SrcSpan
sp Expression A
dstE' Expression A
call
                    where
                     call :: Expression A
call = A
-> SrcSpan
-> Expression A
-> Maybe (AList Argument A)
-> Expression A
forall a.
a
-> SrcSpan
-> Expression a
-> Maybe (AList Argument a)
-> Expression a
F.ExpFunctionCall A
a SrcSpan
sp Expression A
transf Maybe (AList Argument A)
argst
                     transf :: Expression A
transf = A -> SrcSpan -> Value A -> Expression A
forall a. a -> SrcSpan -> Value a -> Expression a
F.ExpValue A
a SrcSpan
sp (String -> Value A
forall a. String -> Value a
F.ValVariable String
"transfer")
                     argst :: Maybe (AList Argument A)
argst  = AList Argument A -> Maybe (AList Argument A)
forall a. a -> Maybe a
Just (A -> SrcSpan -> [Argument A] -> AList Argument A
forall (t :: * -> *) a. a -> SrcSpan -> [t a] -> AList t a
F.AList A
a SrcSpan
sp [Argument A]
args)
                     args :: [Argument A]
args   = (Expression A -> Argument A) -> [Expression A] -> [Argument A]
forall a b. (a -> b) -> [a] -> [b]
map (A -> SrcSpan -> Maybe String -> Expression A -> Argument A
forall a.
a -> SrcSpan -> Maybe String -> Expression a -> Argument a
F.Argument A
a SrcSpan
sp Maybe String
forall a. Maybe a
Nothing) [Expression A
srcE', Expression A
dstE']
       -- Types are equal, simple a assignment
       Just IDType
_ -> A -> SrcSpan -> Expression A -> Expression A -> Statement A
forall a.
a -> SrcSpan -> Expression a -> Expression a -> Statement a
F.StExpressionAssign A
a SrcSpan
sp Expression A
dstE' Expression A
srcE'
  where
     -- Set position to be at col = 0
     sp :: SrcSpan
sp   = Position -> Position -> SrcSpan
FU.SrcSpan (Position -> Position
toCol0 Position
pos) (Position -> Position
toCol0 Position
pos)
     -- But store the aligned position in refactored so
     -- that the reprint algorithm can add the appropriate indentation
     a :: A
a = A
unitAnnotation { refactored :: Maybe Position
refactored = Position -> Maybe Position
forall a. a -> Maybe a
Just Position
pos, newNode :: Bool
newNode = Bool
True }
     dstE' :: Expression A
dstE' = Expression (Analysis A) -> Expression A
forall (b :: * -> *) a. Functor b => b (Analysis a) -> b a
FA.stripAnalysis Expression (Analysis A)
dstE
     srcE' :: Expression A
srcE' = Expression (Analysis A) -> Expression A
forall (b :: * -> *) a. Functor b => b (Analysis a) -> b a
FA.stripAnalysis Expression (Analysis A)
srcE

perBlockRmEquiv :: F.Block A1 -> StateT RmEqState EquivalenceRefactoring (F.Block A1)
perBlockRmEquiv :: Block (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Block (Analysis A))
perBlockRmEquiv = (Statement (Analysis A)
 -> StateT
      RmEqState EquivalenceRefactoring (Statement (Analysis A)))
-> Block (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Block (Analysis A))
forall (m :: * -> *) from to.
(Monad m, Applicative m, Biplate from to) =>
(to -> m to) -> from -> m from
transformBiM Statement (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Statement (Analysis A))
perStatementRmEquiv

perStatementRmEquiv
  :: F.Statement A1
  -> StateT RmEqState EquivalenceRefactoring (F.Statement A1)
perStatementRmEquiv :: Statement (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Statement (Analysis A))
perStatementRmEquiv (F.StEquivalence Analysis A
a sp :: SrcSpan
sp@(FU.SrcSpan Position
spL Position
_) AList (AList Expression) (Analysis A)
equivs) = do
    ([[Expression (Analysis A)]]
ess, Int
n) <- StateT RmEqState EquivalenceRefactoring RmEqState
forall s (m :: * -> *). MonadState s m => m s
get

    let spL' :: SrcSpan
spL' = Position -> Position -> SrcSpan
FU.SrcSpan Position
spL Position
spL
    SrcSpan -> Text -> StateT RmEqState EquivalenceRefactoring ()
forall e w (m :: * -> *) a.
(MonadLogger e w m, Spanned a) =>
a -> Text -> m ()
logInfo' SrcSpan
spL' (Text -> StateT RmEqState EquivalenceRefactoring ())
-> Text -> StateT RmEqState EquivalenceRefactoring ()
forall a b. (a -> b) -> a -> b
$ Text
"removed equivalence"

    RmEqState -> StateT RmEqState EquivalenceRefactoring ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put ((((AList Expression (Analysis A) -> [Expression (Analysis A)])
-> [AList Expression (Analysis A)] -> [[Expression (Analysis A)]]
forall a b. (a -> b) -> [a] -> [b]
map AList Expression (Analysis A) -> [Expression (Analysis A)]
forall (t :: * -> *) a. AList t a -> [t a]
F.aStrip) ([AList Expression (Analysis A)] -> [[Expression (Analysis A)]])
-> (AList (AList Expression) (Analysis A)
    -> [AList Expression (Analysis A)])
-> AList (AList Expression) (Analysis A)
-> [[Expression (Analysis A)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AList (AList Expression) (Analysis A)
-> [AList Expression (Analysis A)]
forall (t :: * -> *) a. AList t a -> [t a]
F.aStrip (AList (AList Expression) (Analysis A)
 -> [[Expression (Analysis A)]])
-> AList (AList Expression) (Analysis A)
-> [[Expression (Analysis A)]]
forall a b. (a -> b) -> a -> b
$ AList (AList Expression) (Analysis A)
equivs) [[Expression (Analysis A)]]
-> [[Expression (Analysis A)]] -> [[Expression (Analysis A)]]
forall a. [a] -> [a] -> [a]
++ [[Expression (Analysis A)]]
ess, Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
    let a' :: Analysis A
a' = (A -> A) -> Analysis A -> Analysis A
forall a. (a -> a) -> Analysis a -> Analysis a
onPrev (\A
ap -> A
ap {refactored :: Maybe Position
refactored = Position -> Maybe Position
forall a. a -> Maybe a
Just Position
spL, deleteNode :: Bool
deleteNode = Bool
True}) Analysis A
a
    Statement (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Statement (Analysis A))
forall (m :: * -> *) a. Monad m => a -> m a
return (Analysis A
-> SrcSpan
-> AList (AList Expression) (Analysis A)
-> Statement (Analysis A)
forall a. a -> SrcSpan -> AList (AList Expression) a -> Statement a
F.StEquivalence Analysis A
a' (SrcSpan -> SrcSpan
deleteLine SrcSpan
sp) AList (AList Expression) (Analysis A)
equivs)
perStatementRmEquiv Statement (Analysis A)
f = Statement (Analysis A)
-> StateT RmEqState EquivalenceRefactoring (Statement (Analysis A))
forall (m :: * -> *) a. Monad m => a -> m a
return Statement (Analysis A)
f

-- 'equivalents e' returns a list of variables/memory cells
-- that have been equivalenced with "e".
equivalentsToExpr
  :: F.Expression A1
  -> StateT RmEqState EquivalenceRefactoring [F.Expression A1]
equivalentsToExpr :: Expression (Analysis A)
-> StateT
     RmEqState EquivalenceRefactoring [Expression (Analysis A)]
equivalentsToExpr Expression (Analysis A)
y = do
    ([[Expression (Analysis A)]]
equivs, Int
_) <- StateT RmEqState EquivalenceRefactoring RmEqState
forall s (m :: * -> *). MonadState s m => m s
get
    [Expression (Analysis A)]
-> StateT
     RmEqState EquivalenceRefactoring [Expression (Analysis A)]
forall (m :: * -> *) a. Monad m => a -> m a
return (Expression (Analysis A)
-> [[Expression (Analysis A)]] -> [Expression (Analysis A)]
forall t. Eq (AnnotationFree t) => t -> [[t]] -> [t]
inGroup Expression (Analysis A)
y [[Expression (Analysis A)]]
equivs)
  where
    inGroup :: t -> [[t]] -> [t]
inGroup t
_ [] = []
    inGroup t
x ([t]
xs:[[t]]
xss) =
        if t -> AnnotationFree t
forall t. t -> AnnotationFree t
AnnotationFree t
x AnnotationFree t -> [AnnotationFree t] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (t -> AnnotationFree t) -> [t] -> [AnnotationFree t]
forall a b. (a -> b) -> [a] -> [b]
map t -> AnnotationFree t
forall t. t -> AnnotationFree t
AnnotationFree [t]
xs
        then [t]
xs
        else t -> [[t]] -> [t]
inGroup t
x [[t]]
xss