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𝒟 })


--------------------------------------------------------------------------------