    {-|
    Module:      Data.Enum.Deriving.Internal
    Copyright:   (C) 2015-2017 Ryan Scott
    License:     BSD-style (see the file LICENSE)
    Maintainer:  Ryan Scott
    Portability: Template Haskell

    Exports functions to mechanically derive 'Enum' instances.

    Note: this is an internal module, and as such, the API presented here is not
    guaranteed to be stable, even between minor releases of this library.
    -}
    module Data.Enum.Deriving.Internal (
          -- * 'Enum'
          deriveEnum
        , makeSucc
        , makePred
        , makeToEnum
        , makeFromEnum
        , makeEnumFrom
        , makeEnumFromThen
        ) where

    import Data.Deriving.Internal
    import Data.List.NonEmpty (NonEmpty(..))

    import Language.Haskell.TH.Datatype
    import Language.Haskell.TH.Lib
    import Language.Haskell.TH.Syntax

    -------------------------------------------------------------------------------
    -- Code generation
    -------------------------------------------------------------------------------

    -- | Generates an 'Enum' instance declaration for the given data type or data
    -- family instance.
    deriveEnum :: Name -> Q [Dec]
    deriveEnum :: Name -> Q [Dec]
    deriveEnum Name
    name = do
      info <- Name -> Q DatatypeInfo
    reifyDatatype Name
    name
      case info of
        DatatypeInfo { datatypeContext :: DatatypeInfo -> Cxt
    datatypeContext   = Cxt
    ctxt
                     , datatypeName :: DatatypeInfo -> Name
    datatypeName      = Name
    parentName
                     , datatypeInstTypes :: DatatypeInfo -> Cxt
    datatypeInstTypes = Cxt
    instTypes
                     , datatypeVariant :: DatatypeInfo -> DatatypeVariant
    datatypeVariant   = DatatypeVariant
    variant
                     , datatypeCons :: DatatypeInfo -> [ConstructorInfo]
    datatypeCons      = [ConstructorInfo]
    cons
                     } -> do
          (instanceCxt, instanceType)
              <- EnumClass -> Name -> Cxt -> Cxt -> DatatypeVariant -> Q (Cxt, Type)
    forall a.
    ClassRep a =>
    a -> Name -> Cxt -> Cxt -> DatatypeVariant -> Q (Cxt, Type)
    buildTypeInstance EnumClass
    EnumClass Name
    parentName Cxt
    ctxt Cxt
    instTypes DatatypeVariant
    variant
          (:[]) `fmap` instanceD (return instanceCxt)
                                 (return instanceType)
                                 (enumFunDecs parentName instanceType cons)

    -- | Generates a lambda expression which behaves like 'succ' (without
    -- requiring an 'Enum' instance).
    makeSucc :: Name -> Q Exp
    makeSucc :: Name -> Q Exp
    makeSucc = EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    Succ

    -- | Generates a lambda expression which behaves like 'pred' (without
    -- requiring an 'Enum' instance).
    makePred :: Name -> Q Exp
    makePred :: Name -> Q Exp
    makePred = EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    Pred

    -- | Generates a lambda expression which behaves like 'toEnum' (without
    -- requiring an 'Enum' instance).
    makeToEnum :: Name -> Q Exp
    makeToEnum :: Name -> Q Exp
    makeToEnum = EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    ToEnum

    -- | Generates a lambda expression which behaves like 'fromEnum' (without
    -- requiring an 'Enum' instance).
    makeFromEnum :: Name -> Q Exp
    makeFromEnum :: Name -> Q Exp
    makeFromEnum = EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    FromEnum

    -- | Generates a lambda expression which behaves like 'enumFrom' (without
    -- requiring an 'Enum' instance).
    makeEnumFrom :: Name -> Q Exp
    makeEnumFrom :: Name -> Q Exp
    makeEnumFrom = EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    EnumFrom

    -- | Generates a lambda expression which behaves like 'enumFromThen' (without
    -- requiring an 'Enum' instance).
    makeEnumFromThen :: Name -> Q Exp
    makeEnumFromThen :: Name -> Q Exp
    makeEnumFromThen = EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    EnumFromThen

    -- | Generates method declarations for an 'Enum' instance.
    enumFunDecs :: Name -> Type -> [ConstructorInfo] -> [Q Dec]
    enumFunDecs :: Name -> Type -> [ConstructorInfo] -> [Q Dec]
    enumFunDecs Name
    tyName Type
    ty [ConstructorInfo]
    cons =
        (EnumFun -> Q Dec) -> [EnumFun] -> [Q Dec]
    forall a b. (a -> b) -> [a] -> [b]
    map EnumFun -> Q Dec
    makeFunD [ EnumFun
    Succ
                     , EnumFun
    Pred
                     , EnumFun
    ToEnum
                     , EnumFun
    EnumFrom
                     , EnumFun
    EnumFromThen
                     , EnumFun
    FromEnum
                     ]
      where
        makeFunD :: EnumFun -> Q Dec
        makeFunD :: EnumFun -> Q Dec
    makeFunD EnumFun
    ef =
          Name -> [Q Clause] -> Q Dec
    forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
    funD (EnumFun -> Name
    enumFunName EnumFun
    ef)
               [ [Q Pat] -> Q Body -> [Q Dec] -> Q Clause
    forall (m :: * -> *).
    Quote m =>
    [m Pat] -> m Body -> [m Dec] -> m Clause
    clause []
                        (Q Exp -> Q Body
    forall (m :: * -> *). Quote m => m Exp -> m Body
    normalB (Q Exp -> Q Body) -> Q Exp -> Q Body
    forall a b. (a -> b) -> a -> b
    $ EnumFun -> Name -> Type -> [ConstructorInfo] -> Q Exp
    makeEnumFunForCons EnumFun
    ef Name
    tyName Type
    ty [ConstructorInfo]
    cons)
                        []
               ]

    -- | Generates a lambda expression which behaves like the EnumFun argument.
    makeEnumFun :: EnumFun -> Name -> Q Exp
    makeEnumFun :: EnumFun -> Name -> Q Exp
    makeEnumFun EnumFun
    ef Name
    name = do
      info <- Name -> Q DatatypeInfo
    reifyDatatype Name
    name
      case info of
        DatatypeInfo { datatypeContext :: DatatypeInfo -> Cxt
    datatypeContext   = Cxt
    ctxt
                     , datatypeName :: DatatypeInfo -> Name
    datatypeName      = Name
    parentName
                     , datatypeInstTypes :: DatatypeInfo -> Cxt
    datatypeInstTypes = Cxt
    instTypes
                     , datatypeVariant :: DatatypeInfo -> DatatypeVariant
    datatypeVariant   = DatatypeVariant
    variant
                     , datatypeCons :: DatatypeInfo -> [ConstructorInfo]
    datatypeCons      = [ConstructorInfo]
    cons
                     } -> do
          (_, instanceType) <- EnumClass -> Name -> Cxt -> Cxt -> DatatypeVariant -> Q (Cxt, Type)
    forall a.
    ClassRep a =>
    a -> Name -> Cxt -> Cxt -> DatatypeVariant -> Q (Cxt, Type)
    buildTypeInstance EnumClass
    EnumClass Name
    parentName Cxt
    ctxt Cxt
    instTypes DatatypeVariant
    variant
          makeEnumFunForCons ef parentName instanceType cons

    -- | Generates a lambda expression for fromEnum/toEnum/etc. for the
    -- given constructors. All constructors must be from the same type.
    makeEnumFunForCons :: EnumFun -> Name -> Type -> [ConstructorInfo] -> Q Exp
    makeEnumFunForCons :: EnumFun -> Name -> Type -> [ConstructorInfo] -> Q Exp
    makeEnumFunForCons EnumFun
    _  Name
    _      Type
    _  [] = Q Exp
    forall a. Q a
    noConstructorsError
    makeEnumFunForCons EnumFun
    ef Name
    tyName Type
    ty (ConstructorInfo
    con:[ConstructorInfo]
    cons')
        | Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ NonEmpty ConstructorInfo -> Bool
    isEnumerationType NonEmpty ConstructorInfo
    cons
        = String -> Q Exp
    forall a. String -> Q a
    enumerationError String
    tyNameBase
        | Bool
    otherwise = case EnumFun
    ef of
            EnumFun
    Succ -> (Name -> Q Exp) -> Q Exp
    lamOneHash ((Name -> Q Exp) -> Q Exp) -> (Name -> Q Exp) -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ \Name
    aHash ->
              Q Exp -> Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp -> m Exp
    condE (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    eqValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Q Exp
    maxTagExpr Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE`
                       (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    conE Name
    iHashDataName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    aHash))
                    (String -> String -> String -> Q Exp
    illegalExpr String
    "succ" String
    tyNameBase
                                 String
    "tried to take `succ' of last tag in enumeration")
                    (Q Exp
    tag2Con Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    plusValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE`
                      (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    conE Name
    iHashDataName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    aHash) Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Int -> Q Exp
    integerE Int
    1))

            EnumFun
    Pred -> (Name -> Q Exp) -> Q Exp
    lamOneHash ((Name -> Q Exp) -> Q Exp) -> (Name -> Q Exp) -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ \Name
    aHash ->
              Q Exp -> Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp -> m Exp
    condE (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    eqValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Int -> Q Exp
    integerE Int
    0 Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE`
                       (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    conE Name
    iHashDataName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    aHash))
                    (String -> String -> String -> Q Exp
    illegalExpr String
    "pred" String
    tyNameBase
                                 String
    "tried to take `pred' of first tag in enumeration")
                    (Q Exp
    tag2Con Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    plusValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE`
                      (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    conE Name
    iHashDataName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    aHash) Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Int -> Q Exp
    integerE (-Int
    1)))

            EnumFun
    ToEnum -> (Name -> Q Exp) -> Q Exp
    lamOne ((Name -> Q Exp) -> Q Exp) -> (Name -> Q Exp) -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ \Name
    a ->
              Q Exp -> Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp -> m Exp
    condE ([Q Exp] -> Q Exp
    forall (m :: * -> *). Quote m => [m Exp] -> m Exp
    appsE [ Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    andValName
                           , Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    geValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    a Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Int -> Q Exp
    integerE Int
    0
                           , Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    leValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    a Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Q Exp
    maxTagExpr
                           ])
                    (Q Exp
    tag2Con Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    a)
                    (String -> Q Exp -> Name -> Q Exp
    illegalToEnumTag String
    tyNameBase Q Exp
    maxTagExpr Name
    a)

            EnumFun
    EnumFrom -> (Name -> Q Exp) -> Q Exp
    lamOneHash ((Name -> Q Exp) -> Q Exp) -> (Name -> Q Exp) -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ \Name
    aHash ->
              [Q Exp] -> Q Exp
    forall (m :: * -> *). Quote m => [m Exp] -> m Exp
    appsE [ Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    mapValName
                    , Q Exp
    tag2Con
                    , Q Exp -> Q Exp -> Q Exp
    enumFromToExpr (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    conE Name
    iHashDataName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    aHash) Q Exp
    maxTagExpr
                    ]

            EnumFun
    EnumFromThen -> do
              a     <- String -> Q Name
    forall (m :: * -> *). Quote m => String -> m Name
    newName String
    "a"
              aHash <- newName "a#"
              b     <- newName "b"
              bHash <- newName "b#"
              lamE [varP a, varP b] $ untagExpr [(a, aHash), (b, bHash)] $
                  appE (varE mapValName `appE` tag2Con) $
                      enumFromThenToExpr
                        (conE iHashDataName `appE` varE aHash)
                        (conE iHashDataName `appE` varE bHash)
                        (condE (appsE [ varE gtValName
                                      , conE iHashDataName `appE` varE aHash
                                      , conE iHashDataName `appE` varE bHash
                                      ])
                               (integerE 0) maxTagExpr)

            EnumFun
    FromEnum -> (Name -> Q Exp) -> Q Exp
    lamOneHash ((Name -> Q Exp) -> Q Exp) -> (Name -> Q Exp) -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ \Name
    aHash ->
              Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    conE Name
    iHashDataName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    aHash

      where
        tyNameBase :: String
        tyNameBase :: String
    tyNameBase = Name -> String
    nameBase Name
    tyName

        cons :: NonEmpty ConstructorInfo
        cons :: NonEmpty ConstructorInfo
    cons = ConstructorInfo
    con ConstructorInfo -> [ConstructorInfo] -> NonEmpty ConstructorInfo
    forall a. a -> [a] -> NonEmpty a
    :| [ConstructorInfo]
    cons'

        maxTagExpr :: Q Exp
        maxTagExpr :: Q Exp
    maxTagExpr = Int -> Q Exp
    integerE ([ConstructorInfo] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [ConstructorInfo]
    cons') Q Exp -> Q Type -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Type -> m Exp
    `sigE` Name -> Q Type
    forall (m :: * -> *). Quote m => Name -> m Type
    conT Name
    intTypeName

        lamOne :: (Name -> Q Exp) -> Q Exp
        lamOne :: (Name -> Q Exp) -> Q Exp
    lamOne Name -> Q Exp
    f = do
            a <- String -> Q Name
    forall (m :: * -> *). Quote m => String -> m Name
    newName String
    "a"
            lam1E (varP a) $ f a

        lamOneHash :: (Name -> Q Exp) -> Q Exp
        lamOneHash :: (Name -> Q Exp) -> Q Exp
    lamOneHash Name -> Q Exp
    f = (Name -> Q Exp) -> Q Exp
    lamOne ((Name -> Q Exp) -> Q Exp) -> (Name -> Q Exp) -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ \Name
    a -> do
            aHash <- String -> Q Name
    forall (m :: * -> *). Quote m => String -> m Name
    newName String
    "a#"
            untagExpr [(a, aHash)] $ f aHash

        tag2Con :: Q Exp
        tag2Con :: Q Exp
    tag2Con = Type -> Q Exp
    tag2ConExpr (Type -> Q Exp) -> Type -> Q Exp
    forall a b. (a -> b) -> a -> b
    $ Type -> Type
    removeClassApp Type
    ty

    -------------------------------------------------------------------------------
    -- Class-specific constants
    -------------------------------------------------------------------------------

    -- There's only one Enum variant!
    data EnumClass = EnumClass

    instance ClassRep EnumClass where
        arity :: EnumClass -> Int
    arity EnumClass
    _ = Int
    0

        allowExQuant :: EnumClass -> Bool
    allowExQuant EnumClass
    _ = Bool
    True

        fullClassName :: EnumClass -> Name
    fullClassName EnumClass
    _ = Name
    enumTypeName

        classConstraint :: EnumClass -> Int -> Maybe Name
    classConstraint EnumClass
    _ Int
    0 = Name -> Maybe Name
    forall a. a -> Maybe a
    Just (Name -> Maybe Name) -> Name -> Maybe Name
    forall a b. (a -> b) -> a -> b
    $ Name
    enumTypeName
        classConstraint EnumClass
    _ Int
    _ = Maybe Name
    forall a. Maybe a
    Nothing

    -- | A representation of which function is being generated.
    data EnumFun = Succ
                 | Pred
                 | ToEnum
                 | FromEnum
                 | EnumFrom
                 | EnumFromThen
      deriving Int -> EnumFun -> ShowS
    [EnumFun] -> ShowS
    EnumFun -> String
    (Int -> EnumFun -> ShowS)
    -> (EnumFun -> String) -> ([EnumFun] -> ShowS) -> Show EnumFun
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> EnumFun -> ShowS
    showsPrec :: Int -> EnumFun -> ShowS
    $cshow :: EnumFun -> String
    show :: EnumFun -> String
    $cshowList :: [EnumFun] -> ShowS
    showList :: [EnumFun] -> ShowS
    Show

    enumFunName :: EnumFun -> Name
    enumFunName :: EnumFun -> Name
    enumFunName EnumFun
    Succ           = Name
    succValName
    enumFunName EnumFun
    Pred           = Name
    predValName
    enumFunName EnumFun
    ToEnum         = Name
    toEnumValName
    enumFunName EnumFun
    FromEnum       = Name
    fromEnumValName
    enumFunName EnumFun
    EnumFrom       = Name
    enumFromValName
    enumFunName EnumFun
    EnumFromThen   = Name
    enumFromThenValName

    -------------------------------------------------------------------------------
    -- Assorted utilities
    -------------------------------------------------------------------------------

    enumFromThenToExpr :: Q Exp -> Q Exp -> Q Exp -> Q Exp
    enumFromThenToExpr :: Q Exp -> Q Exp -> Q Exp -> Q Exp
    enumFromThenToExpr Q Exp
    f Q Exp
    t1 Q Exp
    t2 = Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    enumFromThenToValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Q Exp
    f Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Q Exp
    t1 Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` Q Exp
    t2

    illegalExpr :: String -> String -> String -> Q Exp
    illegalExpr :: String -> String -> String -> Q Exp
    illegalExpr String
    meth String
    tp String
    msg =
        Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    errorValName Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    `appE` String -> Q Exp
    forall (m :: * -> *). Quote m => String -> m Exp
    stringE (String
    meth String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Char
    '{'Char -> ShowS
    forall a. a -> [a] -> [a]
    :String
    tp String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "}: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    msg)

    illegalToEnumTag :: String -> Q Exp -> Name -> Q Exp
    illegalToEnumTag :: String -> Q Exp -> Name -> Q Exp
    illegalToEnumTag String
    tp Q Exp
    maxtag Name
    a =
        Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    errorValName)
             (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    appendValName)
                         (String -> Q Exp
    forall (m :: * -> *). Quote m => String -> m Exp
    stringE (String
    "toEnum{" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    tp String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "}: tag(")))
                   (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE
                     (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    showsPrecValName)
                     (Int -> Q Exp
    integerE Int
    0))
                     (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    a))
                     (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE
                       (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    appendValName)
                       (String -> Q Exp
    forall (m :: * -> *). Quote m => String -> m Exp
    stringE String
    ") is outside of enumeration's range (0,"))
                       (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE (Q Exp -> Q Exp -> Q Exp
    forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
    appE
                             (Name -> Q Exp
    forall (m :: * -> *). Quote m => Name -> m Exp
    varE Name
    showsPrecValName)
                             (Int -> Q Exp
    integerE Int
    0))
                             Q Exp
    maxtag)
                             (String -> Q Exp
    forall (m :: * -> *). Quote m => String -> m Exp
    stringE String
    ")")))))