content: 
  -- | A fragment profile determines what features a program can use.
  module DDC.Core.Fragment.Profile
          ( Profile (..)
          , mapFeaturesOfProfile
          , zeroProfile
  
          , Features(..)
          , zeroFeatures
          , setFeature)
  where
  import DDC.Core.Exp.Literal
  import DDC.Core.Fragment.Feature
  import DDC.Type.DataDef
  import DDC.Type.Exp
  import DDC.Type.Env                     (KindEnv, TypeEnv)
  import DDC.Data.SourcePos
  import qualified DDC.Type.Env           as Env
  
  
  -- | The fragment profile describes the language features and 
  --   primitive operators available in the language.
  data Profile n
          = Profile
          { -- | The name of this profile.
            profileName                   :: !String
  
            -- | Permitted language features.
          , profileFeatures               :: !Features
  
            -- | Primitive data type declarations.
          , profilePrimDataDefs           :: !(DataDefs n)
  
            -- | Kinds of primitive types.
          , profilePrimKinds              :: !(KindEnv n)
  
            -- | Types of primitive operators.
          , profilePrimTypes              :: !(TypeEnv n)
  
            -- | Check whether a type is an unboxed type.
            --   Some fragments limit how these can be used.
          , profileTypeIsUnboxed          :: !(Type n -> Bool) 
  
            -- | Check whether some name represents a hole that needs
            --   to be filled in by the type checker.
          , profileNameIsHole             :: !(Maybe (n -> Bool)) 
  
            -- | Convert a literal to a name,
            --   given the source position, literal value and whether
            --   the literal should be taken as a language primitive
            --   (with a trailing '#').
          , profileMakeLiteralName
                  :: Maybe (SourcePos -> Literal -> Bool -> Maybe n) }
  
  
  -- | Apply a function to the `Features` of a `Profile`.
  mapFeaturesOfProfile :: (Features -> Features) -> Profile n -> Profile n
  mapFeaturesOfProfile f profile
          = profile
          { profileFeatures       = f (profileFeatures profile) }
  
  
  -- | A language profile with no features or primitive operators.
  --
  --   This provides a simple first-order language.
  zeroProfile :: Profile n
  zeroProfile
          = Profile
          { profileName                   = "Zero"
          , profileFeatures               = zeroFeatures
          , profilePrimDataDefs           = emptyDataDefs
          , profilePrimKinds              = Env.empty
          , profilePrimTypes              = Env.empty
          , profileTypeIsUnboxed          = const False 
          , profileNameIsHole             = Nothing 
          , profileMakeLiteralName        = Nothing }
  
  
  -- | A flattened set of features, for easy lookup.
  data Features 
          = Features
          { featuresTrackedEffects        :: Bool
          , featuresTrackedClosures       :: Bool
          , featuresFunctionalEffects     :: Bool
          , featuresFunctionalClosures    :: Bool
          , featuresEffectCapabilities    :: Bool
          , featuresImplicitRun           :: Bool
          , featuresImplicitBox           :: Bool
          , featuresMetaVariables         :: Bool
          , featuresPartialPrims          :: Bool
          , featuresPartialApplication    :: Bool
          , featuresGeneralApplication    :: Bool
          , featuresNestedFunctions       :: Bool
          , featuresGeneralLetRec         :: Bool
          , featuresDebruijnBinders       :: Bool
          , featuresUnboundLevel0Vars     :: Bool
          , featuresNameShadowing         :: Bool
          , featuresUnusedBindings        :: Bool
          , featuresUnusedMatches         :: Bool
          }
  
  
  -- | An emtpy feature set, with all flags set to `False`.
  zeroFeatures :: Features
  zeroFeatures
          = Features
          { featuresTrackedEffects        = False
          , featuresTrackedClosures       = False
          , featuresFunctionalEffects     = False
          , featuresFunctionalClosures    = False
          , featuresEffectCapabilities    = False
          , featuresImplicitRun           = False
          , featuresImplicitBox           = False
          , featuresMetaVariables         = False
          , featuresPartialPrims          = False
          , featuresPartialApplication    = False
          , featuresGeneralApplication    = False
          , featuresNestedFunctions       = False
          , featuresGeneralLetRec         = False
          , featuresDebruijnBinders       = False
          , featuresUnboundLevel0Vars     = False
          , featuresNameShadowing         = False
          , featuresUnusedBindings        = False
          , featuresUnusedMatches         = False }
  
  
  -- | Set a language `Flag` in the `Profile`.
  setFeature :: Feature -> Bool -> Features -> Features
  setFeature feature val features
   = case feature of
          TrackedEffects          -> features { featuresTrackedEffects       = val }
          TrackedClosures         -> features { featuresTrackedClosures      = val }
          FunctionalEffects       -> features { featuresFunctionalEffects    = val }
          FunctionalClosures      -> features { featuresFunctionalClosures   = val }
          EffectCapabilities      -> features { featuresEffectCapabilities   = val }
          ImplicitRun             -> features { featuresImplicitRun          = val }
          ImplicitBox             -> features { featuresImplicitBox          = val }
          MetaVariables           -> features { featuresMetaVariables        = val }
          PartialPrims            -> features { featuresPartialPrims         = val }
          PartialApplication      -> features { featuresPartialApplication   = val }
          GeneralApplication      -> features { featuresGeneralApplication   = val }
          NestedFunctions         -> features { featuresNestedFunctions      = val }
          GeneralLetRec           -> features { featuresGeneralLetRec        = val }
          DebruijnBinders         -> features { featuresDebruijnBinders      = val }
          UnboundLevel0Vars       -> features { featuresUnboundLevel0Vars    = val }
          NameShadowing           -> features { featuresNameShadowing        = val }
          UnusedBindings          -> features { featuresUnusedBindings       = val }
          UnusedMatches           -> features { featuresUnusedMatches        = val }
  
  