module Scoped.Except where

open import Function

open import Data.Empty
open import Data.Sum
open import Data.Maybe using (Maybe ; just ; nothing)

open import Container
open import Scoped.Prog

module _ where

  open Con

  data ThrowOp (X : Set) : Set where
    `throw : X  ThrowOp X

  ThrowSig : Set  Con
  S (ThrowSig X) = ThrowOp X
  P (ThrowSig X) (`throw x) = 


  data Catch (X : Set) : Set where
    `catch : Catch X

  CatchScope : Set  Con
  S (CatchScope X) = Catch X
  P (CatchScope X) `catch = Maybe X

module _ {X : Set} where 

  catch : Prog σ (CatchScope X) A 
          (X  Prog σ (CatchScope X) A) 
          Prog σ (CatchScope X) A
  catch p h =
    scope `catch
           where
            nothing  p
            (just x)  h x)
          var

  hEx : Prog (ThrowSig X  σ) (CatchScope X  γ) A  Prog σ γ (A  X)
  hEx (var x) = var (inj₁ x)
  hEx (op (inj₁ (`throw x)) k) = var (inj₂ x)
  hEx (op (inj₂ c) k) = op c (hEx  k)
  hEx (scope (inj₁ `catch) sc k) = do
    (inj₁ x)  hEx (sc nothing)
      where
        (inj₂ x) 
          do (inj₁ x)  hEx (sc (just x))
                   where (inj₂ x)  var (inj₂ x)
             hEx (k x)
    hEx (k x)
  hEx (scope (inj₂ g) sc k) =
    scope g (hEx  sc)  where
                          (inj₁ b)  hEx (k b)
                          (inj₂ x)  var (inj₂ x))