{-# LANGUAGE ImportQualifiedPost #-}
module Extension(
  defaultExtensions,
  configExtensions,
  extensionImpliedEnabledBy,
  extensionImplies
  ) where

import Data.List.Extra
import Data.Map qualified as Map
import GHC.LanguageExtensions.Type
import Language.Haskell.GhclibParserEx.GHC.Driver.Session qualified as GhclibParserEx

badExtensions :: [Extension]
badExtensions =
  [Extension]
reallyBadExtensions [Extension] -> [Extension] -> [Extension]
forall a. [a] -> [a] -> [a]
++
  [ Extension
Arrows -- steals proc
  , Extension
UnboxedTuples, Extension
UnboxedSums -- breaks (#) lens operator
  , Extension
QuasiQuotes -- breaks [x| ...], making whitespace free list comps break
  , {- DoRec , -} Extension
RecursiveDo -- breaks rec
  , Extension
LexicalNegation -- changes '-', see https://github.com/ndmitchell/hlint/issues/1230
  -- These next two change syntax significantly and must be opt-in.
  , Extension
OverloadedRecordDot
  , Extension
OverloadedRecordUpdate
  ]

reallyBadExtensions :: [Extension]
reallyBadExtensions =
  [ Extension
TransformListComp -- steals the group keyword
  , Extension
StaticPointers -- steals the static keyword
  {- , XmlSyntax , RegularPatterns -} -- steals a-b and < operators
  , Extension
AlternativeLayoutRule -- Does not play well with 'MultiWayIf'
  , Extension
NegativeLiterals -- Was not enabled by HSE and enabling breaks tests.
  , Extension
StarIsType -- conflicts with TypeOperators. StarIsType is currently enabled by default,
               -- so adding it here has no effect, but it may not be the case in future GHC releases.
  , Extension
MonadComprehensions -- Discussed in https://github.com/ndmitchell/hlint/issues/1261
  ]

-- | Extensions we turn on by default when parsing. Aim to parse as
-- many files as we can.
defaultExtensions :: [Extension]
defaultExtensions :: [Extension]
defaultExtensions = [Extension]
forall a. (Enum a, Bounded a) => [a]
enumerate [Extension] -> [Extension] -> [Extension]
forall a. Eq a => [a] -> [a] -> [a]
\\ [Extension]
badExtensions

-- | Extensions we turn on when reading config files, don't have to deal with the whole world
--   of variations - in particular, we might require spaces in some places.
configExtensions :: [Extension]
configExtensions :: [Extension]
configExtensions = [Extension]
forall a. (Enum a, Bounded a) => [a]
enumerate [Extension] -> [Extension] -> [Extension]
forall a. Eq a => [a] -> [a] -> [a]
\\ [Extension]
reallyBadExtensions

-- | This extension implies the following extensions are
-- enabled/disabled.
extensionImplies :: Extension -> ([Extension], [Extension])
extensionImplies :: Extension -> ([Extension], [Extension])
extensionImplies = \Extension
x ->([Extension], [Extension])
-> Extension
-> Map Extension ([Extension], [Extension])
-> ([Extension], [Extension])
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault ([], []) Extension
x Map Extension ([Extension], [Extension])
mp
  where mp :: Map Extension ([Extension], [Extension])
mp = [(Extension, ([Extension], [Extension]))]
-> Map Extension ([Extension], [Extension])
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Extension, ([Extension], [Extension]))]
extensionImplications

-- 'x' is implied enabled by the result extensions.
extensionImpliedEnabledBy :: Extension -> [Extension]
extensionImpliedEnabledBy :: Extension -> [Extension]
extensionImpliedEnabledBy = \Extension
x -> [Extension]
-> Extension -> Map Extension [Extension] -> [Extension]
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault [] Extension
x Map Extension [Extension]
mp
  where
    mp :: Map Extension [Extension]
mp = ([Extension] -> [Extension] -> [Extension])
-> [(Extension, [Extension])] -> Map Extension [Extension]
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith [Extension] -> [Extension] -> [Extension]
forall a. [a] -> [a] -> [a]
(++) [(Extension
b, [Extension
a]) | (Extension
a, ([Extension]
bs, [Extension]
_)) <- [(Extension, ([Extension], [Extension]))]
extensionImplications, Extension
b <- [Extension]
bs]

-- 'x' is implied disabled by the result extensions. Not called at this time.
_extensionImpliedDisabledBy :: Extension -> [Extension]
_extensionImpliedDisabledBy :: Extension -> [Extension]
_extensionImpliedDisabledBy = \Extension
x -> [Extension]
-> Extension -> Map Extension [Extension] -> [Extension]
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault [] Extension
x Map Extension [Extension]
mp
  where
    mp :: Map Extension [Extension]
mp = ([Extension] -> [Extension] -> [Extension])
-> [(Extension, [Extension])] -> Map Extension [Extension]
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith [Extension] -> [Extension] -> [Extension]
forall a. [a] -> [a] -> [a]
(++) [(Extension
b, [Extension
a]) | (Extension
a, ([Extension]
_, [Extension]
bs)) <- [(Extension, ([Extension], [Extension]))]
extensionImplications, Extension
b <- [Extension]
bs]

-- | (a, bs) means extension a implies all of bs. Uses GHC source at
-- DynFlags.impliedXFlags
extensionImplications :: [(Extension, ([Extension], [Extension]))]
extensionImplications :: [(Extension, ([Extension], [Extension]))]
extensionImplications = [(Extension, ([Extension], [Extension]))]
GhclibParserEx.extensionImplications