module Camfort.Reprint where
import Data.Generics.Zipper
import Camfort.PrettyPrint
import Camfort.Analysis.Annotations
import Camfort.Helpers
import Camfort.Traverse
import qualified Data.ByteString.Char8 as B
import Data.Functor.Identity
import Data.Data
import Control.Monad.Trans.State.Lazy
import Language.Fortran
import Camfort.Analysis.Syntax
reprint :: (Data (p Annotation), PrettyPrint (p Annotation))
=> (forall a . Typeable a => [String] -> SrcLoc -> a -> State Int (String, SrcLoc, Bool))
-> SourceText -> Filename -> p Annotation -> String
reprint refactoring input f p
| B.null input = prettyPrint p
| otherwise =
pn ++ pe
where input' = map B.unpack $ B.lines input
len = Prelude.length input'
start = SrcLoc f 1 0
end = SrcLoc f len (1 + (Prelude.length $ Prelude.last input'))
(pn, cursorn) = evalState (reprintC refactoring start input' (toZipper p)) 0
(_, inpn) = takeBounds (start, cursorn) input'
(pe, _) = takeBounds (cursorn, end) inpn
reprintC :: (forall b . (Typeable b) => [String] -> SrcLoc -> b -> State Int (String, SrcLoc, Bool))
-> SrcLoc -> [String] -> Zipper a -> State Int (String, SrcLoc)
reprintC refactoring cursor inp z = do
(p1, cursor', flag) <- query (refactoring inp cursor) z
(_, inp') <- return $ takeBounds (cursor, cursor') inp
(p2, cursor'') <- if flag then return ("", cursor')
else enterDown refactoring cursor' inp' z
(_, inp'') <- return $ takeBounds (cursor', cursor'') inp'
(p3, cursor''') <- enterRight refactoring cursor'' inp'' z
return (p1 ++ p2 ++ p3, cursor''')
enterDown, enterRight ::
(forall b . (Typeable b) => [String] -> SrcLoc -> b -> State Int (String, SrcLoc, Bool))
-> SrcLoc -> [String] -> Zipper a -> State Int (String, SrcLoc)
enterDown refactoring cursor inp z = case (down' z) of
Just dz -> reprintC refactoring cursor inp dz
Nothing -> return $ ("", cursor)
enterRight refactoring cursor inp z = case (right z) of
Just rz -> reprintC refactoring cursor inp rz
Nothing -> return $ ("", cursor)
takeBounds (l, u) inp = takeBounds' (lineCol l, lineCol u) [] inp
takeBounds' ((ll, lc), (ul, uc)) tk inp =
if (ll == ul && lc == uc) || (ll > ul) then (Prelude.reverse tk, inp)
else case inp of [] -> (Prelude.reverse tk, inp)
([]:[]) -> (Prelude.reverse tk, inp)
([]:ys) -> takeBounds' ((ll+1, 0), (ul, uc)) ('\n':tk) ys
((x:xs):ys) -> takeBounds' ((ll, lc+1), (ul, uc)) (x:tk) (xs:ys)