packages feed

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

{-# LANGUAGE TypeFamilies #-}

module Descript.BasicInj.Process.Refactor.RefactorReduce
  ( refactorReduce
  ) where

import Descript.BasicInj.Process.Reduce.SrcAnn
import qualified Descript.BasicInj.Traverse.Term as T
import Descript.BasicInj.Process.Validate
import Descript.BasicInj.Traverse
import qualified Descript.BasicInj.Data.Value.In as In
import qualified Descript.BasicInj.Data.Value.Out as Out
import Descript.BasicInj.Data
import Descript.Misc
import Data.Semigroup as S
import Data.Monoid as M
import Data.Functor.Identity
import Core.Control.Monad.Trans
import Control.Monad.Trans.Writer.Strict

data RefactorReduce = RefactorReduce (PhaseCtx ())

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

  tonTerm T.PhaseCtx (RefactorReduce phase) = pure . reducePhase phase
  tonTerm T.RegValue (RefactorReduce phase) = pure . reduceReg phase
  tonTerm _ _ = pure

-- | Replaces the left (input) value with the right (output) within
-- every value in the source, including reducers.
refactorReduce :: DirtyDep SrcAnn
               -> In.Value SrcAnn
               -> Out.Value SrcAnn
               -> RefactorFunc Source
refactorReduce dextra old new x = do
  validateForRefactor $ Depd dextra x -- Handles dependency errors
  -- Ignores dependency errors, already handled
  validateForRefactorIn T.Reducer fullMod reducer
  rehoist $ refactorReduce' T.Source (PhaseCtx () [reducer_]) x
  where reducer = Reducer (getAnn old S.<> getAnn new) old new
        reducer_ = remAnns reducer
        fullMod = sourceAModule_ x M.<> dirtyVal dextra

-- | Applies the reducer to every value in the node, including other
-- reducers (it's a macro reducer).
refactorReduce' :: TTerm t -> PhaseCtx () -> RefactorFunc t
refactorReduce' term phase = travTerm term $ RefactorReduce phase