module CoercionExpr.Simulation where

open import Data.Nat
open import Data.Unit using (⊀; tt)
open import Data.Bool using (true; false) renaming (Bool to 𝔹)
open import Data.List hiding ([_])
open import Data.Product renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_)
open import Data.Maybe
open import Relation.Nullary using (Β¬_; Dec; yes; no)
open import Relation.Binary.PropositionalEquality using (_≑_; refl)
open import Function using (case_of_)

open import Common.Utils
open import Common.SecurityLabels
open import Common.BlameLabels
open import CoercionExpr.CoercionExpr
open import CoercionExpr.Precision
open import CoercionExpr.SimLemmas


sim : βˆ€ {g₁ g₁′ gβ‚‚ gβ‚‚β€²} {c̅₁ : CExpr g₁ β‡’ gβ‚‚} {c̅₁′ cΜ…β‚‚β€² : CExpr g₁′ β‡’ gβ‚‚β€²}
  β†’ ⊒ c̅₁ βŠ‘ c̅₁′
  β†’ c̅₁′ β€”β†’ cΜ…β‚‚β€²
    --------------------------------------
  β†’ βˆƒ[ cΜ…β‚‚ ] (c̅₁ β€”β†  cΜ…β‚‚) Γ— (⊒ cΜ…β‚‚ βŠ‘ cΜ…β‚‚β€²)


sim-cast : βˆ€ {g₁ g₁′ gβ‚‚ gβ‚‚β€² g₃ g₃′}
             {c̅₁ : CExpr g₁ β‡’ gβ‚‚} {c̅₁′ : CExpr g₁′ β‡’ gβ‚‚β€²}
             {cΜ…β‚‚β€² : CExpr g₁′ β‡’ g₃′}
             {c  : ⊒ gβ‚‚ β‡’ g₃} {cβ€²  : ⊒ gβ‚‚β€² β‡’ g₃′}
  β†’ ⊒ c̅₁ βŠ‘ c̅₁′
  β†’ gβ‚‚ βŠ‘β‚— gβ‚‚β€² β†’ g₃ βŠ‘β‚— g₃′     {- c βŠ‘ cβ€² -}
  β†’ c̅₁′ β¨Ύ cβ€² β€”β†’ cΜ…β‚‚β€²
    ---------------------------------------------
  β†’ βˆƒ[ cΜ…β‚‚ ] (c̅₁ β¨Ύ c β€”β†  cΜ…β‚‚) Γ— (⊒ cΜ…β‚‚ βŠ‘ cΜ…β‚‚β€²)
sim-cast {c = c} {cβ€²} cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ (ΞΎ c̅₁′→cΜ…β€²)
  with sim cΜ…β‚βŠ‘c̅₁′ c̅₁′→cΜ…β€²
... | ⟨ cΜ… , c̅₁↠cΜ… , cΜ…βŠ‘cΜ…β€² ⟩ = ⟨ cΜ… β¨Ύ c , plug-cong c̅₁↠cΜ… , βŠ‘-cast cΜ…βŠ‘cΜ…β€² gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ ⟩
sim-cast {c̅₁ = c̅₁} {c = c} {cβ€²} cΜ…β‚βŠ‘βŠ₯ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ ΞΎ-βŠ₯ =
  let ⟨ gβ‚βŠ‘g₁′ , _ ⟩ = precβ†’βŠ‘ c̅₁ _ cΜ…β‚βŠ‘βŠ₯ in
  ⟨ c̅₁ β¨Ύ c , _ ∎ , βŠ‘-βŠ₯ gβ‚βŠ‘g₁′ gβ‚ƒβŠ‘g₃′ ⟩
sim-cast cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ (id   vβ€²) = sim-cast-id  cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ vβ€²
sim-cast cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ (?-id vβ€²) = sim-cast-id? cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ vβ€²
sim-cast cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ (?-↑ vβ€²) = sim-cast-↑  cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ vβ€²
sim-cast cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ (?-βŠ₯  vβ€²) =
  let ⟨ gβ‚βŠ‘g₁′ , _ ⟩ = precβ†’βŠ‘ _ _ cΜ…β‚βŠ‘c̅₁′ in
  ⟨ _ , _ ∎ , βŠ‘-βŠ₯ gβ‚βŠ‘g₁′ gβ‚ƒβŠ‘g₃′ ⟩


sim-castr : βˆ€ {g₁ g₁′ gβ‚‚ gβ‚‚β€² g₃′}
             {c̅₁ : CExpr g₁ β‡’ gβ‚‚} {c̅₁′ : CExpr g₁′ β‡’ gβ‚‚β€²}
             {cΜ…β‚‚β€² : CExpr g₁′ β‡’ g₃′}
             {cβ€²  : ⊒ gβ‚‚β€² β‡’ g₃′}
  β†’ ⊒ c̅₁ βŠ‘ c̅₁′
  β†’ gβ‚‚ βŠ‘β‚— gβ‚‚β€² β†’ gβ‚‚ βŠ‘β‚— g₃′
  β†’ c̅₁′ β¨Ύ cβ€² β€”β†’ cΜ…β‚‚β€²
    ---------------------------------------------
  β†’ βˆƒ[ cΜ…β‚‚ ] (c̅₁ β€”β†  cΜ…β‚‚) Γ— (⊒ cΜ…β‚‚ βŠ‘ cΜ…β‚‚β€²)
sim-castr {cβ€² = cβ€²} cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚‚βŠ‘g₃′ (ΞΎ c̅₁′→cΜ…β€²)
  with sim cΜ…β‚βŠ‘c̅₁′ c̅₁′→cΜ…β€²
... | ⟨ cΜ… , c̅₁↠cΜ… , cΜ…βŠ‘cΜ…β€² ⟩ = ⟨ cΜ… , c̅₁↠cΜ… , βŠ‘-castr cΜ…βŠ‘cΜ…β€² gβ‚‚βŠ‘gβ‚‚β€² gβ‚‚βŠ‘g₃′ ⟩
sim-castr {c̅₁ = c̅₁} {cβ€² = cβ€²} cΜ…β‚βŠ‘βŠ₯ gβ‚‚βŠ‘gβ‚‚β€² gβ‚‚βŠ‘g₃′ ΞΎ-βŠ₯ =
  let ⟨ gβ‚βŠ‘g₁′ , _ ⟩ = precβ†’βŠ‘ c̅₁ _ cΜ…β‚βŠ‘βŠ₯ in
  ⟨ c̅₁ , _ ∎ , βŠ‘-βŠ₯ gβ‚βŠ‘g₁′ gβ‚‚βŠ‘g₃′ ⟩
sim-castr cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚‚βŠ‘g₃′ (id   vβ€²) = ⟨ _ , _ ∎ , cΜ…β‚βŠ‘c̅₁′ ⟩
sim-castr cΜ…β‚βŠ‘c̅₁′ β‹†βŠ‘ β‹†βŠ‘ (?-id vβ€²)
  with catchup _ _ (inj vβ€²) cΜ…β‚βŠ‘c̅₁′
... | ⟨ cΜ…β‚™ , v , c̅₁↠cΜ…β‚™ , cΜ…β‚™βŠ‘c̅₁′ ⟩ = ⟨ cΜ…β‚™ , c̅₁↠cΜ…β‚™ , prec-inj-left _ _ v vβ€² cΜ…β‚™βŠ‘c̅₁′ ⟩
sim-castr cΜ…β‚βŠ‘c̅₁′ β‹†βŠ‘ β‹†βŠ‘ (?-↑ vβ€²)
  with catchup _ _ (inj vβ€²) cΜ…β‚βŠ‘c̅₁′
... | ⟨ cΜ…β‚™ , v , c̅₁↠cΜ…β‚™ , cΜ…β‚™βŠ‘c̅₁′ ⟩ = ⟨ cΜ…β‚™ , c̅₁↠cΜ…β‚™ , βŠ‘-castr (prec-inj-left _ _ v vβ€² cΜ…β‚™βŠ‘c̅₁′) β‹†βŠ‘ β‹†βŠ‘ ⟩
sim-castr cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘gβ‚‚β€² gβ‚ƒβŠ‘g₃′ (?-βŠ₯  vβ€²) =
  let ⟨ gβ‚βŠ‘g₁′ , _ ⟩ = precβ†’βŠ‘ _ _ cΜ…β‚βŠ‘c̅₁′ in
  ⟨ _ , _ ∎ , βŠ‘-βŠ₯ gβ‚βŠ‘g₁′ gβ‚ƒβŠ‘g₃′ ⟩


sim (βŠ‘-cast  cΜ…β‚βŠ‘c̅₁′ gβ‚ƒβŠ‘g₃′ gβ‚‚βŠ‘gβ‚‚β€²) c̅₁′→cΜ…β‚‚β€² = sim-cast cΜ…β‚βŠ‘c̅₁′ gβ‚ƒβŠ‘g₃′ gβ‚‚βŠ‘gβ‚‚β€² c̅₁′→cΜ…β‚‚β€²
sim (βŠ‘-castl {c = c} cΜ…β‚βŠ‘c̅₁′ gβ‚ƒβŠ‘gβ‚‚β€² gβ‚‚βŠ‘gβ‚‚β€²) c̅₁′→cΜ…β‚‚β€²
  with sim cΜ…β‚βŠ‘c̅₁′ c̅₁′→cΜ…β‚‚β€²
... | ⟨ cΜ… , c̅₁↠cΜ… , cΜ…βŠ‘cΜ…β€² ⟩ = ⟨ cΜ… β¨Ύ c , plug-cong c̅₁↠cΜ… , βŠ‘-castl cΜ…βŠ‘cΜ…β€² gβ‚ƒβŠ‘gβ‚‚β€² gβ‚‚βŠ‘gβ‚‚β€² ⟩
sim (βŠ‘-castr cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘g₃′ gβ‚‚βŠ‘gβ‚‚β€²) c̅₁′→cΜ…β‚‚β€² = sim-castr cΜ…β‚βŠ‘c̅₁′ gβ‚‚βŠ‘g₃′ gβ‚‚βŠ‘gβ‚‚β€² c̅₁′→cΜ…β‚‚β€²