module Camfort.Traverse where
import Camfort.Analysis.Annotations
import Language.Fortran
import Generics.Deriving.Base
import Generics.Deriving.Copoint
import GHC.Generics
import Control.Monad.Trans.Writer.Lazy
import Data.Generics.Zipper
import Data.Generics.Aliases
import Data.Generics.Str
import Data.Generics.Uniplate.Operations
import Language.Fortran.Lexer
import Control.Comonad
import Data.Data
import Data.Maybe
import Data.Monoid
import Debug.Trace
#if __GLASGOW_HASKELL__ < 800
instance Monoid x => Monad ((,) x) where
return a = (mempty, a)
(x, a) >>= k = let (x', b) = k a
in (mappend x x', b)
#endif
extendBi :: (Biplate (from a) (to a), RComonad to) => (to a -> a) -> (from a) -> (from a)
extendBi f x = case biplate x of
(current, generate) -> generate $ strMap (rextend f) current
reduceCollect :: (Data s, Data t, Uniplate t, Biplate t s) => (s -> Maybe a) -> t -> [a]
reduceCollect k x = execWriter (transformBiM (\y -> do case k y of
Just x -> tell [x]
Nothing -> return ()
return y) x)
everywhere :: (Zipper a -> Zipper a) -> Zipper a -> Zipper a
everywhere k z = let everywhere' = enterRight . enterDown . k
enterDown z = case (down' z) of
Just dz -> let dz' = everywhere' dz
in case (up $ dz') of
Just uz -> uz
Nothing -> dz'
Nothing -> z
enterRight z = case (right z) of
Just rz -> let rz' = everywhere' rz
in case (left $ rz') of
Just lz -> lz
Nothing -> rz'
Nothing -> z
in everywhere' z
zfmap :: Data a => (a -> a) -> Zipper (d a) -> Zipper (d a)
zfmap f x = zeverywhere (mkT f) x
extendBi' :: (Biplate (from a) (to a), Comonad to) => (to a -> a) -> (from a) -> (from a)
extendBi' f x = case biplate x of
(current, generate) -> generate $ strMap (extend f) current
class RComonad t where
rextract :: t a -> a
rextend :: (t a -> a) -> t a -> t a
class RFunctor t where
rfmap :: (a -> a) -> t a -> t a
instance RComonad Fortran where
rextract x = tag x
rextend k y@(Assg _ sp e1 e2) = Assg (k y) sp e1 e2
rextend k y@(For _ sp v e1 e2 e3 fs) = For (k y) sp v e1 e2 e3 (rextend k fs)
rextend k y@(FSeq _ sp f1 f2) = FSeq (k y) sp (rextend k f1) (rextend k f2)
rextend k y@(If _ sp e f1 fes f3) = let fes' = map (\(e, f) -> (e, rextend k f)) fes
f3' = case f3 of
Nothing -> Nothing
Just f3a -> Just (rextend k f3a)
in If (k y) sp e (rextend k f1) fes' f3'
rextend k y@(Allocate _ sp e1 e2) = Allocate (k y) sp e1 e2
rextend k y@(Backspace _ sp sp') = Backspace (k y) sp sp'
rextend k y@(Call _ sp e as) = Call (k y) sp e as
rextend k y@(Open _ sp s) = Open (k y) sp s
rextend k y@(Close _ sp s) = Close (k y) sp s
rextend k y@(Continue _ sp) = Continue (k y) sp
rextend k y@(Cycle _ sp s) = Cycle (k y) sp s
rextend k y@(Deallocate _ sp es e) = Deallocate (k y) sp es e
rextend k y@(Endfile _ sp s) = Endfile (k y) sp s
rextend k y@(Exit _ sp s) = Exit (k y) sp s
rextend k y@(Forall _ sp es f) = Forall (k y) sp es (rextend k f)
rextend k y@(Goto _ sp s) = Goto (k y) sp s
rextend k y@(Nullify _ sp e) = Nullify (k y) sp e
rextend k y@(Inquire _ sp s e) = Inquire (k y) sp s e
rextend k y@(Rewind _ sp s) = Rewind (k y) sp s
rextend k y@(Stop _ sp e) = Stop (k y) sp e
rextend k y@(Where _ sp e f Nothing) = Where (k y) sp e (rextend k f) Nothing
rextend k y@(Where _ sp e f (Just f')) = Where (k y) sp e (rextend k f) (Just (rextend k f'))
rextend k y@(Write _ sp s e) = Write (k y) sp s e
rextend k y@(PointerAssg _ sp e1 e2) = PointerAssg (k y) sp e1 e2
rextend k y@(Return _ sp e) = Return (k y) sp e
rextend k y@(Label _ sp s f) = Label (k y) sp s (rextend k f)
rextend k y@(Print _ sp e es) = Print (k y) sp e es
rextend k y@(ReadS _ sp s e) = ReadS (k y) sp s e
rextend k y@(TextStmt _ sp s) = TextStmt (k y) sp s
rextend k y@(NullStmt _ sp) = NullStmt (k y) sp
class Refill d where
refill :: d a -> a -> d a
instance Refill Fortran where
refill y@(Assg _ sp e1 e2) a = Assg a sp e1 e2
refill y@(For _ sp v e1 e2 e3 fs) a = For a sp v e1 e2 e3 fs
refill y@(DoWhile _ sp e f) a = DoWhile a sp e f
refill y@(FSeq _ sp f1 f2) a = FSeq a sp f1 f2
refill y@(If _ sp e f1 fes f3) a = If a sp e f1 fes f3
refill y@(Allocate _ sp e1 e2) a = Allocate a sp e1 e2
refill y@(Backspace _ sp sp') a = Backspace a sp sp'
refill y@(Call _ sp e as) a = Call a sp e as
refill y@(Open _ sp s) a = Open a sp s
refill y@(Close _ sp s) a = Close a sp s
refill y@(Continue _ sp) a = Continue a sp
refill y@(Cycle _ sp s) a = Cycle a sp s
refill y@(DataStmt _ sp p) a = DataStmt a sp p
refill y@(Deallocate _ sp es e) a = Deallocate a sp es e
refill y@(Endfile _ sp s) a = Endfile a sp s
refill y@(Exit _ sp s) a = Exit a sp s
refill y@(Forall _ sp es f) a = Forall a sp es f
refill y@(Format _ sp s) a = Format a sp s
refill y@(Goto _ sp s) a = Goto a sp s
refill y@(Nullify _ sp e) a = Nullify a sp e
refill y@(Inquire _ sp s e) a = Inquire a sp s e
refill y@(Pause _ sp s) a = Pause a sp s
refill y@(Rewind _ sp s) a = Rewind a sp s
refill y@(Stop _ sp e) a = Stop a sp e
refill y@(Where _ sp e f f') a = Where a sp e f f'
refill y@(Write _ sp s e) a = Write a sp s e
refill y@(PointerAssg _ sp e1 e2) a = PointerAssg a sp e1 e2
refill y@(Return _ sp e) a = Return a sp e
refill y@(Label _ sp s f) a = Label a sp s f
refill y@(Print _ sp e es) a = Print a sp e es
refill y@(ReadS _ sp s e) a = ReadS a sp s e
refill y@(TextStmt _ sp s) a = TextStmt a sp s
refill y@(NullStmt _ sp) a = NullStmt a sp
annotation :: Tagged g => g a -> a
annotation = tag