{-# OPTIONS --rewriting #-}
module A201801.STLCStandardNameResolution where
open import A201801.Prelude
open import A201801.Names
open import A201801.Fin
open import A201801.Vec
open import A201801.STLCTypes
open import A201801.STLCStandardBidirectionalTerms-CheckedInferred
mutual
  data RawTermₗ : Set
    where
      LAM : Name → RawTermₗ → RawTermₗ
      INF : RawTermᵣ → RawTermₗ
  data RawTermᵣ : Set
    where
      VAR : Name → RawTermᵣ
      APP : RawTermᵣ → RawTermₗ → RawTermᵣ
      CHK : RawTermₗ → Type → RawTermᵣ
mutual
  infix 3 ⊢_≫_tocheck[_]
  data ⊢_≫_tocheck[_] : ∀ {g} → RawTermₗ → Termₗ g → Names g → Set
    where
      lam : ∀ {x g P M} → {Γ : Names g}
                        → ⊢ P ≫ M tocheck[ Γ , x ]
                        → ⊢ LAM x P ≫ LAM M tocheck[ Γ ]
      inf : ∀ {g P M} → {Γ : Names g}
                      → ⊢ P ≫ M toinfer[ Γ ]
                      → ⊢ INF P ≫ INF M tocheck[ Γ ]
  infix 3 ⊢_≫_toinfer[_]
  data ⊢_≫_toinfer[_] : ∀ {g} → RawTermᵣ → Termᵣ g → Names g → Set
    where
      vz : ∀ {x g} → {Γ : Names g}
                   → ⊢ VAR x ≫ VAR zero toinfer[ Γ , x ]
      wk : ∀ {x y g I} → {Γ : Names g}
                       → x ≢ y → ⊢ VAR x ≫ VAR I toinfer[ Γ ]
                       → ⊢ VAR x ≫ VAR (suc I) toinfer[ Γ , y ]
      app : ∀ {g P Q M N} → {Γ : Names g}
                          → ⊢ P ≫ M toinfer[ Γ ] → ⊢ Q ≫ N tocheck[ Γ ]
                          → ⊢ APP P Q ≫ APP M N toinfer[ Γ ]
      chk : ∀ {A g P M} → {Γ : Names g}
                        → ⊢ P ≫ M tocheck[ Γ ]
                        → ⊢ CHK P A ≫ CHK M A toinfer[ Γ ]
injvzwk : ∀ {g x y M} → {Γ : Names g}
                      → ⊢ VAR x ≫ M toinfer[ Γ , y ]
                      → x ≡ y ⊎ Σ (Termᵣ g) (\ M′ → ⊢ VAR x ≫ M′ toinfer[ Γ ])
injvzwk vz       = inj₁ refl
injvzwk (wk p 𝒟) = inj₂ (VAR _ , 𝒟)
find : ∀ {g} → (Γ : Names g) (x : Name)
             → Dec (Σ (Termᵣ g) (\ M → ⊢ VAR x ≫ M toinfer[ Γ ]))
find ∙       x  = no (\ { (M , ())})
find (Γ , y) x  with x ≟ₛ y
find (Γ , x) .x | yes refl = yes (VAR zero , vz)
find (Γ , y) x  | no x≢y   with find Γ x
find (Γ , y) x  | no x≢y   | yes (VAR I , 𝒟)    = yes (VAR (suc I) , wk x≢y 𝒟)
find (Γ , y) x  | no x≢y   | yes (APP M N , ())
find (Γ , y) x  | no x≢y   | yes (CHK M A , ())
find (Γ , y) x  | no x≢y   | no ¬M𝒟             = no (\ { (M′ , 𝒟′) → case injvzwk 𝒟′ of
                                                       (\ { (inj₁ x≡y) → x≡y ↯ x≢y
                                                          ; (inj₂ M𝒟) → M𝒟 ↯ ¬M𝒟
                                                          }) })
mutual
  resolveₗ : ∀ {g} → (Γ : Names g) (P : RawTermₗ)
                   → Dec (Σ (Termₗ g) (\ M → ⊢ P ≫ M tocheck[ Γ ]))
  resolveₗ Γ (LAM x P) with resolveₗ (Γ , x) P
  resolveₗ Γ (LAM x P) | yes (M , 𝒟) = yes (LAM M , lam 𝒟)
  resolveₗ Γ (LAM x P) | no ¬M𝒟      = no (\ { (LAM M′ , lam 𝒟′) → (M′ , 𝒟′) ↯ ¬M𝒟 })
  resolveₗ Γ (INF P)   with resolveᵣ Γ P
  resolveₗ Γ (INF P)   | yes (M , 𝒟) = yes (INF M , inf 𝒟)
  resolveₗ Γ (INF P)   | no ¬M𝒟      = no (\ { (INF M′ , inf 𝒟′) → (M′ , 𝒟′) ↯ ¬M𝒟 })
  resolveᵣ : ∀ {g} → (Γ : Names g) (P : RawTermᵣ)
                   → Dec (Σ (Termᵣ g) (\ M → ⊢ P ≫ M toinfer[ Γ ]))
  resolveᵣ Γ (VAR x)   = find Γ x
  resolveᵣ Γ (APP P Q) with resolveᵣ Γ P | resolveₗ Γ Q
  resolveᵣ Γ (APP P Q) | yes (M , 𝒟) | yes (N , ℰ) = yes (APP M N , app 𝒟 ℰ)
  resolveᵣ Γ (APP P Q) | yes (M , 𝒟) | no ¬Nℰ      = no (\ { (APP M′ N′ , app 𝒟′ ℰ′) → (N′ , ℰ′) ↯ ¬Nℰ })
  resolveᵣ Γ (APP P Q) | no ¬M𝒟      | _           = no (\ { (APP M′ N′ , app 𝒟′ ℰ′) → (M′ , 𝒟′) ↯ ¬M𝒟 })
  resolveᵣ Γ (CHK P A) with resolveₗ Γ P
  resolveᵣ Γ (CHK P A) | yes (M , 𝒟) = yes (CHK M A , chk 𝒟)
  resolveᵣ Γ (CHK P A) | no ¬M𝒟      = no (\ { (CHK M′ A′ , chk 𝒟′) → (M′ , 𝒟′) ↯ ¬M𝒟 })