content: {-# LANGUAGE GADTs, DataKinds, RankNTypes, FlexibleContexts #-}
  {-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Language.Glambda.Globals
  -- Copyright   :  (C) 2015 Richard Eisenberg
  -- License     :  BSD-style (see LICENSE)
  -- Maintainer  :  Richard Eisenberg (rae@cs.brynmawr.edu)
  -- Stability   :  experimental
  --
  -- Manages the global variables in Glambda
  --
  ----------------------------------------------------------------------------
  
  module Language.Glambda.Globals (
    Globals, emptyGlobals, extend, lookupGlobal ) where
  
  import Language.Glambda.Exp
  import Language.Glambda.Type
  
  import Prettyprinter (Doc, pretty, (<+>), squotes)
  import Prettyprinter.Render.Terminal (AnsiStyle)
  
  import Control.Monad.Except
  
  import Data.Map as Map
  
  -- | An existential wrapper around 'Exp', storing the expression and
  -- its type.
  data EExp where
    EExp :: STy ty -> Exp '[] ty -> EExp
  
  -- | The global variable environment maps variables to type-checked
  -- expressions
  newtype Globals = Globals (Map String EExp)
  
  -- | An empty global variable environment
  emptyGlobals :: Globals
  emptyGlobals = Globals Map.empty
  
  -- | Extend a 'Globals' with a new binding
  extend :: String -> STy ty -> Exp '[] ty -> Globals -> Globals
  extend var sty exp (Globals globals)
    = Globals $ Map.insert var (EExp sty exp) globals
  
  -- | Lookup a global variable. Fails with 'throwError' if the variable
  -- is not bound.
  lookupGlobal :: MonadError (Doc AnsiStyle) m
               => Globals -> String
               -> (forall ty. STy ty -> Exp '[] ty -> m r)
               -> m r
  lookupGlobal (Globals globals) var k
    = case Map.lookup var globals of
        Just (EExp sty exp) -> k sty exp
        Nothing             -> throwError $
                               pretty "Global variable not in scope:" <+>
                                 squotes (pretty var)
  