{-# LANGUAGE TemplateHaskell #-}
module Data.Singletons.Names where
import Data.Singletons.Internal
import Data.Singletons.SuppressUnusedWarnings
import Data.Singletons.Decide
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Desugar
import GHC.TypeLits ( Nat, Symbol )
import GHC.Exts ( Constraint )
import GHC.Show ( showCommaSpace, showSpace )
import Data.Typeable ( TypeRep )
import Data.Singletons.Util
import Control.Monad
boolName, andName, tyEqName, compareName, minBoundName,
maxBoundName, repName,
nilName, consName, listName, tyFunName,
applyName, natName, symbolName, typeRepName, stringName,
eqName, ordName, boundedName, orderingName,
singFamilyName, singIName, singMethName, demoteName,
singKindClassName, sEqClassName, sEqMethName, sconsName, snilName, strueName,
sIfName,
someSingTypeName, someSingDataName,
sListName, sDecideClassName, sDecideMethName,
provedName, disprovedName, reflName, toSingName, fromSingName,
equalityName, applySingName, suppressClassName, suppressMethodName,
thenCmpName,
sameKindName, tyFromIntegerName, tyNegateName, sFromIntegerName,
sNegateName, errorName, foldlName, cmpEQName, cmpLTName, cmpGTName,
singletonsToEnumName, singletonsFromEnumName, enumName, singletonsEnumName,
equalsName, constraintName,
showName, showCharName, showCommaSpaceName, showParenName, showsPrecName,
showSpaceName, showStringName, showSingName, showsSingPrecName,
composeName, gtName, tyFromStringName, sFromStringName :: Name
boolName = ''Bool
andName = '(&&)
compareName = 'compare
minBoundName = 'minBound
maxBoundName = 'maxBound
tyEqName = mk_name_tc "Data.Singletons.Prelude.Eq" "=="
repName = mkName "Rep"
nilName = '[]
consName = '(:)
listName = ''[]
tyFunName = ''TyFun
applyName = ''Apply
symbolName = ''Symbol
natName = ''Nat
typeRepName = ''TypeRep
stringName = ''String
eqName = ''Eq
ordName = ''Ord
boundedName = ''Bounded
orderingName = ''Ordering
singFamilyName = ''Sing
singIName = ''SingI
singMethName = 'sing
toSingName = 'toSing
fromSingName = 'fromSing
demoteName = ''Demote
singKindClassName = ''SingKind
sEqClassName = mk_name_tc "Data.Singletons.Prelude.Eq" "SEq"
sEqMethName = mk_name_v "Data.Singletons.Prelude.Eq" "%=="
sIfName = mk_name_v "Data.Singletons.Prelude.Bool" "sIf"
sconsName = mk_name_d "Data.Singletons.Prelude.Instances" "SCons"
snilName = mk_name_d "Data.Singletons.Prelude.Instances" "SNil"
strueName = mk_name_d "Data.Singletons.Prelude.Instances" "STrue"
someSingTypeName = ''SomeSing
someSingDataName = 'SomeSing
sListName = mk_name_tc "Data.Singletons.Prelude.Instances" "SList"
sDecideClassName = ''SDecide
sDecideMethName = '(%~)
provedName = 'Proved
disprovedName = 'Disproved
reflName = 'Refl
equalityName = ''(~)
applySingName = 'applySing
suppressClassName = ''SuppressUnusedWarnings
suppressMethodName = 'suppressUnusedWarnings
thenCmpName = mk_name_v "Data.Singletons.Prelude.Ord" "thenCmp"
sameKindName = ''SameKind
tyFromIntegerName = mk_name_tc "Data.Singletons.Prelude.Num" "FromInteger"
tyNegateName = mk_name_tc "Data.Singletons.Prelude.Num" "Negate"
sFromIntegerName = mk_name_v "Data.Singletons.Prelude.Num" "sFromInteger"
sNegateName = mk_name_v "Data.Singletons.Prelude.Num" "sNegate"
errorName = 'error
foldlName = 'foldl
cmpEQName = 'EQ
cmpLTName = 'LT
cmpGTName = 'GT
singletonsToEnumName = mk_name_v "Data.Singletons.Prelude.Enum" "toEnum"
singletonsFromEnumName = mk_name_v "Data.Singletons.Prelude.Enum" "fromEnum"
enumName = ''Enum
singletonsEnumName = mk_name_tc "Data.Singletons.Prelude.Enum" "Enum"
equalsName = '(==)
constraintName = ''Constraint
showName = ''Show
showCharName = 'showChar
showParenName = 'showParen
showSpaceName = 'showSpace
showsPrecName = 'showsPrec
showStringName = 'showString
showSingName = mk_name_tc "Data.Singletons.ShowSing" "ShowSing"
showsSingPrecName = mk_name_v "Data.Singletons.ShowSing" "showsSingPrec"
composeName = '(.)
gtName = '(>)
showCommaSpaceName = 'showCommaSpace
tyFromStringName = mk_name_tc "Data.Singletons.Prelude.IsString" "FromString"
sFromStringName = mk_name_v "Data.Singletons.Prelude.IsString" "sFromString"
singPkg :: String
singPkg = $( (LitE . StringL . loc_package) `liftM` location )
mk_name_tc :: String -> String -> Name
mk_name_tc = mkNameG_tc singPkg
mk_name_d :: String -> String -> Name
mk_name_d = mkNameG_d singPkg
mk_name_v :: String -> String -> Name
mk_name_v = mkNameG_v singPkg
mkTupleTypeName :: Int -> Name
mkTupleTypeName n = mk_name_tc "Data.Singletons.Prelude.Instances" $
"STuple" ++ (show n)
mkTupleDataName :: Int -> Name
mkTupleDataName n = mk_name_d "Data.Singletons.Prelude.Instances" $
"STuple" ++ (show n)
promoteValNameLhs :: Name -> Name
promoteValNameLhs = promoteValNameLhsPrefix noPrefix
promoteValNameLhsPrefix :: (String, String) -> Name -> Name
promoteValNameLhsPrefix pres@(alpha, symb) n
| nameBase n == "."
= mkName $ symb ++ ":."
| nameBase n == "!"
= mkName $ symb ++ ":!"
| Just (us, rest) <- splitUnderscores (nameBase n)
= mkName $ alpha ++ "US" ++ us ++ rest
| otherwise
= mkName $ toUpcaseStr pres n
promoteValRhs :: Name -> DType
promoteValRhs name
| name == nilName
= DConT nilName
| otherwise
= DConT $ promoteTySym name 0
promoteTySym :: Name -> Int -> Name
promoteTySym name sat
| nameBase name == ":."
= default_case (mkName ".")
| nameBase name == ":!"
= default_case (mkName "!")
| name == nilName
= mkName $ "NilSym" ++ (show sat)
| Just degree <- tupleNameDegree_maybe name `mplus`
unboxedTupleNameDegree_maybe name
= mk_name_tc "Data.Singletons.Prelude.Instances" $
"Tuple" ++ show degree ++ "Sym" ++ (show sat)
| otherwise
= default_case name
where
default_case :: Name -> Name
default_case name' =
let capped = toUpcaseStr noPrefix name' in
if isHsLetter (head capped)
then mkName (capped ++ "Sym" ++ (show sat))
else mkName (capped ++ "@#@"
++ (replicate (sat + 1) '$'))
promoteClassName :: Name -> Name
promoteClassName = prefixName "P" "#"
mkTyName :: Quasi 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 = DConT boolName
andTySym :: DType
andTySym = promoteValRhs andName
singDataConName :: Name -> Name
singDataConName nm
| nm == nilName = snilName
| nm == consName = sconsName
| Just degree <- tupleNameDegree_maybe nm = mkTupleDataName degree
| Just degree <- unboxedTupleNameDegree_maybe nm = mkTupleDataName degree
| otherwise = prefixConName "S" "%" nm
singTyConName :: Name -> Name
singTyConName name
| name == listName = sListName
| Just degree <- tupleNameDegree_maybe name = mkTupleTypeName degree
| Just degree <- unboxedTupleNameDegree_maybe name = mkTupleTypeName degree
| otherwise = prefixName "S" "%" name
singClassName :: Name -> Name
singClassName = singTyConName
singValName :: Name -> Name
singValName n
| Just (us, rest) <- splitUnderscores (nameBase n)
= prefixName (us ++ "s") "%" $ mkName rest
| otherwise
= prefixName "s" "%" $ upcase n
singFamily :: DType
singFamily = DConT singFamilyName
singKindConstraint :: DKind -> DPred
singKindConstraint = DAppPr (DConPr singKindClassName)
demote :: DType
demote = DConT demoteName
apply :: DType -> DType -> DType
apply t1 t2 = DAppT (DAppT (DConT applyName) t1) t2
mkListE :: [DExp] -> DExp
mkListE =
foldr (\h t -> DConE consName `DAppE` h `DAppE` t) (DConE nilName)
foldApply :: DType -> [DType] -> DType
foldApply = foldl apply
mkEqPred :: DType -> DType -> DPred
mkEqPred ty1 ty2 = foldl DAppPr (DConPr equalityName) [ty1, ty2]
splitUnderscores :: String -> Maybe (String, String)
splitUnderscores s = case span (== '_') s of
([], _) -> Nothing
res -> Just res
modifyConNameDPred :: (Name -> Name) -> DPred -> DPred
modifyConNameDPred mod_con_name = go
where
go (DAppPr p t) = DAppPr (go p) t
go (DSigPr p k) = DSigPr (go p) k
go p@(DVarPr _) = p
go (DConPr n) = DConPr (mod_con_name n)
go p@DWildCardPr = p