module CoercionExpr.GG 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.CatchUp     using (catchup) public
open import CoercionExpr.Simulation  using (sim) public
open import CoercionExpr.CatchUpBack using (InSync; v-v; v-⊄; catchup-back) public
open import CoercionExpr.SimBack     using (sim-back) public
open import CoercionExpr.SimBackBlame


sim-mult : āˆ€ {g₁ g₁′ gā‚‚ g₂′} {c̅₁ : CExpr g₁ ⇒ gā‚‚} {c̅₁′ c̅₂′ : CExpr g₁′ ⇒ g₂′}
  → ⊢ c̅₁ āŠ‘ c̅₁′
  → CVal c̅₂′
  → c̅₁′ —↠ c̅₂′
    ---------------------------------------------------
  → ∃[ cĢ…ā‚‚ ] (CVal cĢ…ā‚‚) Ɨ (c̅₁ —↠ cĢ…ā‚‚) Ɨ (⊢ cĢ…ā‚‚ āŠ‘ c̅₂′)
sim-mult cĢ…ā‚āŠ‘c̅₁′ š“‹ā€² (_ āˆŽ) = catchup _ _ š“‹ā€² cĢ…ā‚āŠ‘c̅₁′
sim-mult {c̅₁ = c̅₁} cĢ…ā‚āŠ‘c̅₁′ š“‹ā€² (_ ā€”ā†’āŸØ c̅₁′→c̅′ ⟩ c̅′↠c̅₂′) =
  let ⟨ cĢ…ā‚‚ ,     c̅₁↠cĢ…ā‚‚ , cĢ…ā‚‚āŠ‘c̅′ ⟩  = sim cĢ…ā‚āŠ‘c̅₁′ c̅₁′→c̅′ in
  let ⟨ cĢ…ā‚ƒ , š“‹ , c̅₂↠cĢ…ā‚ƒ , cĢ…ā‚ƒāŠ‘c̅₂′ ⟩ = sim-mult cĢ…ā‚‚āŠ‘c̅′ š“‹ā€² c̅′↠c̅₂′ in
  ⟨ cĢ…ā‚ƒ , š“‹ , ↠-trans c̅₁↠cĢ…ā‚‚ c̅₂↠cĢ…ā‚ƒ , cĢ…ā‚ƒāŠ‘c̅₂′ ⟩


sim-back-success : āˆ€ {ā„“ ℓ′ g g′} {c̅₁ cĢ…ā‚‚ : CExpr l ā„“ ⇒ g} {c̅₁′ : CExpr l ℓ′ ⇒ g′}
  → ⊢ c̅₁ āŠ‘ c̅₁′
  → CVal cĢ…ā‚‚
  → c̅₁ —↠ cĢ…ā‚‚
    ---------------------------------------------------
  → ∃[ c̅₂′ ] (c̅₁′ —↠ c̅₂′) Ɨ (InSync cĢ…ā‚‚ c̅₂′)
sim-back-success cĢ…ā‚āŠ‘c̅₁′ š“‹ (_ āˆŽ) = catchup-back _ _ š“‹ cĢ…ā‚āŠ‘c̅₁′
sim-back-success {c̅₁ = c̅₁} cĢ…ā‚āŠ‘c̅₁′ š“‹ (_ ā€”ā†’āŸØ c̅₁→cĢ… ⟩ c̅↠cĢ…ā‚‚) =
  let ⟨ c̅₂′ , c̅₁′↠c̅₂′ , prec ⟩ = sim-back cĢ…ā‚āŠ‘c̅₁′ c̅₁→cĢ… in
  let ⟨ cĢ…ā‚ƒā€² , c̅₂′↠cĢ…ā‚ƒā€² , sync ⟩ = sim-back-success prec š“‹ c̅↠cĢ…ā‚‚ in
  ⟨ cĢ…ā‚ƒā€² , ↠-trans c̅₁′↠c̅₂′ c̅₂′↠cĢ…ā‚ƒā€² , sync ⟩

sim-back-fail : āˆ€ {ā„“ ℓ′ g g′} {cĢ… : CExpr l ā„“ ⇒ g} {c̅′ : CExpr l ℓ′ ⇒ g′} {p}
  → ⊢ cĢ… āŠ‘ c̅′
  → cĢ… —↠ ⊄ (l ā„“) g p
    ---------------------------------------------------
  → ∃[ q ] (c̅′ —↠ ⊄ (l ℓ′) g′ q) Ɨ (⊢ ⊄ (l ā„“) g p āŠ‘ ⊄ (l ℓ′) g′ q)
sim-back-fail cĢ…āŠ‘c̅′ (_ āˆŽ) = sim-back-blame cĢ…āŠ‘c̅′
sim-back-fail {cĢ… = c̅₁} cĢ…ā‚āŠ‘c̅₁′ (_ ā€”ā†’āŸØ c̅₁→cĢ… ⟩ c̅↠cĢ…ā‚‚) =
  let ⟨ c̅₂′ , c̅₁′↠c̅₂′ , prec ⟩ = sim-back cĢ…ā‚āŠ‘c̅₁′ c̅₁→cĢ… in
  let ⟨ cĢ…ā‚ƒā€² , c̅₂′↠cĢ…ā‚ƒā€² , sync ⟩ = sim-back-fail prec c̅↠cĢ…ā‚‚ in
  ⟨ cĢ…ā‚ƒā€² , ↠-trans c̅₁′↠c̅₂′ c̅₂′↠cĢ…ā‚ƒā€² , sync ⟩