content: 
  module DDC.Core.Discus.Convert.Exp.Base
          ( -- * Context
            Context       (..)
          , typeContext
          , extendKindEnv, extendsKindEnv
          , extendTypeEnv, extendsTypeEnv
  
          , ExpContext    (..)
  
          -- * Constructors
          , xConvert
          , xTakePtr
          , xMakePtr)
  where
  import DDC.Core.Discus.Transform.Curry.Callable
  import DDC.Core.Discus.Convert.Error
  import DDC.Core.Salt.Platform
  import DDC.Core.Exp.Annot
  import DDC.Core.Check                                   (AnTEC(..))
  import DDC.Type.DataDef
  import DDC.Type.Env                                     (KindEnv, TypeEnv)
  import Data.Set                                         (Set)
  import Data.Map                                         (Map)
  import qualified DDC.Core.Discus.Convert.Type.Base      as T
  import qualified DDC.Core.Discus.Prim                   as E
  import qualified DDC.Type.Env                           as Env
  import qualified DDC.Core.Salt.Name                     as A
  
  
  ---------------------------------------------------------------------------------------------------
  -- | Context of an Exp conversion.
  data Context a
          = Context
          { -- | The platform that we're converting to,
            --   this sets the pointer width.
            contextPlatform       :: Platform
  
            -- | Data type definitions.
            --   All the visible type equations, from the current and imported modules.
          , contextDataDefs       :: DataDefs E.Name
  
            -- | Type equations.
            --   All the visible type equations, from the current and imported modules.
          , contextTypeEqns       :: Map E.Name (Type E.Name)
  
            -- | Names of foreign boxed data type contructors.
            --   These are names like 'Ref' and 'Array' that are defined in the
            --   runtime system rather than as an algebraic data type with a
            --   Discus-level data type definition. Although there is no data
            --   type definition, we still represent the values of these types
            --   in generic boxed form.
          , contextForeignBoxedTypeCtors
                                  :: Set      E.Name
  
            -- | Call patterns of things that we can call directly, in the generated code.
            --   This is locally defined supers, as well as imported supers and sea functions.
          , contextCallable       :: Map E.Name Callable
  
            -- | Current kind environment.
            --   This is updated as we decend into the AST during conversion.
          , contextKindEnv        :: KindEnv  E.Name
  
            -- | Current type environment.
            --   This is updated as we decend into the AST during conversion.
          , contextTypeEnv        :: TypeEnv  E.Name
  
            -- | Re-bindings of top-level supers.
            --   This is used to handle let-expressions like 'f = g [t]' where
            --   'g' is a top-level super. See [Note: Binding top-level supers]
            --   Maps the left hand variable to the right hand one, eg f -> g,
            --   along with its unpacked type arguments.
          , contextSuperBinds
                  :: Map E.Name (E.Name, [(Type E.Name, Kind E.Name)])
  
            -- Functions to convert the various parts of the AST.
            -- We tie the recursive knot though this `Context` type so that
            -- we can split the implementation into separate non-recursive modules.
          , contextConvertExp
                  :: ExpContext   -> Context a
                  -> Exp  (AnTEC a E.Name) E.Name
                  -> ConvertM a (Exp a A.Name)
  
          , contextConvertLets
                  :: Context a
                  -> Lets (AnTEC a E.Name)   E.Name
                  -> ConvertM a (Maybe (Lets a A.Name), Context a)
  
          , contextConvertAlt
                  :: a
                  -> Maybe (Bound E.Name) -> Type E.Name
                  -> ExpContext   -> Context a
                  -> Alt  (AnTEC a E.Name) E.Name
                  -> ConvertM a (Alt a A.Name)
          }
  
  
  -- | Create a type context from an expression context.
  typeContext :: Context a -> T.Context
  typeContext ctx
          = T.Context
          { T.contextDataDefs     = contextDataDefs ctx
          , T.contextTypeEqns     = contextTypeEqns ctx
          , T.contextForeignBoxedTypeCtors
                                  = contextForeignBoxedTypeCtors ctx
          , T.contextKindEnv      = contextKindEnv  ctx }
  
  
  -- | Extend the kind environment of a context with a new binding.
  extendKindEnv  ::  Bind E.Name  -> Context a -> Context a
  extendKindEnv b ctx
          = ctx { contextKindEnv = Env.extend b (contextKindEnv ctx) }
  
  
  -- | Extend the kind environment of a context with some new bindings.
  extendsKindEnv :: [Bind E.Name] -> Context a -> Context a
  extendsKindEnv bs ctx
          = ctx { contextKindEnv = Env.extends bs (contextKindEnv ctx) }
  
  
  -- | Extend the type environment of a context with a new binding.
  extendTypeEnv  :: Bind E.Name   -> Context a -> Context a
  extendTypeEnv b ctx
          = ctx { contextTypeEnv = Env.extend b (contextTypeEnv ctx) }
  
  
  -- | Extend the type environment of a context with some new bindings.
  extendsTypeEnv :: [Bind E.Name] -> Context a -> Context a
  extendsTypeEnv bs ctx
          = ctx { contextTypeEnv = Env.extends bs (contextTypeEnv ctx) }
  
  
  ---------------------------------------------------------------------------------------------------
  -- | The context we're converting an expression in.
  --   We keep track of this during conversion to ensure we don't produce
  --   code outside the Salt language fragment. For example, in Salt a function
  --   can only be applied to a value variable, type or witness -- and not
  --   a general expression.
  data ExpContext
          = ExpTop        -- ^ At the top-level of the module.
          | ExpFun        -- ^ At the top-level of a function.
          | ExpBody       -- ^ In the body of a function.
          | ExpBind       -- ^ In the right of a let-binding.
          | ExpArg        -- ^ In a function argument.
          deriving (Show, Eq, Ord)
  
  
  ---------------------------------------------------------------------------------------------------
  xConvert :: a -> Type A.Name -> Type A.Name -> Exp a A.Name -> Exp a A.Name
  xConvert a t1 t2 x1
          = xApps a (XVar a  (UName (A.NamePrimOp $ A.PrimCast $ A.PrimCastConvert)))
                    [ RType t1, RType t2, RTerm x1 ]
  
  
  xTakePtr :: a -> Type A.Name -> Type A.Name -> Exp a A.Name -> Exp a A.Name
  xTakePtr a tR tA x1
          = xApps a (XVar a  (UName (A.NamePrimOp $ A.PrimStore A.PrimStoreTakePtr)))
                    [ RType tR, RType tA, RTerm x1 ]
  
  
  xMakePtr :: a -> Type A.Name -> Type A.Name -> Exp a A.Name -> Exp a A.Name
  xMakePtr a tR tA x1
          = xApps a (XVar a  (UName (A.NamePrimOp $ A.PrimStore A.PrimStoreMakePtr)))
                    [ RType tR, RType tA, RTerm x1 ]
  
  
  