{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Rank2Types #-}
module Synthesizer.LLVM.Causal.ProcessValue (
   Causal.T,
   mapAccum,
   fromModifier,
   ) where

import qualified Synthesizer.LLVM.Causal.Private as Causal

import qualified Synthesizer.LLVM.Value as Value

import qualified Synthesizer.Plain.Modifier as Modifier

import qualified LLVM.Extra.MaybeContinuation as MaybeCont
import qualified LLVM.Extra.Memory as Memory

import qualified LLVM.Core as LLVM

import Control.Monad.Trans.State (runState)



mapAccum ::
   (Memory.C state) =>
   (forall r. a -> state -> LLVM.CodeGenFunction r (b, state)) ->
   (forall r. LLVM.CodeGenFunction r state) ->
   Causal.T a b
mapAccum next = Causal.simple (\a s -> MaybeCont.lift $ next a s)

fromModifier ::
   (Value.Flatten ah, Value.Registers ah ~ al,
    Value.Flatten bh, Value.Registers bh ~ bl,
    Value.Flatten ch, Value.Registers ch ~ cl,
    Value.Flatten sh, Value.Registers sh ~ sl,
    Memory.C sl) =>
   Modifier.Simple sh ch ah bh -> Causal.T (cl,al) bl
fromModifier (Modifier.Simple initial step) =
   mapAccum
      (\(c,a) s ->
         Value.flatten $
         runState
            (step (Value.unfold c) (Value.unfold a))
            (Value.unfold s))
      (Value.flatten initial)