open import Prelude 

open import Level 
open import Data.Product
open import Relation.Binary.PropositionalEquality as Eq using (_≡_)

{-
  Soundness and Completeness between Stack Machine Semantics and Big-Step Semantics
-}
module SoundnessCompleteness.StackMachineBigStep { : Level} (monoid : Monoid ) where

open import Language.PCF monoid
open import Language.Substitution monoid

open import Language.StackMachine monoid
open import Language.BigStep monoid 

open MonoidArithmetic monoid

private
  variable
    τ : Type

⇓→↦* : {e v : ·  τ} {a : Effect} {K : Frame}  
    e  v  a 
   (k : K ÷ τ) 
  ------------------------
   k  e ↦* k  v  a
⇓→↦* be-zero k = k▹v↦*k◃v v-zero 
⇓→↦* (be-suc {v = v} {a = a} e⇓v) k = 
  let step₁ = ↦*-step ke-suc₁ (⇓→↦* e⇓v (k  suc⟨-⟩)) in
  let step₂ = ↦*-step ke-suc₂ ↦*-refl in 
  let step = ↦*-trans step₁ step₂ in
  Eq.subst  a  k  `suc _ ↦* k  `suc v  a) (arithmetic₉ a) step
⇓→↦* (be-case-z {a = a} {b = b} e⇓z e⇓v) k rewrite arithmetic₇ a b = 
  let step₁ = ↦*-step ke-case (⇓→↦* e⇓z (k  _)) in 
  let step₂ = ↦*-step ke-case-z (⇓→↦* e⇓v k) in
    ↦*-trans step₁ step₂
⇓→↦* (be-case-s {a = a} {b = b} e⇓s e⇓v) k rewrite arithmetic₇ a b = 
  let step₁ = ↦*-step ke-case (⇓→↦* e⇓s (k  _)) in 
  let step₂ = ↦*-step ke-case-s (⇓→↦* e⇓v k) in
    ↦*-trans step₁ step₂
⇓→↦* be-fun k = k▹v↦*k◃v v-fun
⇓→↦* (be-app {a = a} {b = b} {c = c} e⇓f e⇓v e⇓v₁) k rewrite arithmetic₈ a b c = 
  let step₁ = ↦*-step ke-app₁ (⇓→↦* e⇓f (k  _)) in 
  let step₂ = ↦*-step ke-app₂ (⇓→↦* e⇓v (k  _)) in
  let step₃ = ↦*-step ke-app₃ (⇓→↦* e⇓v₁ k) in
    ↦*-trans step₁ (↦*-trans step₂ step₃)
⇓→↦* (be-eff e⇓v) k = ↦*-step ke-eff (⇓→↦* e⇓v k)

{-
  Convergent Completeness
-}
⇓→↦*-ε : {e v : ·  τ} {a : Effect}  
    e  v  a  
  ------------------------
   ε  e ↦* ε  v  a
⇓→↦*-ε e⇓v = ⇓→↦* e⇓v ε

{-
  Co-evaluation: if e evaluates to v then d also evaluates to v with an extra effect
  
  This is necessary for proving soundness because there is no chance to inspect intermediate steps in big-step semantics.
-}
infix 4 _⟪_∣_
_⟪_∣_ : ·  τ  ·  τ  Effect  Set  
_⟪_∣_ {τ} e d a = {v : ·  τ} {b : Effect}  (c : Effect)   
    c  a  b 
   e  v  b 
  ------------------------
   d  v  c

⟪-● : {K : Frame} {e d : ·  τ} {a : Effect} 
    (k : K ÷ τ) 
   e  d  a
  ------------------------
   k  e  k  d  a
⟪-● ε f = f
⟪-● {a = b} (K  suc⟨-⟩) f
  = ⟪-● K  { c' c'≡a'∙b (be-suc e⇓v)  be-suc (f c' c'≡a'∙b e⇓v) }) 
⟪-● {e = e} {d = d} {a = b} (K  case⟨-⟩ e₁ e₂) f 
  = ⟪-● K  { c' c'≡a'∙b (be-case-z {a = a} {b = c} e⇓z e⇓v)  
      let step = be-case-z (f (b  a) Eq.refl e⇓z) e⇓v in 
        Eq.subst 
           a  `case d _ _  _  a) 
          (Eq.trans (assoc b a c) (Eq.sym c'≡a'∙b)) 
          step
      ; c' c'≡a'∙b (be-case-s {a = a} {b = c} e⇓s e⇓v)  
      let step = be-case-s (f (b  a) Eq.refl e⇓s) e⇓v in 
        Eq.subst 
           a  `case d _ _  _  a) 
          (Eq.trans (assoc b a c) (Eq.sym c'≡a'∙b)) 
          step }) 
⟪-● {e = e} {d = d} {a = b} (K  app⟨-⟩ e₂) f 
  = ⟪-● K  { c' c'≡a'∙b (be-app {a = a} e⇓f e₂⇓v e⇓v)  
      let step = be-app (f (b  a) Eq.refl e⇓f) e₂⇓v e⇓v in 
        Eq.subst 
           a  `app d _  _  a) 
          (Eq.trans (Eq.trans (assoc (b  _) _ _) (Eq.trans (assoc _ _ _) (Eq.cong  a  b  a) (Eq.sym (assoc _ _ _))))) (Eq.sym c'≡a'∙b)) 
          step })
⟪-● {e = e} {d = d} {a = b} (K  app⟨fun e₁ ⟩⟨-⟩) f 
  = ⟪-● K  { c' c'≡a'∙b (be-app {a = a} {b = c} {c = g} be-fun e₂⇓v e⇓v)  
      let step = be-app be-fun (f (b  c) Eq.refl e₂⇓v) e⇓v in 
        Eq.subst 
           a  `app (`fun _) d  _  a) 
          (Eq.trans (Eq.cong  a  a  g) (identityˡ (b  c))) (Eq.trans (assoc b c g) (Eq.trans (Eq.cong  a  b  (a  g)) (Eq.sym (identityˡ c))) (Eq.sym c'≡a'∙b)))) 
          step })

mutual 
  ▹-↦*→⇓ : {K : Frame} {k : K ÷ τ} {e : ·  τ} {v : ·  return-type k} {a : Effect}  
      k  e ↦* ε  v  a  
    ------------------------
     k  e  v  a
  ▹-↦*→⇓ (↦*-step {b = b} ke-zero s) rewrite identityˡ b = ◃-↦*→⇓ s v-zero 
  ▹-↦*→⇓ (↦*-step {b = b} ke-suc₁ s) rewrite identityˡ b = ▹-↦*→⇓ s
  ▹-↦*→⇓ (↦*-step {b = b} ke-case s) rewrite identityˡ b = ▹-↦*→⇓ s
  ▹-↦*→⇓ (↦*-step {b = b} ke-fun s)  rewrite identityˡ b = ◃-↦*→⇓ s v-fun 
  ▹-↦*→⇓ (↦*-step {b = b} ke-app₁ s) rewrite identityˡ b = ▹-↦*→⇓ s
  ▹-↦*→⇓ {k = k} (↦*-step {a = a} {b = b} ke-eff s) 
    = ⟪-● k 
       c' c'≡a∙b' e⇓v  
        let step = be-eff e⇓v in 
          Eq.subst  a  `eff _ _  _  a) (Eq.sym c'≡a∙b') step) 
      (a  b) Eq.refl (▹-↦*→⇓ s)

  ◃-↦*→⇓ : {K : Frame} {k : K ÷ τ} {e : ·  τ} {v : ·  return-type k} {a : Effect}  
      k  e ↦* ε  v  a
     e val
    ------------------------
     k  e  v  a
  ◃-↦*→⇓ {k = ε} ↦*-refl e-val = v⇓v e-val
  ◃-↦*→⇓ {k = k  F} (↦*-step {b = b} ke-suc₂ s) e-val rewrite identityˡ b = ◃-↦*→⇓ s (v-suc e-val)
  ◃-↦*→⇓ {k = k  F} (↦*-step {b = b} ke-case-z s) e-val 
    = ⟪-● k  b' b'≡b e₁⇓v  
        let step = be-case-z be-zero e₁⇓v in 
          Eq.subst  a  `case `zero _ _  _  a) (Eq.sym b'≡b) step) 
      (1#  b) Eq.refl (▹-↦*→⇓ s)
  ◃-↦*→⇓ {k = k  F} (↦*-step {b = b} ke-case-s s) (v-suc v-val) 
    = ⟪-● k  b' b'≡b e₂⇓v  
        let step = be-case-s (be-suc (v⇓v v-val)) e₂⇓v in 
          Eq.subst  a  `case (`suc _) _ _  _  a) (Eq.sym b'≡b) step)
      (1#  b) Eq.refl (▹-↦*→⇓ s)
  ◃-↦*→⇓ {k = k  F} (↦*-step {b = b} ke-app₂ s) v-fun rewrite identityˡ b = ▹-↦*→⇓ s
  ◃-↦*→⇓ {k = k  F} (↦*-step {b = b} ke-app₃ s) e-val
    = ⟪-● k  c' c'≡a∙b' e⇓v  
        let step = be-app be-fun (v⇓v e-val) e⇓v in 
          Eq.subst  a  `app (`fun _) _  _  a) (Eq.trans (Eq.cong  a  a  _) (identityʳ 1#)) (Eq.sym c'≡a∙b')) step) 
      (1#  b) Eq.refl (▹-↦*→⇓ s)

{-
  Convergent Soundness
-}
↦*→⇓-ε : {e v : ·  τ} {a : Effect}  
    ε  e ↦* ε  v  a
  ------------------------
   e  v  a  
↦*→⇓-ε e↦*v = ▹-↦*→⇓ e↦*v

{-
  Convergent Equivalence

  Since big-step semantics can only describe terminating computations, convergent equivalence 
  is the only soundness and completeness property that can be stated between small-step and big-step semantics.
-}
↦*⇔⇓ : {e v : ·  τ} {a : Effect}  
    ε  e ↦* ε  v  a
  ------------------------
   
  ------------------------
    e  v  a 
↦*⇔⇓ = ↦*→⇓-ε , ⇓→↦*-ε