module Data.Singletons.Names where
import Data.Singletons
import Data.Singletons.SuppressUnusedWarnings
import Data.Singletons.Types
import Data.Singletons.Decide
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Desugar
import GHC.TypeLits ( Symbol )
import GHC.Exts ( Any )
import Data.Typeable ( TypeRep )
import Data.Singletons.Util
anyTypeName, boolName, andName, tyEqName, tyCompareName, tyminBoundName,
tymaxBoundName, repName,
nilName, consName, listName, tyFunName,
applyName, symbolName, undefinedName, typeRepName, stringName,
eqName, ordName, boundedName, orderingName, ordLTSymName, ordEQSymName,
ordGTSymName,
singFamilyName, singIName, singMethName, demoteRepName,
singKindClassName, sEqClassName, sEqMethName, sconsName, snilName,
sIfName, kProxyDataName, kProxyTypeName, proxyTypeName, proxyDataName,
someSingTypeName, someSingDataName,
sListName, sDecideClassName, sDecideMethName,
provedName, disprovedName, reflName, toSingName, fromSingName,
equalityName, applySingName, suppressClassName, suppressMethodName,
tyThenCmpName, kindOfName :: Name
anyTypeName = ''Any
boolName = ''Bool
andName = '(&&)
tyCompareName = mkName "Compare"
tyminBoundName = mkName "MinBound"
tymaxBoundName = mkName "MaxBound"
tyEqName = mkName ":=="
repName = mkName "Rep"
nilName = '[]
consName = '(:)
listName = ''[]
tyFunName = ''TyFun
applyName = ''Apply
symbolName = ''Symbol
undefinedName = 'undefined
typeRepName = ''TypeRep
stringName = ''String
eqName = ''Eq
ordName = ''Ord
boundedName = ''Bounded
orderingName = ''Ordering
ordLTSymName = mkName "LTSym0"
ordEQSymName = mkName "EQSym0"
ordGTSymName = mkName "GTSym0"
singFamilyName = ''Sing
singIName = ''SingI
singMethName = 'sing
toSingName = 'toSing
fromSingName = 'fromSing
demoteRepName = ''DemoteRep
singKindClassName = ''SingKind
sEqClassName = mkName "SEq"
sEqMethName = mkName "%:=="
sIfName = mkName "sIf"
sconsName = mkName "SCons"
snilName = mkName "SNil"
kProxyDataName = 'KProxy
kProxyTypeName = ''KProxy
someSingTypeName = ''SomeSing
someSingDataName = 'SomeSing
proxyTypeName = ''Proxy
proxyDataName = 'Proxy
sListName = mkName "SList"
sDecideClassName = ''SDecide
sDecideMethName = '(%~)
provedName = 'Proved
disprovedName = 'Disproved
reflName = 'Refl
equalityName = ''(~)
applySingName = 'applySing
suppressClassName = ''SuppressUnusedWarnings
suppressMethodName = 'suppressUnusedWarnings
tyThenCmpName = mkName "ThenCmp"
kindOfName = ''KindOf
mkTupleName :: Int -> Name
mkTupleName n = mkName $ "STuple" ++ (show n)
promoteValNameLhs :: Name -> Name
promoteValNameLhs = upcase
promoteValNameLhsPrefix :: String -> Name -> Name
promoteValNameLhsPrefix prefix = mkName . (prefix ++) . toUpcaseStr
promoteValRhs :: Name -> DType
promoteValRhs name
| name == nilName
= DConT nilName
| otherwise
= DConT $ promoteTySym name 0
promoteTySym :: Name -> Int -> Name
promoteTySym name sat
| name == undefinedName
= anyTypeName
| name == nilName
= mkName $ "NilSym" ++ (show sat)
| Just degree <- tupleNameDegree_maybe name
= mkName $ "Tuple" ++ show degree ++ "Sym" ++ (show sat)
| Just degree <- unboxedTupleNameDegree_maybe name
= mkName $ "Tuple" ++ show degree ++ "Sym" ++ (show sat)
| otherwise
= let capped = toUpcaseStr name in
if isHsLetter (head capped)
then mkName (capped ++ "Sym" ++ (show sat))
else mkName (capped ++ (replicate (sat + 1) '$'))
promoteClassName :: Name -> Name
promoteClassName = prefixUCName "P" "#"
classTvsName :: Name -> Name
classTvsName = suffixName "TyVars" "^^^"
mkTyName :: DsMonad q => Name -> q Name
mkTyName tmName = do
let nameStr = nameBase tmName
symbolic = not (isHsLetter (head nameStr))
qNewName (if symbolic then "ty" else nameStr)
falseTySym :: DType
falseTySym = promoteValRhs falseName
trueTySym :: DType
trueTySym = promoteValRhs trueName
boolKi :: DKind
boolKi = DConK boolName []
andTySym :: DType
andTySym = promoteValRhs andName
inferKindTV :: DsMonad q => Name -> q DTyVarBndr
inferKindTV n = do
#if __GLASGOW_HASKELL__ < 707
ki <- fmap DVarK $ qNewName "k"
return $ DKindedTV n _ki
#else
return $ DPlainTV n
#endif
inferMaybeKindTV :: DsMonad q => Name -> Maybe DKind -> q DTyVarBndr
inferMaybeKindTV n Nothing =
#if __GLASGOW_HASKELL__ < 707
do k <- qNewName "k"
return $ DKindedTV n (DVarK k)
#else
return $ DPlainTV n
#endif
inferMaybeKindTV n (Just k) = return $ DKindedTV n k
unknownResult :: DKind -> Maybe DKind
#if __GLASGOW_HASKELL__ < 707
unknownResult = Just
#else
unknownResult = const Nothing
#endif
singDataConName :: Name -> Name
singDataConName nm
| nm == nilName = snilName
| nm == consName = sconsName
| Just degree <- tupleNameDegree_maybe nm = mkTupleName degree
| Just degree <- unboxedTupleNameDegree_maybe nm = mkTupleName degree
| otherwise = prefixUCName "S" ":%" nm
singTyConName :: Name -> Name
singTyConName name
| name == listName = sListName
| Just degree <- tupleNameDegree_maybe name = mkTupleName degree
| Just degree <- unboxedTupleNameDegree_maybe name = mkTupleName degree
| otherwise = prefixUCName "S" ":%" name
singClassName :: Name -> Name
singClassName = singTyConName
singValName :: Name -> Name
singValName n
| n == undefinedName = undefinedName
| head (nameBase n) == '_' = (prefixLCName "_s" "%") $ n
| otherwise = (prefixLCName "s" "%") $ upcase n
kindParam :: DKind -> DType
kindParam k = DSigT (DConT kProxyDataName) (DConK kProxyTypeName [k])
proxyFor :: DType -> DExp
proxyFor ty = DSigE (DConE proxyDataName) (DAppT (DConT proxyTypeName) ty)
singFamily :: DType
singFamily = DConT singFamilyName
singKindConstraint :: DKind -> DPred
singKindConstraint k = DAppPr (DConPr singKindClassName) (kindParam k)
demote :: DType
demote = DConT demoteRepName
apply :: DType -> DType -> DType
apply t1 t2 = DAppT (DAppT (DConT applyName) t1) t2
foldApply :: DType -> [DType] -> DType
foldApply = foldl apply