    {-# LANGUAGE CPP, TupleSections #-}
    {-# OPTIONS_GHC -fno-cse #-}
    -- -fno-cse is needed for GLOBAL_VAR's to behave properly

    -----------------------------------------------------------------------------
    --
    -- Static flags
    --
    -- Static flags can only be set once, on the command-line.  Inside GHC,
    -- each static flag corresponds to a top-level value, usually of type Bool.
    --
    -- (c) The University of Glasgow 2005
    --
    -----------------------------------------------------------------------------

    module StaticFlags (
            -- entry point
            parseStaticFlags,

            staticFlags,
            initStaticOpts,
            discardStaticFlags,

            -- Output style options
            opt_PprStyle_Debug,
            opt_NoDebugOutput,

            -- optimisation opts
            opt_NoStateHack,
            opt_CprOff,
            opt_NoOptCoercion,

            -- For the parser
            addOpt, removeOpt, v_opt_C_ready,

            -- For options autocompletion
            flagsStatic, flagsStaticNames
      ) where

    #include "HsVersions.h"

    import CmdLineParser
    import FastString
    import SrcLoc
    import Util
    -- import Maybes                ( firstJusts )
    import Panic

    import Control.Monad
    import Data.IORef
    import System.IO.Unsafe ( unsafePerformIO )

    -----------------------------------------------------------------------------
    -- Static flags

    -- | Parses GHC's static flags from a list of command line arguments.
    --
    -- These flags are static in the sense that they can be set only once and they
    -- are global, meaning that they affect every instance of GHC running;
    -- multiple GHC threads will use the same flags.
    --
    -- This function must be called before any session is started, i.e., before
    -- the first call to 'GHC.withGhc'.
    --
    -- Static flags are more of a hack and are static for more or less historical
    -- reasons.  In the long run, most static flags should eventually become
    -- dynamic flags.
    --
    -- XXX: can we add an auto-generated list of static flags here?
    --
    parseStaticFlags :: [Located String] -> IO ([Located String], [Located String])
    parseStaticFlags = parseStaticFlagsFull flagsStatic

    -- | Parse GHC's static flags as @parseStaticFlags@ does. However it also
    -- takes a list of available static flags, such that certain flags can be
    -- enabled or disabled through this argument.
    parseStaticFlagsFull :: [Flag IO] -> [Located String]
                         -> IO ([Located String], [Located String])
    parseStaticFlagsFull flagsAvailable args = do
      ready <- readIORef v_opt_C_ready
      when ready $ throwGhcExceptionIO (ProgramError "Too late for parseStaticFlags: call it before runGhc or runGhcT")

      (leftover, errs, warns) <- processArgs flagsAvailable args

      -- See Note [Handling errors when parsing commandline flags]
      unless (null errs) $ throwGhcExceptionIO $
          errorsToGhcException . map (("on the commandline", ) . unLoc) $ errs

        -- see sanity code in staticOpts
      writeIORef v_opt_C_ready True
      return (leftover, warns)

    -- holds the static opts while they're being collected, before
    -- being unsafely read by unpacked_static_opts below.
    GLOBAL_VAR(v_opt_C, [], [String])
    GLOBAL_VAR(v_opt_C_ready, False, Bool)

    staticFlags :: [String]
    staticFlags = unsafePerformIO $ do
      ready <- readIORef v_opt_C_ready
      if (not ready)
            then panic "Static flags have not been initialised!\n        Please call GHC.parseStaticFlags early enough."
            else readIORef v_opt_C

    -- All the static flags should appear in this list.  It describes how each
    -- static flag should be processed.  Two main purposes:
    -- (a) if a command-line flag doesn't appear in the list, GHC can complain
    -- (b) a command-line flag may remove, or add, other flags; e.g. the "-fno-X"
    --     things
    --
    -- The common (PassFlag addOpt) action puts the static flag into the bunch of
    -- things that are searched up by the top-level definitions like
    --      opt_foo = lookUp (fsLit "-dfoo")

    -- Note that ordering is important in the following list: any flag which
    -- is a prefix flag (i.e. HasArg, Prefix, OptPrefix, AnySuffix) will override
    -- flags further down the list with the same prefix.

    -- see Note [Updating flag description in the User's Guide] in DynFlags
    flagsStatic :: [Flag IO]
    flagsStatic = [
      ------ Debugging ----------------------------------------------------
        defFlag "dppr-debug"       (PassFlag addOptEwM)
      , defFlag "dno-debug-output" (PassFlag addOptEwM)
      -- rest of the debugging flags are dynamic

      ------ Compiler flags -----------------------------------------------
      -- All other "-fno-<blah>" options cancel out "-f<blah>" on the hsc cmdline
      , defFlag "fno-"
             (PrefixPred (\s -> isStaticFlag ("f"++s)) (\s -> removeOptEwM ("-f"++s)))

      -- Pass all remaining "-f<blah>" options to hsc
      , defFlag "f" (AnySuffixPred isStaticFlag addOptEwM)
      ]

    isStaticFlag :: String -> Bool
    isStaticFlag f = f `elem` flagsStaticNames

    -- see Note [Updating flag description in the User's Guide] in DynFlags
    flagsStaticNames :: [String]
    flagsStaticNames = [
        "fno-state-hack",
        "fno-opt-coercion",
        "fcpr-off"
        ]

    -- We specifically need to discard static flags for clients of the
    -- GHC API, since they can't be safely reparsed or reinitialized. In general,
    -- the existing flags do nothing other than control debugging and some low-level
    -- optimizer phases, so for the most part this is OK.
    --
    -- See GHC issue #8276: http://ghc.haskell.org/trac/ghc/ticket/8276#comment:37
    discardStaticFlags :: [String] -> [String]
    discardStaticFlags = filter (\x -> x `notElem` flags)
      where flags = [ "-fno-state-hack"
                    , "-fno-opt-coercion"
                    , "-fcpr-off"
                    , "-dppr-debug"
                    , "-dno-debug-output"
                    ]

    initStaticOpts :: IO ()
    initStaticOpts = writeIORef v_opt_C_ready True

    addOpt :: String -> IO ()
    addOpt = consIORef v_opt_C

    removeOpt :: String -> IO ()
    removeOpt f = do
      fs <- readIORef v_opt_C
      writeIORef v_opt_C $! filter (/= f) fs

    type StaticP = EwM IO

    addOptEwM :: String -> StaticP ()
    addOptEwM = liftEwM . addOpt

    removeOptEwM :: String -> StaticP ()
    removeOptEwM = liftEwM . removeOpt

    packed_static_opts :: [FastString]
    packed_static_opts   = map mkFastString staticFlags

    lookUp :: FastString -> Bool
    lookUp sw = sw `elem` packed_static_opts

    -- debugging options

    -- see Note [Updating flag description in the User's Guide] in DynFlags

    opt_PprStyle_Debug :: Bool
    opt_PprStyle_Debug = lookUp  (fsLit "-dppr-debug")

    opt_NoDebugOutput  :: Bool
    opt_NoDebugOutput  = lookUp  (fsLit "-dno-debug-output")

    opt_NoStateHack    :: Bool
    opt_NoStateHack    = lookUp  (fsLit "-fno-state-hack")

    -- Switch off CPR analysis in the new demand analyser
    opt_CprOff         :: Bool
    opt_CprOff         = lookUp  (fsLit "-fcpr-off")

    opt_NoOptCoercion  :: Bool
    opt_NoOptCoercion  = lookUp  (fsLit "-fno-opt-coercion")

    {-
    -- (lookup_str "foo") looks for the flag -foo=X or -fooX,
    -- and returns the string X
    lookup_str       :: String -> Maybe String
    lookup_str sw
       = case firstJusts (map (stripPrefix sw) staticFlags) of
            Just ('=' : str) -> Just str
            Just str         -> Just str
            Nothing          -> Nothing

    lookup_def_int   :: String -> Int -> Int
    lookup_def_int sw def = case (lookup_str sw) of
                                Nothing -> def              -- Use default
                                Just xx -> try_read sw xx

    lookup_def_float :: String -> Float -> Float
    lookup_def_float sw def = case (lookup_str sw) of
                                Nothing -> def              -- Use default
                                Just xx -> try_read sw xx

    try_read :: Read a => String -> String -> a
    -- (try_read sw str) tries to read s; if it fails, it
    -- bleats about flag sw
    try_read sw str
      = case reads str of
            ((x,_):_) -> x  -- Be forgiving: ignore trailing goop, and alternative parses
            []        -> throwGhcException (UsageError ("Malformed argument " ++ str ++ " for flag " ++ sw))
                            -- ToDo: hack alert. We should really parse the arguments
                            --       and announce errors in a more civilised way.
    -}