    -- | An abstraction for representing type constructors. This is a very
    -- simplified version of `Data.Typeable`, which we don't use directly
    -- to avoid compatibility headaches.
    module Data.GI.CodeGen.Type
        ( Type(..)  -- Reexported for convenience.
        , BasicType(..)

        , TypeRep

        , con
        , con0

        , typeShow
        , typeConName

        , io
        , ptr
        , funptr
        , maybeT
        ) where

    #if !MIN_VERSION_base(4,11,0)
    import Data.Monoid ((<>))
    #endif
    import qualified Data.Text as T
    import Data.Text (Text)

    import Data.GI.GIR.BasicTypes (Type(..), BasicType(..))

    -- | A fully applied type.
    data TypeRep = TypeRep { TypeRep -> TypeCon
    typeCon     :: TypeCon
                           , TypeRep -> [TypeRep]
    typeConArgs :: [TypeRep]
                           } deriving (TypeRep -> TypeRep -> Bool
    (TypeRep -> TypeRep -> Bool)
    -> (TypeRep -> TypeRep -> Bool) -> Eq TypeRep
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: TypeRep -> TypeRep -> Bool
    == :: TypeRep -> TypeRep -> Bool
    $c/= :: TypeRep -> TypeRep -> Bool
    /= :: TypeRep -> TypeRep -> Bool
    Eq)

    -- | A type constructor. We single out some specific constructors
    -- since they have special syntax in their Haskell representation.
    data TypeCon = TupleCon
                 | ListCon
                 | TextualCon Text
      deriving (TypeCon -> TypeCon -> Bool
    (TypeCon -> TypeCon -> Bool)
    -> (TypeCon -> TypeCon -> Bool) -> Eq TypeCon
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: TypeCon -> TypeCon -> Bool
    == :: TypeCon -> TypeCon -> Bool
    $c/= :: TypeCon -> TypeCon -> Bool
    /= :: TypeCon -> TypeCon -> Bool
    Eq)

    -- | Give a valid Haskell source representation of the given
    -- `TypeRep`.
    typeShow :: TypeRep -> Text
    typeShow :: TypeRep -> Text
    typeShow (TypeRep TypeCon
    TupleCon [TypeRep]
    args) =
      Text
    "(" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text -> [Text] -> Text
    T.intercalate Text
    ", " ((TypeRep -> Text) -> [TypeRep] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map TypeRep -> Text
    typeShow [TypeRep]
    args) Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    ")"
    typeShow (TypeRep TypeCon
    ListCon [TypeRep]
    args) =
      Text
    "[" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text -> [Text] -> Text
    T.intercalate Text
    ", " ((TypeRep -> Text) -> [TypeRep] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map TypeRep -> Text
    typeShow [TypeRep]
    args) Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "]"
    typeShow (TypeRep (TextualCon Text
    con) [TypeRep]
    args) =
      Text -> [Text] -> Text
    T.intercalate Text
    " " (Text
    con Text -> [Text] -> [Text]
    forall a. a -> [a] -> [a]
    : (TypeRep -> Text) -> [TypeRep] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map (Text -> Text
    parenthesize (Text -> Text) -> (TypeRep -> Text) -> TypeRep -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TypeRep -> Text
    typeShow) [TypeRep]
    args)
      where parenthesize :: Text -> Text
            parenthesize :: Text -> Text
    parenthesize Text
    s = if (Char -> Bool) -> Text -> Bool
    T.any (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    ' ') Text
    s
                             then Text
    "(" Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    s Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    ")"
                             else Text
    s

    -- | Return a textual representation of the type constructor for the
    -- given `TypeRep`.
    typeConName :: TypeRep -> Text
    typeConName :: TypeRep -> Text
    typeConName (TypeRep TypeCon
    TupleCon [TypeRep]
    _) = Text
    "(,)"
    typeConName (TypeRep TypeCon
    ListCon [TypeRep]
    _) = Text
    "[,]"
    typeConName (TypeRep (TextualCon Text
    s) [TypeRep]
    _) = Text
    s

    -- | Type constructor applied to the given types.
    con :: Text -> [TypeRep] -> TypeRep
    con :: Text -> [TypeRep] -> TypeRep
    con Text
    "[]" [TypeRep]
    xs = TypeRep {typeCon :: TypeCon
    typeCon = TypeCon
    ListCon, typeConArgs :: [TypeRep]
    typeConArgs = [TypeRep]
    xs }
    con Text
    "(,)" [TypeRep]
    xs = TypeRep {typeCon :: TypeCon
    typeCon = TypeCon
    TupleCon, typeConArgs :: [TypeRep]
    typeConArgs = [TypeRep]
    xs }
    con Text
    s [TypeRep]
    xs = TypeRep {typeCon :: TypeCon
    typeCon = Text -> TypeCon
    TextualCon Text
    s, typeConArgs :: [TypeRep]
    typeConArgs = [TypeRep]
    xs}

    -- | A shorthand for a type constructor taking no arguments.
    con0 :: Text -> TypeRep
    con0 :: Text -> TypeRep
    con0 Text
    c = Text -> [TypeRep] -> TypeRep
    con Text
    c []

    -- | Embed in the `IO` monad.
    io :: TypeRep -> TypeRep
    io :: TypeRep -> TypeRep
    io TypeRep
    t = Text
    "IO" Text -> [TypeRep] -> TypeRep
    `con` [TypeRep
    t]

    -- | A `Ptr` to the type.
    ptr :: TypeRep -> TypeRep
    ptr :: TypeRep -> TypeRep
    ptr TypeRep
    t = Text
    "Ptr" Text -> [TypeRep] -> TypeRep
    `con` [TypeRep
    t]

    -- | A `FunPtr` to the type.
    funptr :: TypeRep -> TypeRep
    funptr :: TypeRep -> TypeRep
    funptr TypeRep
    t = Text
    "FunPtr" Text -> [TypeRep] -> TypeRep
    `con` [TypeRep
    t]

    -- | Embed in the `Maybe` monad.
    maybeT :: TypeRep -> TypeRep
    maybeT :: TypeRep -> TypeRep
    maybeT TypeRep
    t = Text
    "Maybe" Text -> [TypeRep] -> TypeRep
    `con` [TypeRep
    t]