content: -- | 'Global's - top-level values in 'Module's - and supporting structures.
  module LLVM.AST.Global where
  
  import LLVM.Prelude
  
  import LLVM.AST.Name
  import LLVM.AST.Type
  import LLVM.AST.Constant (Constant)
  import LLVM.AST.AddrSpace
  import LLVM.AST.Instruction (Named, Instruction, Terminator)
  import qualified LLVM.AST.Linkage as L
  import qualified LLVM.AST.Visibility as V
  import qualified LLVM.AST.DLL as DLL
  import qualified LLVM.AST.CallingConvention as CC
  import qualified LLVM.AST.ThreadLocalStorage as TLS
  import qualified LLVM.AST.Attribute as A
  import LLVM.AST.Operand (MDRef, MDNode)
  
  -- | <http://llvm.org/doxygen/classllvm_1_1GlobalValue.html>
  data Global
      -- | <http://llvm.org/docs/LangRef.html#global-variables>
      = GlobalVariable {
          name :: Name,
          linkage :: L.Linkage,
          visibility :: V.Visibility,
          dllStorageClass :: Maybe DLL.StorageClass,
          threadLocalMode :: Maybe TLS.Model,
          unnamedAddr :: Maybe UnnamedAddr,
          isConstant :: Bool,
          type' :: Type,
          addrSpace :: AddrSpace,
          initializer :: Maybe Constant,
          section :: Maybe ShortByteString,
          comdat :: Maybe ShortByteString,
          alignment :: Word32,
          metadata :: [(ShortByteString, MDRef MDNode)]
        }
      -- | <http://llvm.org/docs/LangRef.html#aliases>
      | GlobalAlias {
          name :: Name,
          linkage :: L.Linkage,
          visibility :: V.Visibility,
          dllStorageClass :: Maybe DLL.StorageClass,
          threadLocalMode :: Maybe TLS.Model,
          unnamedAddr :: Maybe UnnamedAddr,
          type' :: Type,
          addrSpace :: AddrSpace,
          aliasee :: Constant
        }
      -- | <http://llvm.org/docs/LangRef.html#functions>
      | Function {
          linkage :: L.Linkage,
          visibility :: V.Visibility,
          dllStorageClass :: Maybe DLL.StorageClass,
          callingConvention :: CC.CallingConvention,
          returnAttributes :: [A.ParameterAttribute],
          returnType :: Type,
          name :: Name,
          parameters :: ([Parameter],Bool), -- ^ snd indicates varargs
          functionAttributes :: [Either A.GroupID A.FunctionAttribute],
          section :: Maybe ShortByteString,
          comdat :: Maybe ShortByteString,
          alignment :: Word32,
          garbageCollectorName :: Maybe ShortByteString,
          prefix :: Maybe Constant,
          basicBlocks :: [BasicBlock],
          personalityFunction :: Maybe Constant,
          metadata :: [(ShortByteString, MDRef MDNode)]
        }
    deriving (Eq, Read, Show, Typeable, Data, Generic)
  
  -- | 'Parameter's for 'Function's
  data Parameter = Parameter Type Name [A.ParameterAttribute]
    deriving (Eq, Read, Show, Typeable, Data, Generic)
  
  -- | <http://llvm.org/doxygen/classllvm_1_1BasicBlock.html>
  -- LLVM code in a function is a sequence of 'BasicBlock's each with a label,
  -- some instructions, and a terminator.
  data BasicBlock = BasicBlock Name [Named Instruction] (Named Terminator)
    deriving (Eq, Read, Show, Typeable, Data, Generic)
  
  data UnnamedAddr = LocalAddr | GlobalAddr
    deriving (Eq, Read, Show, Typeable, Data, Generic)
  
  -- | helper for making 'GlobalVariable's
  globalVariableDefaults :: Global
  globalVariableDefaults = 
    GlobalVariable {
    name = error "global variable name not defined",
    linkage = L.External,
    visibility = V.Default,
    dllStorageClass = Nothing,
    threadLocalMode = Nothing,
    addrSpace = AddrSpace 0,
    unnamedAddr = Nothing,
    isConstant = False,
    type' = error "global variable type not defined",
    initializer = Nothing,
    section = Nothing,
    comdat = Nothing,
    alignment = 0,
    metadata = []
    }
  
  -- | helper for making 'GlobalAlias's
  globalAliasDefaults :: Global
  globalAliasDefaults =
    GlobalAlias {
      name = error "global alias name not defined",
      linkage = L.External,
      visibility = V.Default,
      dllStorageClass = Nothing,
      threadLocalMode = Nothing,
      unnamedAddr = Nothing,
      type' = error "global alias type not defined",
      addrSpace = AddrSpace 0,
      aliasee = error "global alias aliasee not defined"
    }
  
  -- | helper for making 'Function's
  functionDefaults :: Global
  functionDefaults = 
    Function {
      linkage = L.External,
      visibility = V.Default,
      dllStorageClass = Nothing,
      callingConvention = CC.C,
      returnAttributes = [],
      returnType = error "function return type not defined",
      name = error "function name not defined",
      parameters = ([], False),
      functionAttributes = [],
      section = Nothing,
      comdat = Nothing,
      alignment = 0,
      garbageCollectorName = Nothing,
      prefix = Nothing,
      basicBlocks = [],
      personalityFunction = Nothing,
      metadata = []
    }
  