-- ghc-mod: Making Haskell development *more* fun -- Copyright (C) 2015 Daniel Gröber -- -- 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 . {-# LANGUAGE CPP, TemplateHaskell #-} module Language.Haskell.GhcMod.DynFlagsTH where import Language.Haskell.TH.Syntax import Control.Applicative import Data.Maybe import Data.Generics.Aliases import Data.Generics.Schemes import DynFlags import Prelude deriveEqDynFlags :: Q [Dec] -> Q [Dec] deriveEqDynFlags qds = do #if __GLASGOW_HASKELL__ <= 710 ~(TyConI (DataD [] _ [] [ctor] _ )) #else ~(TyConI (DataD [] _ [] _ [ctor] _ )) #endif <- reify ''DynFlags let ~(RecC _ fs) = ctor a <- newName "a" b <- newName "b" e <- AppE (VarE 'and) . ListE <$> sequence (catMaybes $ map (eq a b) fs) 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) eq a b (fn@(Name (OccName fon) _), _, ft) | not (isUneqable || isIgnored) = Just expr | otherwise = Nothing where isUneqable = everything (||) (mkQ False hasUnEqable) ft hasUnEqable ArrowT = True hasUnEqable (ConT (Name (OccName on) _)) | any (==on) ignoredTypeNames = True | any (==on) ignoredTypeOccNames = True hasUnEqable _ = False isIgnored = fon `elem` ignoredNames ignoredNames = [ "pkgDatabase" -- 7.8 #if __GLASGOW_HASKELL__ <= 706 , "ways" -- 'Ways' is not exported :/ #endif ] ignoredTypeNames = [ "LogAction" , "PackageState" , "Hooks" , "FlushOut" , "FlushErr" , "Settings" -- I think these can't cange at runtime ] ignoredTypeOccNames = [ "OnOff" ] fa = AppE (VarE fn) (VarE a) fb = AppE (VarE fn) (VarE b) expr = case fon of "rtsOptsEnabled" -> do eqfn <- [| let eqfn RtsOptsNone RtsOptsNone = True eqfn RtsOptsSafeOnly RtsOptsSafeOnly = True eqfn RtsOptsAll RtsOptsAll = True eqfn _ _ = False in eqfn |] return $ AppE (AppE eqfn fa) fb #if __GLASGOW_HASKELL__ >= 710 && __GLASGOW_HASKELL__ < 800 "sigOf" -> do eqfn <- [| let eqfn NotSigOf NotSigOf = True eqfn (SigOf a') (SigOf b') = a' == b' eqfn (SigOfMap a') (SigOfMap b') = a' == b' eqfn _ _ = False in eqfn |] return $ AppE (AppE eqfn fa) fb #endif #if __GLASGOW_HASKELL <= 706 "profAuto" -> do eqfn <- [| let eqfn NoProfAuto NoProfAuto = True eqfn ProfAutoAll ProfAutoAll = True eqfn ProfAutoTop ProfAutoTop = True eqfn ProfAutoExports ProfAutoExports = True eqfn ProfAutoCalls ProfAutoCalls = True eqfn _ _ = False in eqfn |] return $ AppE (AppE eqfn fa) fb #endif #if __GLASGOW_HASKELL__ >= 706 "language" -> do eqfn <- [| let eqfn (Just Haskell98) (Just Haskell98) = True eqfn (Just Haskell2010) (Just Haskell2010) = True eqfn _ _ = False in eqfn |] return $ AppE (AppE eqfn fa) fb #endif _ -> return $ InfixE (Just fa) (VarE '(==)) (Just fb)