{-# LANGUAGE UndecidableInstances #-}
module Data.KindID.Error where
import Data.Kind
import Data.TypeID.Error
import Data.Type.Bool
import Data.Type.Equality
import Data.Type.Ord
import GHC.TypeLits
class ToErrorMessageC (e :: k) where
type ToErrorMessage e :: ErrorMessage
instance ToErrorMessageC (TypeIDErrorPrefixTooLong t) where
type ToErrorMessage (TypeIDErrorPrefixTooLong t) =
Text "The prefix "
:<>: ShowType (Str2Sym t)
:<>: Text " with "
:<>: ShowType (LengthSymbol (Str2Sym t))
:<>: Text " characters is too long!"
instance ToErrorMessageC TypeIDExtraSeparator where
type ToErrorMessage TypeIDExtraSeparator = Text
"The underscore separator should not be present if the prefix is empty!"
instance ToErrorMessageC (TypeIDStartWithUnderscore t) where
type ToErrorMessage (TypeIDStartWithUnderscore t) =
Text "The prefix "
:<>: ShowType (Str2Sym t)
:<>: Text " should not start with an underscore!"
instance ToErrorMessageC (TypeIDEndWithUnderscore t) where
type ToErrorMessage (TypeIDEndWithUnderscore t) =
Text "The prefix "
:<>: ShowType (Str2Sym t)
:<>: Text " should not end with an underscore!"
instance ToErrorMessageC (TypeIDErrorPrefixInvalidChar t c) where
type ToErrorMessage (TypeIDErrorPrefixInvalidChar t c) =
Text "The prefix "
:<>: ShowType (Str2Sym t)
:<>: Text " contains invalid character "
:<>: ShowType c
:<>: Text "!"
type family Str2Sym (str :: String) :: Symbol where
Str2Sym '[] = ""
Str2Sym (c ': cs) = ConsSymbol c (Str2Sym cs)
type family Sym2Str (str :: Symbol) :: String where
Sym2Str s = SSUH (UnconsSymbol s)
type family SSUH (uncons :: Maybe (Char, Symbol)) :: String where
SSUH Nothing = '[]
SSUH (Just '( c, s )) = c ': Sym2Str s
type family LengthSymbol (prefix :: Symbol) :: Nat where
LengthSymbol prefix = LSUH (UnconsSymbol prefix)
type family LSUH (uncons :: Maybe (Char, Symbol)) :: Nat where
LSUH 'Nothing = 0
LSUH ('Just '( c, s )) = 1 + LengthSymbol s
type family IsLowerChar (ch :: Char) :: Bool where
IsLowerChar ch = Compare '`' ch == 'LT && Compare ch '{' == 'LT
type family IsUnderscore (ch :: Char) :: Bool where
IsUnderscore ch = Compare '_' ch == 'EQ
type family IsLUSymbol (prefix :: Symbol) :: Maybe TypeIDError where
IsLUSymbol "_" = 'Just 'TypeIDExtraSeparator
IsLUSymbol prefix = ILUSUH1 (UnconsSymbol prefix) prefix
type family ILUSUH1 (uncons :: Maybe (Char, Symbol)) (prefix :: Symbol)
:: Maybe TypeIDError where
ILUSUH1 'Nothing s = 'Nothing
ILUSUH1 ('Just '( '_', _ )) s = 'Just
(TypeIDStartWithUnderscore (Sym2Str s))
ILUSUH1 ('Just '( c, r )) s =
WrapMaybe (IsLowerChar c || IsUnderscore c)
(TypeIDErrorPrefixInvalidChar (Sym2Str s) c)
<|> ILUSUH2 (UnconsSymbol r) s
type family ILUSUH2 (uncons :: Maybe (Char, Symbol)) (prefix :: Symbol)
:: Maybe TypeIDError where
ILUSUH2 'Nothing s = 'Nothing
ILUSUH2 ('Just '( '_', "" )) s = 'Just (TypeIDEndWithUnderscore (Sym2Str s))
ILUSUH2 ('Just '( c, r )) s =
WrapMaybe (IsLowerChar c || IsUnderscore c)
(TypeIDErrorPrefixInvalidChar (Sym2Str s) c)
<|> ILUSUH2 (UnconsSymbol r) s
type family WrapMaybe p a where
WrapMaybe True a = 'Nothing
WrapMaybe False a = 'Just a
type family (<|>) a b where
'Just a <|> b = 'Just a
Nothing <|> b = b
type family BuildTypeIDErrorConstraint (a :: Maybe TypeIDError)
:: Constraint where
BuildTypeIDErrorConstraint 'Nothing = ()
BuildTypeIDErrorConstraint ('Just e) = TypeError (ToErrorMessage e)