{-# OPTIONS --rewriting #-}
module Reflect4a where

import DSK
import CPS
open import CPS-DSK

open import Data.Unit
open import Data.Empty
open import Data.Product
open import Function
open import Relation.Binary.PropositionalEquality

-- substitution lemma

mutual
  -- v₁[x:=v] = v₂
  lemma-SubstV : {var : Set} 
                 {v₁ : var  CPS.value[ var ]} 
                 {v  : CPS.value[ var ]} 
                 {v₂ : CPS.value[ var ]} 
                 CPS.SubstV v₁ v v₂ 
                 DSK.SubstV {var}  x  dskV (v₁ x)) (dskV v) (dskV v₂)
  lemma-SubstV CPS.sVar= = DSK.sVar=
  lemma-SubstV CPS.sVar≠ = DSK.sVar≠
  lemma-SubstV CPS.sNum = DSK.sNum
  lemma-SubstV CPS.sBol = DSK.sBol
  lemma-SubstV (CPS.sFun sub) = DSK.sFun  x  lemma-Subst (sub x))
  lemma-SubstV CPS.sShift = DSK.sShift
  lemma-SubstV CPS.sShift0 = DSK.sShift0

  -- e₁[x:=v] = e₂
  lemma-Subst : {var : Set} {Δ : CPS.Delta} 
                {e₁ : var  CPS.term[ var , Δ ]} 
                {v  : CPS.value[ var ]} 
                {e₂ : CPS.term[ var , Δ ]} 
                CPS.Subst e₁ v e₂ 
                DSK.Subst {var}  x  dskE (e₁ x)) (dskV v) (dskE e₂)
  lemma-Subst (CPS.sVal ΔΘ sub-c sub-v sub-m) =
    DSK.sVal (dskΔΘ ΔΘ) (lemma-SubstC sub-c)
             (lemma-SubstV sub-v) (lemma-SubstM sub-m)
  lemma-Subst (CPS.sApp ΔΘ sub-v₁ sub-v₂ sub-c sub-m) =
    DSK.sApp (dskΔΘ ΔΘ) (lemma-SubstV sub-v₁) (lemma-SubstV sub-v₂)
             (lemma-SubstC sub-c) (lemma-SubstM sub-m)

  -- c₁[x:=v] = c₂
  lemma-SubstC : {var : Set} {Δ : CPS.Delta} 
                 {c₁ : var  CPS.cont[ var , Δ ]} 
                 {v  : CPS.value[ var ]} 
                 {c₂ : CPS.cont[ var , Δ ]} 
                 CPS.SubstC c₁ v c₂ 
                 DSK.SubstC {var}  x  dskC (c₁ x)) (dskV v) (dskC c₂)
  lemma-SubstC CPS.sKVar≠ = DSK.sKVar≠
  lemma-SubstC CPS.sKId = DSK.sKId
  lemma-SubstC (CPS.sKLet sub) = DSK.sKLet  x  lemma-Subst (sub x))

  -- m₁[x:=v] = m₂
  lemma-SubstM : {var : Set} {Θ : CPS.Theta} 
                 {m₁ : var  CPS.mcont[ var , Θ ]} 
                 {v  : CPS.value[ var ]} 
                 {m₂ : CPS.mcont[ var , Θ ]} 
                 CPS.SubstM m₁ v m₂ 
                 DSK.SubstM {var}  x  dskM (m₁ x)) (dskV v) (dskM m₂)
  lemma-SubstM CPS.sGVar≠ = DSK.sGVar≠
  lemma-SubstM (CPS.sGCons ΔΘ sub-c sub-m) =
    DSK.sGCons (dskΔΘ ΔΘ) (lemma-SubstC sub-c) (lemma-SubstM sub-m)

mutual
  -- e₁[k:=c] = e₂
  lemma-CSubst : {var : Set} {Δ : CPS.Delta}
                 {e₁ : CPS.term[ var , CPS.K ]} 
                 {c  : CPS.cont[ var , Δ ]} 
                 {e₂ : CPS.term[ var , Δ ]} 
                 CPS.CSubst e₁ c e₂ 
                 DSK.CSubst {var} (dskE e₁) (dskC c) (dskE e₂)
  lemma-CSubst (CPS.sVal₁ csub-c) = DSK.sVal₁ (lemma-CSubstC csub-c)
  lemma-CSubst (CPS.sVal₂ csub-m) = DSK.sVal₂ (lemma-CSubstM csub-m)
  lemma-CSubst (CPS.sApp₁ csub-c) = DSK.sApp₁ (lemma-CSubstC csub-c)
  lemma-CSubst (CPS.sApp₂ csub-m) = DSK.sApp₂ (lemma-CSubstM csub-m)

  -- c₁[k:=c] = c₂
  lemma-CSubstC : {var : Set} {Δ : CPS.Delta}
                  {c₁ : CPS.cont[ var , CPS.K ]} 
                  {c  : CPS.cont[ var , Δ ]} 
                  {c₂ : CPS.cont[ var , Δ ]} 
                  CPS.CSubstC c₁ c c₂ 
                  DSK.CSubstC {var} (dskC c₁) (dskC c) (dskC c₂)
  lemma-CSubstC CPS.sKVar= = DSK.sKVar=
  lemma-CSubstC (CPS.sKLet₂ csub) = DSK.sKLet₂  x  lemma-CSubst (csub x))

  -- m₁[k:=c] = m₂
  lemma-CSubstM : {var : Set} {Δ : CPS.Delta}
                  {m₁ : CPS.mcont[ var , CPS.D CPS.K ]} 
                  {c  : CPS.cont[ var , Δ ]} 
                  {m₂ : CPS.mcont[ var , CPS.D Δ ]} 
                  CPS.CSubstM m₁ c m₂ 
                  DSK.CSubstM {var} (dskM m₁) (dskC c) (dskM m₂)
  lemma-CSubstM (CPS.sGCons₁ csub-c) = DSK.sGCons₁ (lemma-CSubstC csub-c)
  lemma-CSubstM (CPS.sGCons₂ csub-m) = DSK.sGCons₂ (lemma-CSubstM csub-m)

mutual
  -- e₁[g:=m] = e₂
  lemma-MSubst : {var : Set} {Δ Δ' : CPS.Delta} {Θ : CPS.Theta}
                 {e₁ : CPS.term[ var , Δ ]} 
                 {m  : CPS.mcont[ var , Θ ]} 
                 {e₂ : CPS.term[ var , Δ' ]} 
                 (eq : Δ'  Δ CPS.++ Θ) 
                 CPS.MSubst e₁ m eq e₂ 
                 DSK.MSubst {var} (dskE e₁) (dskM m) (cong dskΔ eq) (dskE e₂)
  lemma-MSubst eq (CPS.sVal ΔΘ ΔΘ' msub-m) =
    DSK.sVal (dskΔΘ ΔΘ) (dskΔΘ ΔΘ') (lemma-MSubstM msub-m)
  lemma-MSubst eq (CPS.sApp ΔΘ ΔΘ' v w c m₁ msub-m) =
    DSK.sApp (dskΔΘ ΔΘ) (dskΔΘ ΔΘ') (dskV v) (dskV w) (dskC c) (dskM m₁)
             (lemma-MSubstM msub-m)
             
  -- m₁[g:=m] = m₂
  lemma-MSubstM : {var : Set} {Θ Θ' : CPS.Theta} 
                  {m₁ : CPS.mcont[ var , Θ' ]} 
                  {m  : CPS.mcont[ var , Θ ]} 
                  {m₂ : CPS.mcont[ var , Θ' CPS.+++ Θ ]} 
                  CPS.MSubstM m₁ m refl m₂ 
                  DSK.MSubstM {var} (dskM m₁) (dskM m) refl (dskM m₂)
  lemma-MSubstM CPS.mGVar= = DSK.mGVar=
  lemma-MSubstM (CPS.mGCons ΔΘ' ΔΘ msub-m) =
    DSK.mGCons (dskΔΘ ΔΘ') (dskΔΘ ΔΘ) (lemma-MSubstM msub-m)


-- main theorem
mutual
  -- CPSの値 v,w について v→w ならば、v♮ → w♮
  correctV : {var : Set} 
             {v w : CPS.value[ var ]} 
             CPS.ReduceV v w 
             DSK.ReduceV {var} (dskV v) (dskV w)
  correctV CPS.REtaV = DSK.REtaV
  correctV (CPS.RFun red) = DSK.RFun λ x  correctE (red x)
  correctV CPS.RId = DSK.RId
  correctV (CPS.RTrans red-v₁ red-v₂) =
    DSK.RTrans (correctV red-v₁) (correctV red-v₂)

  -- CPS項 e,e' について e→e' ならば、e# → e'#
  correctE : {var : Set} {Δ : CPS.Delta} 
             {e e' : CPS.term[ var , Δ ]} 
             CPS.Reduce e e' 
             DSK.Reduce {var} (dskE e) (dskE e')
  correctE (CPS.RBetaV ΔΘ sub csub msub) =
    DSK.RBetaV (dskΔΘ ΔΘ) 
               (lemma-Subst sub) (lemma-CSubst csub) (lemma-MSubst refl msub)
  correctE (CPS.RBetaLet ΔΘ sub msub) =
    DSK.RBetaLet (dskΔΘ ΔΘ) (lemma-Subst sub) (lemma-MSubst refl msub)
  correctE CPS.RShift = DSK.RShift
  correctE (CPS.RShift0 ΔΘ) = DSK.RShift0 (dskΔΘ ΔΘ)
  correctE (CPS.RReset ΔΘ) = DSK.RReset (dskΔΘ ΔΘ)
  correctE (CPS.RVal₁ ΔΘ red-c) = DSK.RVal₁ (dskΔΘ ΔΘ) (correctC red-c)
  correctE (CPS.RVal₂ ΔΘ red-v) = DSK.RVal₂ (dskΔΘ ΔΘ) (correctV red-v)
  correctE (CPS.RVal₃ ΔΘ red-m) = DSK.RVal₃ (dskΔΘ ΔΘ) (correctM red-m)
  correctE (CPS.RApp₁ ΔΘ red-v) = DSK.RApp₁ (dskΔΘ ΔΘ) (correctV red-v)
  correctE (CPS.RApp₂ ΔΘ red-v) = DSK.RApp₂ (dskΔΘ ΔΘ) (correctV red-v)
  correctE (CPS.RApp₃ ΔΘ red-c) = DSK.RApp₃ (dskΔΘ ΔΘ) (correctC red-c)
  correctE (CPS.RApp₄ ΔΘ red-m) = DSK.RApp₄ (dskΔΘ ΔΘ) (correctM red-m)
  correctE CPS.RId = DSK.RId
  correctE (CPS.RTrans red₁ red₂) = 
    DSK.RTrans (correctE red₁) (correctE red₂)

  -- CPSの継続 c,c' について c→c' ならば、c♭ → c'♭
  correctC : {var : Set} {Δ : CPS.Delta} 
             {c c' : CPS.cont[ var , Δ ]} 
             CPS.ReduceC c c' 
             DSK.ReduceC {var} (dskC c) (dskC c')
  correctC CPS.REtaLet = DSK.REtaLet
  correctC (CPS.RKLet red) = DSK.RKLet  x  correctE (red x))
  correctC CPS.RId = DSK.RId
  correctC (CPS.RTrans red-c₁ red-c₂) = 
    DSK.RTrans (correctC red-c₁) (correctC red-c₂)

  -- CPSのメタ継続 m,m' について m→m' ならば、m♭♭ → m'♭♭
  correctM : {var : Set} {Θ : CPS.Theta} 
             {m m' : CPS.mcont[ var , Θ ]} 
             CPS.ReduceM m m' 
             DSK.ReduceM {var} (dskM m) (dskM m')
  correctM (CPS.RGCons₁ ΔΘ red-c) = DSK.RGCons₁ (dskΔΘ ΔΘ) (correctC red-c)
  correctM (CPS.RGCons₂ ΔΘ red-m) = DSK.RGCons₂ (dskΔΘ ΔΘ) (correctM red-m)