packages feed

ddc-core-llvm-0.4.2.1: DDC/Core/Llvm/Convert/Context.hs

module DDC.Core.Llvm.Convert.Context
        ( Context       (..)
        , extendKindEnv, extendsKindEnv
        , extendTypeEnv, extendsTypeEnv

        , ExpContext    (..)
        , AltResult     (..)
        , takeVarOfContext
        , takeNonVoidVarOfContext)
where
import DDC.Core.Salt.Platform
import DDC.Core.Llvm.Metadata.Tbaa
import DDC.Core.Llvm.Convert.Base
import DDC.Type.Exp
import DDC.Llvm.Syntax
import DDC.Type.Env                     (KindEnv, TypeEnv)
import Data.Sequence                    (Seq)
import Data.Set                         (Set)
import Data.Map                         (Map)
import qualified DDC.Core.Salt          as A
import qualified DDC.Core.Module        as C
import qualified DDC.Core.Exp           as C
import qualified DDC.Type.Env           as Env


---------------------------------------------------------------------------------------------------
-- | Context of an Salt to LLVM conversion.
data Context 
        = Context
        { -- | The platform that we're converting to, 
          --   this sets the pointer width.
          contextPlatform       :: Platform

          -- | Surrounding module.
        , contextModule         :: C.Module () A.Name

          -- | The top-level kind environment.
        , contextKindEnvTop     :: KindEnv  A.Name

          -- | The top-level type environment.
        , contextTypeEnvTop     :: TypeEnv  A.Name

          -- | Names of imported supers that are defined in external modules.
          --   These are directly callable in the object code.
        , contextImports        :: Set      A.Name

          -- | Names of local supers that are defined in the current module.
          --   These are directly callable in the object code.
        , contextSupers         :: Set      A.Name

          -- | Current kind environment.
        , contextKindEnv        :: KindEnv  A.Name

          -- | Current type environment.
        , contextTypeEnv        :: TypeEnv  A.Name 

          -- | Map between core level variable names and LLVM names.
        , contextNames          :: Map A.Name Var

          -- | Super meta data
        , contextMDSuper        :: MDSuper 

          -- | C library functions that are used directly by the generated code without
          --   having an import declaration in the header of the converted module.
        , contextPrimDecls      :: Map String FunctionDecl

          -- | 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 right hand variable to the left hand one, eg g -> f,
          --   along with its type arguments.
        , contextSuperBinds
                :: Map A.Name (A.Name, [C.Type A.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.
        , contextConvertBody 
                :: Context   -> ExpContext
                -> Seq Block -> Label
                -> Seq AnnotInstr
                -> A.Exp 
                -> ConvertM (Seq Block)

        , contextConvertExp      
                :: Context  -> ExpContext
                -> A.Exp
                -> ConvertM (Seq AnnotInstr)

        , contextConvertCase
                :: Context  -> ExpContext
                -> Label
                -> Seq AnnotInstr
                -> A.Exp
                -> [A.Alt]
                -> ConvertM (Seq Block)
        }


-- | Holds the result of converting an alternative.
data AltResult
        = AltDefault  Label (Seq Block)
        | AltCase Lit Label (Seq Block)


-- | Extend the kind environment of a context with a new binding.
extendKindEnv  :: Bind A.Name  -> Context -> Context
extendKindEnv b ctx
        = ctx { contextKindEnv = Env.extend b (contextKindEnv ctx) }


-- | Extend the kind environment of a context with some new bindings.
extendsKindEnv :: [Bind A.Name] -> Context -> Context
extendsKindEnv bs ctx
        = ctx { contextKindEnv = Env.extends bs (contextKindEnv ctx) }


-- | Extend the type environment of a context with a new binding.
extendTypeEnv  :: Bind A.Name   -> Context -> Context
extendTypeEnv b ctx
        = ctx { contextTypeEnv = Env.extend b (contextTypeEnv ctx) }


-- | Extend the type environment of a context with some new bindings.
extendsTypeEnv :: [Bind A.Name] -> Context -> Context
extendsTypeEnv bs ctx
        = ctx { contextTypeEnv = Env.extends bs (contextTypeEnv ctx) }


---------------------------------------------------------------------------------------------------
-- | What expression context we're doing this conversion in.
data ExpContext
        -- | Conversion at the top-level of a function.
        --   The expresison being converted must eventually pass control.
        = ExpTop 

        -- | In a nested context, like in the right of a let-binding.
        --   The expression should produce a value that we assign to this
        --   variable, then jump to the provided label to continue evaluation.
        | ExpNest   ExpContext Var Label

        -- | In a nested context where we need to assign the result
        --   to the given variable and fall through.
        | ExpAssign ExpContext Var


-- | Take any assignable variable from a `Context`.
takeVarOfContext :: ExpContext -> Maybe Var
takeVarOfContext context
 = case context of
        ExpTop                  -> Nothing
        ExpNest _ var _         -> Just var
        ExpAssign _ var         -> Just var


-- | Take any assignable variable from a `Context`, but only if it has a non-void type.
--   In LLVM we can't assign to void variables.
takeNonVoidVarOfContext :: ExpContext -> Maybe Var
takeNonVoidVarOfContext context
 = case takeVarOfContext context of
        Just (Var _ TVoid)       -> Nothing
        mv                       -> mv