module InRL where

import InSRL
import AbsSRL
import AbsRL hiding (RL,Rlblk,Exp(..),Step(..),Ident(..))
import qualified AbsRL as R (RL,Rlblk,Exp(..),Step(..),Ident(..))
import Control.Monad.State

-- |ラベルを表示する関数
label :: Int -> R.Ident
label n = R.Ident ('l' : show n)

-- |識別子を変換する関数
transId (Ident x) = (R.Ident x)

-- |ExpをAbsSRL.ExpからAbsRL.Expへ変換する関数
transExp :: Exp -> R.Exp
transExp (Etop e) = R.Etop (transExp e)
transExp (Eempty e) = R.Eempty (transExp e)
transExp (Exor e1 e2) = R.Exor (transExp e1) (transExp e2)
transExp (Eeq e1 e2) = R.Eeq (transExp e1) (transExp e2)
transExp (Ene e1 e2) = R.Ene (transExp e1) (transExp e2)
transExp (Elt e1 e2) = R.Elt (transExp e1) (transExp e2)
transExp (Egt e1 e2) = R.Egt (transExp e1) (transExp e2)
transExp (Ele e1 e2) = R.Ele (transExp e1) (transExp e2)
transExp (Ege e1 e2) = R.Ege (transExp e1) (transExp e2)
transExp (Eadd e1 e2) = R.Eadd (transExp e1) (transExp e2)
transExp (Emin e1 e2) = R.Emin (transExp e1) (transExp e2)
transExp (Emul e1 e2) = R.Emul (transExp e1) (transExp e2)
transExp (Ediv e1 e2) = R.Ediv (transExp e1) (transExp e2)
transExp (Earr e1 e2) = R.Earr (transExp e1) (transExp e2)
transExp (Econ n) = R.Econ n
transExp (Evar x) = R.Evar (transId x)

-- |StepをAbsSRL.StepからAbsRL.Stepへ変換する関数
transStep :: Step -> R.Step
transStep (SasnAdd x e) = R.SasnAdd (transId x) (transExp e)
transStep (SasnMin x e) = R.SasnMin (transId x) (transExp e)
transStep (SasnXor x e) = R.SasnXor (transId x) (transExp e)
transStep (SasnArrAdd x e1 e2) = R.SasnArrAdd (transId x) (transExp e1) (transExp e2)
transStep (SasnArrMin x e1 e2) = R.SasnArrMin (transId x) (transExp e1) (transExp e2)
transStep (SasnArrXor x e1 e2) = R.SasnArrXor (transId x) (transExp e1) (transExp e2)
transStep (Spush x y) = R.Spush (transId x) (transId y)
transStep (Spop x y) = R.Spop (transId x) (transId y)
transStep Sskip = R.Sskip

-- |状態を受け取って値と次の状態を返す型
type NameM = State Int

-- |stateモナドを使用して適切なラベルを返す関数
fresh :: NameM R.Ident
fresh = state (\st -> (label st,st+1))

-- |labelの初期値
initState = 0

-- |SRL文から翻訳されたRL文を表示する関数
inRL p = runState (inRL2 p) initState

-- |SRL文をRL Inverterに翻訳し、関数inRLへ返す関数
inRL2 :: SRL -> NameM R.RL
inRL2 (ESRL b) = do
  l0 <- fresh; l1 <- fresh; l2 <- fresh; l3 <- fresh
  body <- srlcompInv (map srlInv b) l0 l1 l2 l3
  return $
    ERL ([Brlblk l0 Fentry [] (Jgoto l1)] ++
         body ++
         [Brlblk l3 (Ffrom l2) [] Jexit])

-- |受け取ったリストの要素が1つならば、関数srl2rlInvへ、2つ以上ならば関数conInvへ値を渡す関数
srlcompInv :: [Blk] -> R.Ident -> R.Ident -> R.Ident -> R.Ident -> NameM [R.Rlblk]
srlcompInv []     l0 l1 l4 l5 = return []
srlcompInv (x:xs) l0 l1 l4 l5 = do
  l2 <- fresh; l3 <- fresh
  list1 <- srl2rlInv x l0 l1 l2 l3
  list2 <- srlcompInv xs l2 l3 l4 l5
  return $ list1 ++ list2

-- |受けとったリストの要素がif文、from文、step文のどれなのかを判別し、文の種類に応じて適切にRL Inverter文に翻訳する関数
srl2rlInv :: Blk -> R.Ident -> R.Ident -> R.Ident -> R.Ident -> NameM [R.Rlblk]
srl2rlInv (Bstep c)  l0 l1 l2 l3 = return                                        --step文
                                [Brlblk l1 (Ffrom l0) [transStep c] (Jgoto l2),
                                 Brlblk l2 (Ffrom l1) [] (Jgoto l3)]
srl2rlInv (Bif ea ba bb eb)  l0 l1 l6 l7 = do                                    --if文
  l2 <- fresh; l3 <- fresh; l4 <- fresh; l5 <- fresh
  list1 <- srlcompInv ba l1 l2 l3 l6
  list2 <- srlcompInv bb l1 l4 l5 l6
  return $
    [Brlblk l1 (Ffrom l0) [] (Jif (transExp ea) l2 l4),
     Brlblk l6 (Ffi (transExp eb) l3 l5) [] (Jgoto l7)] ++
    list1 ++ list2
srl2rlInv (Bfrom ea ba bb eb)  l0 l1 l4 l7 = do                                  --from文
  l2 <- fresh; l3 <- fresh; l5 <- fresh; l6 <- fresh
  list1 <- srlcompInv ba l1 l2 l3 l4
  list2 <- srlcompInv bb l4 l5 l6 l1
  return $
    [Brlblk l1 (Ffi (transExp ea) l0 l6) [] (Jgoto l2),
     Brlblk l4 (Ffrom l3) [] (Jif (transExp eb) l7 l5)] ++
    list1 ++ list2
