happstack-data-0.1: src/HAppS/Data/DeriveAll.hs
{-# LANGUAGE TemplateHaskell, CPP #-}
{-# OPTIONS_GHC -Wall -Werror #-}
-----------------------------------------------------------------------------
-- |
-- Module : HAppS.Data.DeriveAll
-- Copyright : (c) 2007 HAppS LLC
-- License : BSD3
--
-- Maintainer : AlexJacobson@HAppS.org
-- Stability : experimental
-- Portability : Not portable
--
-- Concisely specify which classes to derive for your datatypes.
-- As well as the standard derivable classes, it can also
-- derive syb-with-class's 'New.Data' class and HAppS.Data.Default's
-- 'Default' class.
--
-----------------------------------------------------------------------------
module HAppS.Data.DeriveAll (deriveAll, deriveNewData, deriveNewDataNoDefault)
where
import qualified Data.Generics as Old
import Data.Generics.SYB.WithClass.Derive
import Data.List
import HAppS.Data.Default
import Language.Haskell.TH
deriveNewData :: [Name] -> Q [Dec]
deriveNewData names
= do nd <- deriveData names
defaults <- mapM mkDefaultInstance names
return (nd ++ concat defaults)
deriveNewDataNoDefault :: [Name] -> Q [Dec]
deriveNewDataNoDefault = deriveData
mkDefaultInstance :: Name -> Q [Dec]
mkDefaultInstance name
= do info <- reify name
case info of
TyConI (NewtypeD _ nm tvs _ _) -> return $ deriveDefault True tvs nm
TyConI (DataD _ nm tvs _ _) -> return $ deriveDefault True tvs nm
_ -> fail ("mkDefaultInstance: Bad info: " ++ pprint info)
-- | The 'deriveAll' function takes a list of classes to derive and
-- a block of declarations. It will additionally derive instances for
-- 'Typeable', 'Old.Data' and 'New.Data'.
--
-- Example:
--
-- > $( deriveAll [''Show, ''Eq, ''Default] [d|
-- > data Foo a = Foo a
-- > data Bar = Baz | Quux
-- > |] )
deriveAll :: [Name] -> Q [Dec] -> Q [Dec]
deriveAll classes0 qdecs
= do decs <- qdecs
derivedDecs <- deriveDec (filter isDataOrNewtype decs)
let (classDefault, classes1) = partition (''Default ==) classes0
classes2 = ''Old.Data : classes1
addDefaultInstance = not $ null classDefault
f = addDerivedClasses addDefaultInstance classes2
decs' = concatMap f decs
return (decs' ++ derivedDecs)
addDerivedClasses :: Bool -> [Name] -> Dec -> [Dec]
addDerivedClasses def cs (DataD ctxt nm tvs cons derivs)
= DataD ctxt nm tvs cons (cs ++ derivs)
: deriveDefault def tvs nm
addDerivedClasses def cs (NewtypeD ctxt nm tvs con derivs)
= NewtypeD ctxt nm tvs con (cs ++ derivs)
: deriveDefault def tvs nm
addDerivedClasses _ _ d = [d]
deriveDefault :: Bool -> [Name] -> Name -> [Dec]
deriveDefault False _ _ = []
deriveDefault True tvs n = [InstanceD context instanceHead []]
where tvs' = map VarT tvs
mkDef x = ConT ''Default `AppT` x
context = map mkDef tvs'
instanceHead = mkDef $ foldl AppT (ConT n) tvs'
isDataOrNewtype :: Dec -> Bool
isDataOrNewtype (DataD {}) = True
isDataOrNewtype (NewtypeD {}) = True
isDataOrNewtype _ = False