content: 
  module DDC.Driver.Config
          ( Config        (..)
  
          , ConfigPretty  (..)
          , defaultConfigPretty
          , prettyModeOfConfig
          , objectPathsOfConfig
          , exePathOfConfig
  
          , ViaBackend    (..)
          , RuntimeLinkStrategy (..))
  where
  import DDC.Build.Builder
  import DDC.Core.Simplifier              (Simplifier)
  import DDC.Core.Codec.Text.Pretty       hiding ((</>))
  import DDC.Core.Module
  import System.FilePath
  import Data.Maybe
  import qualified DDC.Core.Salt.Runtime  as Salt
  import qualified DDC.Core.Salt          as Salt
  
  
  ---------------------------------------------------------------------------------------------------
  -- | Configuration for main compiler stages.
  data Config
          = Config
          { -- | Print status to console during builds.
            configLogBuild                :: Bool
  
            -- | Dump intermediate code.
          , configDump                    :: Bool
  
            -- | Use bidirectional type inference on the input code.
          , configInferTypes              :: Bool
  
            -- | Simplifiers to apply to intermediate code
          , configSimplSalt               :: Simplifier Int () Salt.Name
  
            -- | Backend code generator to use
          , configViaBackend              :: ViaBackend
  
            -- | Runtime system configuration
          , configRuntime                 :: Salt.Config
  
            -- | Linking strategy for the runtime.
          , configRuntimeLinkStrategy     :: RuntimeLinkStrategy
  
            -- | The builder to use for the target architecture
          , configBuilder                 :: Builder
  
            -- | Core langauge pretty printer configuration.
          , configPretty                  :: ConfigPretty
  
            -- | Suppress the #import prelude in C modules
          , configSuppressHashImports     :: Bool
  
            -- | Base directories to look for modules sources during build.
          , configModuleBaseDirectories   :: [FilePath]
  
            -- | Override output file
          , configOutputFile              :: Maybe FilePath
  
            -- | Override directory for build products
          , configOutputDir               :: Maybe FilePath
  
            -- | Keep intermediate .ddc.ll files
          , configKeepLlvmFiles           :: Bool
  
            -- | Keep intermediate .ddc.c files
          , configKeepSeaFiles            :: Bool
  
            -- | Keep intermediate .ddc.s files
          , configKeepAsmFiles            :: Bool
  
            -- | Avoid running the type checker where possible.
            --   When debugging program transformations, use this to get
            --   the invalid code rather than just the type error message.
          , configTaintAvoidTypeChecks    :: Bool
          }
  
  ---------------------------------------------------------------------------------------------------
  -- | Core language pretty printer configuration.
  data ConfigPretty
          = ConfigPretty
          { configPrettyUseLetCase        :: Bool
          , configPrettyVarTypes          :: Bool
          , configPrettyConTypes          :: Bool
          , configPrettySuppressImports   :: Bool
          , configPrettySuppressExports   :: Bool
          , configPrettySuppressLetTypes  :: Bool }
  
  
  -- | Default pretty printer configuration.
  defaultConfigPretty :: ConfigPretty
  defaultConfigPretty
          = ConfigPretty
          { configPrettyUseLetCase        = False
          , configPrettyVarTypes          = False
          , configPrettyConTypes          = False
          , configPrettySuppressImports   = False
          , configPrettySuppressExports   = False
          , configPrettySuppressLetTypes  = False }
  
  
  -- | Convert a the pretty configuration into the mode to use to print a module.
  --   We keep the 'ConfigPretty' type separate from PrettyMode because the
  --   former can be non-recursive with other types, and does not need to be
  --   parameterised by the annotation or name types.
  prettyModeOfConfig
          :: ConfigPretty -> PrettyMode (Module a n)
  
  prettyModeOfConfig config
   = modeModule
   where
          modeModule
           = PrettyModeModule
           { modeModuleLets               = modeLets
           , modeModuleSuppressImports    = configPrettySuppressImports config
           , modeModuleSuppressExports    = configPrettySuppressExports config }
  
          modeExp
           = PrettyModeExp
           { modeExpLets                  = modeLets
           , modeExpAlt                   = modeAlt
           , modeExpConTypes              = configPrettyConTypes config
           , modeExpVarTypes              = configPrettyVarTypes config
           , modeExpUseLetCase            = configPrettyUseLetCase config }
  
          modeLets
           = PrettyModeLets
           { modeLetsExp                  = modeExp
           , modeLetsSuppressTypes        = configPrettySuppressLetTypes config
           , modeLetsColumnTypes          = False }
  
          modeAlt
           = PrettyModeAlt
           { modeAltExp                   = modeExp }
  
  
  -- | Given the name of a source file,
  --   determine the where the object files should go.
  --
  --   The first component of the result is where we should put produced object files,
  --   The second are paths of where we might find pre-existing objects,
  --   in preference order.
  
  objectPathsOfConfig
          :: Config       -- ^ Compiler config.
          -> FilePath     -- ^ Path to module source.
          -> (FilePath, [FilePath])
  
  objectPathsOfConfig config pathSource
   | Just dirOutput       <- configOutputDir config
   , takeFileName pathSource == "Main.ds"
   =      (dirOutput </> "Main.ds", [])
  
   | Just dirOutput       <- configOutputDir config
   = let  oFileSource     = replaceExtension pathSource ".o"
          oFileOverride   = dirOutput </> replaceExtension pathSource ".o"
     in   (oFileOverride, [oFileSource])
  
   | otherwise
   = let  oFileSource     = replaceExtension pathSource ".o"
     in   (oFileSource,   [])
  
  
  -- | Given the name of a source file,
  --   determine where we should put an executable built from it.
  exePathOfConfig
          :: Config       -- ^ Compiler config.
          -> FilePath     -- ^ Path to module source.
          -> FilePath
  
  exePathOfConfig config path
   = let  (oPath, _)      = objectPathsOfConfig config path
          exePathDefault  = dropExtension oPath
     in   fromMaybe exePathDefault (configOutputFile config)
  
  
  
  ---------------------------------------------------------------------------------------------------
  data ViaBackend
          -- | Compile via the LLVM backend.
          = ViaLLVM
          deriving Show
  
  
  
  data RuntimeLinkStrategy
          -- | Use the platform's default strategy.
          = LinkDefault
  
          -- | Link the runtime statically.
          | LinkStatic
          deriving (Show, Eq)
  