packages feed

c-expr-dsl-0.1.0.0: src/C/Expr/Syntax/Literal.hs

module C.Expr.Syntax.Literal (
    IntegerLiteral(..)
  , FloatingLiteral(..)
  , CharLiteral(..)
  , StringLiteral(..)
    -- * Auxiliary
  , canBeRepresentedAsRational
  ) where

import Data.ByteString (ByteString)
import Foreign.C (CChar)
import GHC.Generics (Generic)

import C.Type qualified as Runtime

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

-- | Integer literal
data IntegerLiteral =
  IntegerLiteral {
      -- | The type of the integer literal, as determined from suffixes.
      integerLiteralType  :: Runtime.IntLikeType

      -- | The (parsed) value of the literal
    , integerLiteralValue :: Integer
    }
  deriving stock ( Eq, Ord, Show, Generic )

-- | Floating-point literal
data FloatingLiteral =
  FloatingLiteral {
      -- | The type of the floating-point literal, as determined from suffixes.
      floatingLiteralType  :: Runtime.FloatingType

      -- | The (parsed) value of the literal, when parsed as a single precision
      -- floating-point value.
    , floatingLiteralFloatValue :: Float

      -- | The (parsed) value of the literal, when parsed as a double precision
      -- floating-point value.
    , floatingLiteralDoubleValue :: Double
    }
  deriving stock ( Eq, Ord, Show, Generic )

-- | A C character literal.
--
-- The value is represented as a 'CChar'. Wide character literals (prefixed
-- with @L@, @u@, @U@, or @u8@) and characters whose value does not fit in a
-- single byte are rejected during parsing (see
-- 'C.Expr.Parse.Literal.parseLiteralChar').
newtype CharLiteral = CharLiteral { charLiteralValue :: CChar }
  deriving stock ( Eq, Ord, Show, Generic )

-- | A C string literal.
--
-- 'stringLiteralValue' holds the /execution-encoding bytes/ of the literal,
-- assuming a UTF-8 execution character set.  The representation is
-- /bit-for-bit accurate/: the bytes are exactly what a C compiler targeting a
-- UTF-8 execution charset would embed in the object file.  This property is
-- required because the generated Haskell bindings may be passed directly to C
-- functions that expect the same byte sequence (see
-- 'C.Expr.Parse.Literal.parseLiteralString' for the encoding rules).
newtype StringLiteral = StringLiteral { stringLiteralValue :: ByteString }
  deriving stock ( Eq, Ord, Show, Generic )

{-------------------------------------------------------------------------------
  Auxiliary functions
-------------------------------------------------------------------------------}

{-# SPECIALISE canBeRepresentedAsRational :: Float  -> Bool #-}
{-# SPECIALISE canBeRepresentedAsRational :: Double -> Bool #-}

-- | Can this floating-point value be represented (losslessly) as a 'Rational'?
canBeRepresentedAsRational :: RealFloat a => a -> Bool
canBeRepresentedAsRational f = not $ or
  [ isNaN f
  , isInfinite f
  , isNegativeZero f
  , isDenormalized f -- not strictly necessary, but let's be conservative
  ]