module THUtils where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.ExpandSyns
import Control.Monad.Error
import Control.Applicative
import Data.Generics
import Control.Exception
import Data.List(intersperse)
import Data.Char(ord)
deriving instance Ord Type
#if __GLASGOW_HASKELL__ >= 611
deriving instance Ord Kind
deriving instance Ord Pred
deriving instance Ord TyVarBndr
deKindSigify :: TyVarBndr -> Name
deKindSigify (PlainTV t) = t
deKindSigify (KindedTV t _) = t
#else
deKindSigify :: Name -> Name
deKindSigify = id
#endif
(@@) = AppT
(@@@) = AppE
infixl 9 @@
infixl 9 @@@
data AppliedTyCon = AppliedTyCon {
atcHead :: Name
, atcArgs :: [Type]
}
deriving (Eq,Ord,Show,Data,Typeable)
normaliseSpecialTyCons :: (Data a) => a -> a
normaliseSpecialTyCons = everywhere (mkT f)
where
f ListT = ConT (''[])
f (TupleT n) = ConT (tupleTypeName n)
f ArrowT = ConT (''(->))
f x = x
toAppliedTyCon :: (MonadError String m) => Type -> Q (m AppliedTyCon)
toAppliedTyCon t = (go [] . normaliseSpecialTyCons) `fmap` expandSyns t
where
go acc (ConT n) = return (AppliedTyCon n acc)
go acc (AppT t1 t2) = go (t2:acc) t1
go acc other = throwError ("Expected applied type constructor, got: "
++ show (foldl AppT other acc))
fromAppliedTyCon :: AppliedTyCon -> Type
fromAppliedTyCon (AppliedTyCon n ts) | n == ''[] = foldl AppT ListT ts
| otherwise = foldl AppT (ConT n) ts
atc2constructors :: AppliedTyCon -> Q [Con]
atc2constructors (AppliedTyCon n args) = do
i <- reify n
(params,cs) <-
case i of
TyConI (DataD _ _ ps cs0 _) -> return (ps,cs0)
TyConI (NewtypeD _ _ ps c0 _) -> return (ps,[c0])
_ -> fail ("Expected this name to refer to a data or newtype: "
++show n
++"\nBut info for this name was: "++show i)
let
substs :: [(Name,Type)]
substs = assert (length params == length args)
(zip (fmap deKindSigify params) args)
doSubsts x = foldr substInCon x substs
return (doSubsts <$> cs)
cutNames :: (Data a) => a -> a
cutNames = everywhere (mkT cutName)
where
cutName = mkName . nameBase
pprintUnqual :: (Ppr a, Data a) => a -> String
pprintUnqual = pprint . cutNames
#define showQ(X)\
$( (runIO . print =<< (X)) >> [d| showQ_dummy______ = ()|])
instance Ppr AppliedTyCon where
ppr (AppliedTyCon n args) = ppr (foldl AppT (ConT n) args)
sMatch :: Pat -> Exp -> Match
sMatch p b = Match p (NormalB b) []
sClause :: [Pat] -> Exp -> Clause
sClause ps b = Clause ps (NormalB b) []
cleanConstructorName :: [Char] -> [Char]
cleanConstructorName c =
case c of
('(':_) | last c == ')' -> "TUPLE"++show (length c1)
"[]" -> "NIL"
":" -> "CONS"
(':':c1) -> "INFIX_CTOR" ++ concatMap (\x -> "_" ++ (show . ord) x ) c1
_ -> c