hs-bindgen-1.0.0.0: src-internal/HsBindgen/Language/C.hs
-- | Standard C language types
--
-- Intended for qualified import.
--
-- > import HsBindgen.Language.C qualified as C
module HsBindgen.Language.C (
-- * C primitive types
PrimType(..)
, PrimIntType(..)
, PrimFloatType(..)
, PrimSign(..)
, PrimSignChar(..)
-- ** Sign
, primTypeSign
-- ** Pretty-printing
, showsPrimType
) where
import HsBindgen.Imports
{-------------------------------------------------------------------------------
Primitive types
-------------------------------------------------------------------------------}
data PrimType =
-- | @[signed | unsigned] char@
PrimChar PrimSignChar
-- | An integral type, such as @int@ or @unsigned long int@.
| PrimIntegral PrimIntType PrimSign
-- | A floating-point type, such as @float@ or @long double@.
| PrimFloating PrimFloatType
-- | @_Bool@
| PrimBool
deriving stock (Show, Eq, Ord, Generic)
-- | An integral type, such as @int@ or @unsigned long int@.
data PrimIntType
-- | @[signed | unsigned] short [int]@
= PrimShort
-- | @[signed | unsigned] int@
| PrimInt
-- | @[signed | unsigned] long [int]@
| PrimLong
-- | @[signed | unsigned] long long [int]@
| PrimLongLong
deriving stock (Show, Eq, Ord, Enum, Bounded, Generic)
-- | Primitive floating point types
--
-- TODO <https://github.com/well-typed/hs-bindgen/issues/349>
-- We don't currently support @long double@.
data PrimFloatType
-- | @float@
= PrimFloat
-- | @double@
| PrimDouble
deriving stock (Show, Eq, Ord, Enum, Bounded, Generic)
-- | Sign of a primitive type
data PrimSign = Signed | Unsigned
deriving stock (Show, Eq, Ord, Enum, Bounded, Generic)
-- | Sign for @char@
--
-- The C standard distinguishes between /three/ kinds of @char@: @char@, @signed
-- char@ and @unsigned char@. Unlike the other integer types, the interpretation
-- of @char@ as either @signed char@ or @unsigned char@ is implementation
-- defined (see also <https://eel.is/c++draft/basic#fundamental>).
--
-- Our general approach in @hs-bindgen@ is to generate machine code but with a
-- machine independent API. For example, we might know that @int@ is 32 bits on
-- a particular platform, and use this information to define 'Foreign.Storable.sizeOf' in
-- 'Foreign.Storable.Storable' instances, but still use 'Foreign.C.Types.CInt' in the type definition (rather
-- than 'Data.Word.Word32'). For this reason, /if/ the sign was compiler inferred, we
-- record this as a special case, so that we can generate 'Foreign.C.Types.CChar' instead of
-- 'Foreign.C.Types.CUChar' or 'Foreign.C.Types.CSChar'.
data PrimSignChar =
-- | User explicitly specified sign
PrimSignExplicit PrimSign
-- | Sign was left implicit
--
-- In most cases we know the compiler-determined sign, but currently not in
-- all cases. That's probably fixable but it's not trivial; at present we
-- don't need the information and so we can leave this as a 'Maybe'.
| PrimSignImplicit (Maybe PrimSign)
deriving stock (Show, Eq, Ord, Generic)
{-------------------------------------------------------------------------------
Pretty-printing
-------------------------------------------------------------------------------}
showsPrimType :: PrimType -> ShowS
showsPrimType (PrimChar (PrimSignImplicit _)) = showString "char"
showsPrimType (PrimChar (PrimSignExplicit s)) = showsPrimSign s . showString " char"
showsPrimType (PrimIntegral i s) = showsPrimSign s . showChar ' ' . showsPrimIntType i
showsPrimType (PrimFloating f) = showsPrimFloatType f
showsPrimType PrimBool = showString "_Bool"
showsPrimIntType :: PrimIntType -> ShowS
showsPrimIntType PrimShort = showString "short"
showsPrimIntType PrimInt = showString "int"
showsPrimIntType PrimLong = showString "long"
showsPrimIntType PrimLongLong = showString "long long"
showsPrimFloatType :: PrimFloatType -> ShowS
showsPrimFloatType PrimFloat = showString "float"
showsPrimFloatType PrimDouble = showString "double"
showsPrimSign :: PrimSign -> ShowS
showsPrimSign Signed = showString "signed"
showsPrimSign Unsigned = showString "unsigned"
{-------------------------------------------------------------------------------
Sign
-------------------------------------------------------------------------------}
-- | Determine the sign of a primitive type
--
primTypeSign :: PrimType -> PrimSign
primTypeSign = \case
PrimChar (PrimSignExplicit sign) -> sign
PrimChar (PrimSignImplicit (Just sign)) -> sign
PrimChar (PrimSignImplicit Nothing) -> Signed
PrimIntegral _ sign -> sign
PrimFloating _ -> Signed
PrimBool -> Unsigned