packages feed

descript-lang-0.2.0.0: src/Descript/BasicInj/Process/Refactor/RenameModuleElem.hs

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ApplicativeDo #-}

module Descript.BasicInj.Process.Refactor.RenameModuleElem
  ( renameModuleElem
  , renameModuleElem'
  ) where

import Descript.BasicInj.Process.Refactor.GenRenameSymbol
import qualified Descript.BasicInj.Traverse.Term as T
import Descript.BasicInj.Traverse
import Descript.BasicInj.Data
import Descript.Misc
import Data.Functor.Identity
import Core.Data.List
import qualified Data.List.NonEmpty as NonEmpty
import Control.Monad.Trans.Writer.Strict

data RenameModuleElem = RenameModuleElem [Symbol ()] (GenRenameSymbol Symbol)

instance Traversal RenameModuleElem where
  type Eff RenameModuleElem = ResultT RefactorError (WriterT [RefactorWarning] Identity)
  type TAnn RenameModuleElem = SrcAnn

  tonTerm T.ModulePath (RenameModuleElem prevs rsym) x@(ModulePath ann es)
    = case splitPrefixBy (=@=) prevs $ NonEmpty.toList es of
           Nothing -> pure x
           Just (_, []) -> pure x
           Just (fes, (targ : res)) -> do
             targ' <- renameSymbol rsym targ
             pure $ ModulePath ann $ NonEmpty.fromList $ fes ++ targ' : res
  tonTerm _ _ x = pure x

-- | Replaces every occurrence of the first import element immediately
-- after the previous elements with the second.
renameModuleElem :: [String] -> String -> String -> RefactorFunc Source
renameModuleElem prevs old new
  = renameModuleElem' T.Source (map (Symbol ()) prevs) (Symbol () old) (Symbol () new)

-- | Replaces every occurrence of the first import element immediately
-- after the previous elements with the second.
renameModuleElem' :: TTerm t
                  -> [Symbol ()]
                  -> Symbol ()
                  -> Symbol ()
                  -> RefactorFunc t
renameModuleElem' term prevs old new
  = travTerm term $ RenameModuleElem prevs $ GenRenameSymbol old new