module Data.Singletons.Util where
import Language.Haskell.TH
import Data.Char
import Data.Data
import Control.Monad
import Control.Monad.Writer
import qualified Data.Map as Map
import Data.Generics
mkTyFamInst :: Name -> [Type] -> Type -> Dec
mkTyFamInst name lhs rhs =
#if __GLASGOW_HASKELL__ >= 707
TySynInstD name (TySynEqn lhs rhs)
#else
TySynInstD name lhs rhs
#endif
newUniqueName :: String -> Q Name
newUniqueName str = do
n <- newName str
return $ mkName $ show n
reifyWithWarning :: Name -> Q Info
reifyWithWarning name = recover
(fail $ "Looking up " ++ (show name) ++ " in the list of available " ++
"declarations failed.\nThis lookup fails if the declaration " ++
"referenced was made in the same Template\nHaskell splice as the use " ++
"of the declaration. If this is the case, put\nthe reference to " ++
"the declaration in a new splice.")
(reify name)
isTupleString :: String -> Bool
isTupleString s =
(length s > 1) &&
(head s == '(') &&
(last s == ')') &&
((length (takeWhile (== ',') (tail s))) == ((length s) 2))
isTupleName :: Name -> Bool
isTupleName = isTupleString . nameBase
tupleDegree :: String -> Int
tupleDegree "()" = 0
tupleDegree s = length s 1
ctorCases :: (Name -> [Type] -> a) -> ([TyVarBndr] -> Cxt -> Con -> a) -> Con -> a
ctorCases genFun forallFun ctor = case ctor of
NormalC name stypes -> genFun name (map snd stypes)
RecC name vstypes -> genFun name (map (\(_,_,ty) -> ty) vstypes)
InfixC (_,ty1) name (_,ty2) -> genFun name [ty1, ty2]
ForallC [] [] ctor' -> ctorCases genFun forallFun ctor'
ForallC tvbs cx ctor' -> forallFun tvbs cx ctor'
ctor1Case :: (Name -> [Type] -> a) -> Con -> a
ctor1Case mono = ctorCases mono (\_ _ ctor -> ctor1Case mono ctor)
extractNameArgs :: Con -> (Name, Int)
extractNameArgs = ctor1Case (\name tys -> (name, length tys))
reinterpret :: Name -> Name
reinterpret = mkName . nameBase
isUpcase :: Name -> Bool
isUpcase n = let first = head (nameBase n) in isUpper first || first == ':'
upcase :: Name -> Name
upcase n =
let str = nameBase n
first = head str in
if isLetter first
then mkName ((toUpper first) : tail str)
else mkName (':' : str)
locase :: Name -> Name
locase n =
let str = nameBase n
first = head str in
if isLetter first
then mkName ((toLower first) : tail str)
else mkName (tail str)
prefixUCName :: String -> String -> Name -> Name
prefixUCName pre tyPre n = case (nameBase n) of
(':' : rest) -> mkName (tyPre ++ rest)
alpha -> mkName (pre ++ alpha)
prefixLCName :: String -> String -> Name -> Name
prefixLCName pre tyPre n =
let str = nameBase n
first = head str in
if isLetter first
then mkName (pre ++ str)
else mkName (tyPre ++ str)
extractTvbName :: TyVarBndr -> Name
extractTvbName (PlainTV n) = n
extractTvbName (KindedTV n _) = n
#if __GLASGOW_HASKELL__ >= 707
extractTvbName (RoledTV n _) = n
extractTvbName (KindedRoledTV n _ _) = n
#endif
extractTvbKind :: TyVarBndr -> Kind
extractTvbKind (PlainTV _) = StarT
extractTvbKind (KindedTV _ k) = k
#if __GLASGOW_HASKELL__ >= 707
extractTvbKind (RoledTV _ _) = StarT
extractTvbKind (KindedRoledTV _ k _) = k
#endif
foldType :: Type -> [Type] -> Type
foldType = foldl AppT
foldExp :: Exp -> [Exp] -> Exp
foldExp = foldl AppE
isVarK :: Kind -> Bool
isVarK (VarT _) = True
isVarK _ = False
type QWithAux m = WriterT m Q
evalWithoutAux :: QWithAux m a -> Q a
evalWithoutAux = liftM fst . runWriterT
evalForAux :: QWithAux m a -> Q m
evalForAux = execWriterT
evalForPair :: QWithAux m a -> Q (a, m)
evalForPair = runWriterT
addBinding :: Ord k => k -> v -> QWithAux (Map.Map k v) ()
addBinding k v = tell (Map.singleton k v)
addElement :: elt -> QWithAux [elt] ()
addElement elt = tell [elt]
containsName :: Data a => Name -> a -> Bool
containsName n = everything (||) (mkQ False (== n))
concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
concatMapM fn list = do
bss <- mapM fn list
return $ concat bss
getDataD :: String -> Name -> Q ([TyVarBndr], [Con])
getDataD error name = do
info <- reifyWithWarning name
dec <- case info of
TyConI dec -> return dec
_ -> badDeclaration
case dec of
DataD _cxt _name tvbs cons _derivings -> return (tvbs, cons)
NewtypeD _cxt _name tvbs con _derivings -> return (tvbs, [con])
_ -> badDeclaration
where badDeclaration =
fail $ "The name (" ++ (show name) ++ ") refers to something " ++
"other than a datatype. " ++ error