2017-03-06 23:19:57 +00:00
|
|
|
-- ghc-mod: Happy Haskell Hacking
|
2016-02-14 07:41:11 +00:00
|
|
|
-- Copyright (C) 2015 Daniel Gröber <dxld ÄT darkboxed DOT org>
|
|
|
|
--
|
|
|
|
-- This program is free software: you can redistribute it and/or modify
|
|
|
|
-- it under the terms of the GNU Affero General Public License as published by
|
|
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
|
|
|
-- (at your option) any later version.
|
|
|
|
--
|
|
|
|
-- This program is distributed in the hope that it will be useful,
|
|
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
-- GNU Affero General Public License for more details.
|
|
|
|
--
|
|
|
|
-- You should have received a copy of the GNU Affero General Public License
|
|
|
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2017-05-03 09:56:51 +00:00
|
|
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
2016-02-14 07:59:59 +00:00
|
|
|
{-# LANGUAGE CPP, TemplateHaskell #-}
|
2017-05-03 09:56:51 +00:00
|
|
|
{-# LANGUAGE StandaloneDeriving #-}
|
|
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
2017-05-28 02:22:56 +00:00
|
|
|
module GhcMod.DynFlagsTH where
|
2016-02-14 07:41:11 +00:00
|
|
|
|
2016-07-16 01:32:26 +00:00
|
|
|
import Language.Haskell.TH
|
2016-02-14 07:41:11 +00:00
|
|
|
import Language.Haskell.TH.Syntax
|
2016-02-14 07:59:59 +00:00
|
|
|
import Control.Applicative
|
2017-05-03 11:33:52 +00:00
|
|
|
import qualified Data.IntSet as IS
|
2016-02-14 07:41:11 +00:00
|
|
|
import Data.Maybe
|
|
|
|
import Data.Generics.Aliases
|
|
|
|
import Data.Generics.Schemes
|
|
|
|
import DynFlags
|
2016-02-14 07:59:59 +00:00
|
|
|
import Prelude
|
2016-02-14 07:41:11 +00:00
|
|
|
|
2017-05-03 09:56:51 +00:00
|
|
|
-- -------------------------------------
|
|
|
|
|
2016-02-14 07:41:11 +00:00
|
|
|
deriveEqDynFlags :: Q [Dec] -> Q [Dec]
|
|
|
|
deriveEqDynFlags qds = do
|
2016-02-14 11:24:33 +00:00
|
|
|
#if __GLASGOW_HASKELL__ <= 710
|
|
|
|
~(TyConI (DataD [] _ [] [ctor] _ ))
|
|
|
|
#else
|
|
|
|
~(TyConI (DataD [] _ [] _ [ctor] _ ))
|
|
|
|
#endif
|
|
|
|
<- reify ''DynFlags
|
2016-02-14 07:41:11 +00:00
|
|
|
let ~(RecC _ fs) = ctor
|
|
|
|
|
|
|
|
a <- newName "a"
|
|
|
|
b <- newName "b"
|
|
|
|
|
2017-05-03 09:56:51 +00:00
|
|
|
-- let combFunc = [| \(bs,ss) -> (and bs, unwords ss) |]
|
|
|
|
|
|
|
|
-- e <- AppE (VarE 'and) . ListE <$> sequence (mapMaybe (eq a b) fs)
|
|
|
|
-- e <- AppE (combFunc) . ListE <$> sequence $ combFunc (catMaybes $ map (eq a b) fs)
|
|
|
|
e <- ListE <$> sequence (mapMaybe (eq a b) fs)
|
2016-02-14 07:41:11 +00:00
|
|
|
|
|
|
|
tysig@(SigD n _) :_ <- qds
|
|
|
|
|
|
|
|
return $ [tysig, FunD n [Clause [VarP a, VarP b] (NormalB e) []]]
|
|
|
|
|
|
|
|
where
|
|
|
|
eq :: Name -> Name -> (Name, Strict, Type) -> Maybe (Q Exp)
|
2016-07-16 01:32:26 +00:00
|
|
|
eq a b (fun@(Name (OccName fon) _), _, ft)
|
2016-02-14 07:59:59 +00:00
|
|
|
| not (isUneqable || isIgnored) = Just expr
|
2016-02-14 07:41:11 +00:00
|
|
|
| otherwise = Nothing
|
|
|
|
where
|
|
|
|
isUneqable = everything (||) (mkQ False hasUnEqable) ft
|
|
|
|
|
2016-07-16 01:32:26 +00:00
|
|
|
hasUnEqable (AppT (ConT (Name (OccName on) _)) _)
|
|
|
|
| any (==on) ignoredConstructorNames = True
|
2016-02-14 07:59:59 +00:00
|
|
|
hasUnEqable (ConT (Name (OccName on) _))
|
|
|
|
| any (==on) ignoredTypeNames = True
|
2016-02-14 07:41:11 +00:00
|
|
|
| any (==on) ignoredTypeOccNames = True
|
|
|
|
hasUnEqable _ = False
|
|
|
|
|
2016-02-14 07:59:59 +00:00
|
|
|
isIgnored = fon `elem` ignoredNames
|
|
|
|
|
2016-07-16 01:32:26 +00:00
|
|
|
ignoredConstructorNames = [ "IORef" ]
|
|
|
|
|
2016-02-14 07:59:59 +00:00
|
|
|
ignoredNames = [ "pkgDatabase" -- 7.8
|
|
|
|
#if __GLASGOW_HASKELL__ <= 706
|
|
|
|
, "ways" -- 'Ways' is not exported :/
|
|
|
|
#endif
|
|
|
|
]
|
2016-02-14 07:41:11 +00:00
|
|
|
ignoredTypeNames =
|
2016-02-14 07:59:59 +00:00
|
|
|
[ "LogAction"
|
|
|
|
, "PackageState"
|
|
|
|
, "Hooks"
|
|
|
|
, "FlushOut"
|
|
|
|
, "FlushErr"
|
|
|
|
, "Settings" -- I think these can't cange at runtime
|
2016-02-14 07:41:11 +00:00
|
|
|
]
|
|
|
|
ignoredTypeOccNames = [ "OnOff" ]
|
|
|
|
|
2016-07-16 01:32:26 +00:00
|
|
|
fa = AppE (VarE fun) (VarE a)
|
|
|
|
fb = AppE (VarE fun) (VarE b)
|
2016-02-14 07:41:11 +00:00
|
|
|
expr =
|
|
|
|
case fon of
|
|
|
|
"rtsOptsEnabled" -> do
|
2017-05-03 09:56:51 +00:00
|
|
|
let eqfn = [| let fn RtsOptsNone RtsOptsNone = [(True, "")]
|
|
|
|
fn RtsOptsSafeOnly RtsOptsSafeOnly = [(True, "")]
|
|
|
|
fn RtsOptsAll RtsOptsAll = [(True, "")]
|
|
|
|
fn _ _ = [(False, "rtsOptsEnabled changed")]
|
2016-07-16 01:32:26 +00:00
|
|
|
in fn
|
|
|
|
|]
|
|
|
|
[e| $(eqfn) $(return fa) $(return fb) |]
|
|
|
|
|
|
|
|
"extraPkgConfs" -> do
|
2017-05-03 09:56:51 +00:00
|
|
|
-- let eqfn = [| let fn a' b' = and (zipWith eqpr (a' []) (b' []))
|
|
|
|
-- && length (a' []) == length (b' [])
|
|
|
|
let eqfn = [| let fn a' b' = cond a' b'
|
|
|
|
|
|
|
|
cond a' b' = zz ++ ll
|
|
|
|
where
|
|
|
|
zz :: [(Bool,String)]
|
|
|
|
zz = (zipWith eqpr (a' []) (b' []))
|
|
|
|
|
|
|
|
ll :: [(Bool,String)]
|
|
|
|
ll = [( length (a' []) == length (b' [])
|
|
|
|
, if length (a' []) == length (b' []) then "" else "extraPkgConfs length mismatch")]
|
|
|
|
|
|
|
|
eqpr GlobalPkgConf GlobalPkgConf = (True, "")
|
|
|
|
eqpr UserPkgConf UserPkgConf = (True, "")
|
|
|
|
eqpr (PkgConfFile pa) (PkgConfFile pb) = (pa == pb,if pa == pb then "" else "extraPkgConfs changed")
|
|
|
|
eqpr _ _ = (False, "extraPkgConfs changed")
|
2016-07-16 01:32:26 +00:00
|
|
|
in fn
|
|
|
|
|]
|
|
|
|
[e| $(eqfn) $(return fa) $(return fb) |]
|
2016-02-14 07:41:11 +00:00
|
|
|
|
2016-02-14 11:24:33 +00:00
|
|
|
#if __GLASGOW_HASKELL__ >= 710 && __GLASGOW_HASKELL__ < 800
|
2016-02-14 07:41:11 +00:00
|
|
|
"sigOf" -> do
|
2017-05-03 09:56:51 +00:00
|
|
|
let eqfn = [| let fn NotSigOf NotSigOf = [(True, "")]
|
|
|
|
fn (SigOf a') (SigOf b') = [(a' == b', if a' == b' then "" else "sigOf changed")]
|
|
|
|
fn (SigOfMap a') (SigOfMap b') = [(a' == b', if a' == b' then "" else "sigOfMap changed")]
|
|
|
|
fn _ _ = [(False, "sigOf changed")]
|
2016-07-16 01:32:26 +00:00
|
|
|
in fn
|
|
|
|
|]
|
|
|
|
[e| $(eqfn) $(return fa) $(return fb) |]
|
2016-02-14 07:59:59 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if __GLASGOW_HASKELL <= 706
|
|
|
|
"profAuto" -> do
|
2017-05-03 09:56:51 +00:00
|
|
|
let eqfn = [| let fn NoProfAuto NoProfAuto = [(True, "")]
|
|
|
|
fn ProfAutoAll ProfAutoAll = [(True, "")]
|
|
|
|
fn ProfAutoTop ProfAutoTop = [(True, "")]
|
|
|
|
fn ProfAutoExports ProfAutoExports = [(True, "")]
|
|
|
|
fn ProfAutoCalls ProfAutoCalls = [(True, "")]
|
|
|
|
fn _ _ = [(False, "profAuto changed")]
|
2016-07-16 01:32:26 +00:00
|
|
|
in fn
|
|
|
|
|]
|
|
|
|
[e| $(eqfn) $(return fa) $(return fb) |]
|
2016-02-14 07:59:59 +00:00
|
|
|
#endif
|
2016-02-14 07:41:11 +00:00
|
|
|
|
2016-02-14 07:59:59 +00:00
|
|
|
#if __GLASGOW_HASKELL__ >= 706
|
|
|
|
"language" -> do
|
2017-05-03 09:56:51 +00:00
|
|
|
let eqfn = [| let fn (Just Haskell98) (Just Haskell98) = [(True, "")]
|
|
|
|
fn (Just Haskell2010) (Just Haskell2010) = [(True, "")]
|
|
|
|
fn Nothing Nothing = [(True, "")]
|
|
|
|
fn _ _ = [(False, "language changed")]
|
2016-07-16 01:32:26 +00:00
|
|
|
in fn
|
|
|
|
|]
|
|
|
|
[e| $(eqfn) $(return fa) $(return fb) |]
|
2016-02-14 07:59:59 +00:00
|
|
|
#endif
|
2016-02-14 07:41:11 +00:00
|
|
|
|
2017-05-03 11:33:52 +00:00
|
|
|
"generalFlags" -> checkIntSet "generalFlags"
|
|
|
|
|
|
|
|
"warningFlags" -> checkIntSet "warningFlags"
|
|
|
|
|
2016-02-14 07:41:11 +00:00
|
|
|
_ ->
|
2017-05-03 11:33:52 +00:00
|
|
|
[e| [($(return fa) == $(return fb), if $(return fa) == $(return fb) then "" else ("default changed:" ++ fon) )] |]
|
2016-07-16 01:32:26 +00:00
|
|
|
|
2017-05-03 11:33:52 +00:00
|
|
|
checkIntSet fieldName = do
|
|
|
|
let eqfn = [| let fn aa bb = r
|
|
|
|
where
|
|
|
|
uni = IS.union aa bb
|
|
|
|
dif = IS.intersection aa bb
|
|
|
|
delta = IS.difference uni dif
|
|
|
|
-- deltaStr = show $ map toEnum $( (IS.toList delta) :: [GeneralFlag] )
|
|
|
|
r = if delta == IS.empty
|
|
|
|
then [(True, "")]
|
|
|
|
-- else [(False, "generalFlags:delta=" ++ deltaStr )]
|
|
|
|
else [(False, fieldName ++ ":delta=" ++ (show delta) )]
|
|
|
|
in fn
|
|
|
|
|]
|
|
|
|
[e| $(eqfn) $(return fa) $(return fb) |]
|