    {-|
      Copyright   :  (C) 2012-2016, University of Twente,
                         2016     , Myrtle Software Ltd,
                         2017     , Google Inc.,
                         2021     , QBayLogic B.V.
      License     :  BSD2 (see the file LICENSE)
      Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>

      Term Literal
    -}

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE DeriveAnyClass #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE MultiParamTypeClasses #-}

    module Clash.Core.Literal
      ( Literal (..)
      ) where

    import Control.DeepSeq                        (NFData (..))
    import Data.Binary                            (Binary)
    import Data.Hashable                          (Hashable)
    import Data.Primitive.ByteArray               (ByteArray)
    import Data.Primitive.ByteArray.Extra         ()
    import Data.Word                              (Word32, Word64)
    import GHC.Generics                           (Generic)

    {-
    Note [Storage of floating point in Literal]
    -------------------------------------------

    GHC stores literals of 'Float' and 'Double' as 'Rational'. However, unlike
    GHC, we also need to store transfinite "literals". We need to preserve all
    information there is in a specific code word representing a floating point
    value.

    Storing them as 'Float' and 'Double' here introduces issues with 'Eq' and
    'Hashable'. 0.0 == -0.0, and NaN compares unequal to everything including
    itself.

    Also unlike GHC, we already assume that 'Float' is single-precision IEEE-754,
    and 'Double' is double-precision IEEE-754. So we can store them as 'Word32'
    and 'Word64' and get the 'Eq' and hashing properties we require.
    -}

    -- | Term Literal
    data Literal
      = IntegerLiteral  !Integer
      | IntLiteral      !Integer
      | WordLiteral     !Integer
      | Int64Literal    !Integer
      | Word64Literal   !Integer
    #if MIN_VERSION_ghc(8,8,0)
      | Int8Literal     !Integer
      | Int16Literal    !Integer
      | Int32Literal    !Integer
      | Word8Literal    !Integer
      | Word16Literal   !Integer
      | Word32Literal   !Integer
    #endif
      | StringLiteral   !String
      | FloatLiteral    !Word32
      | DoubleLiteral   !Word64
      | CharLiteral     !Char
      | NaturalLiteral  !Integer
      | ByteArrayLiteral !ByteArray
      deriving (Literal -> Literal -> Bool
    (Literal -> Literal -> Bool)
    -> (Literal -> Literal -> Bool) -> Eq Literal
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Literal -> Literal -> Bool
    == :: Literal -> Literal -> Bool
    $c/= :: Literal -> Literal -> Bool
    /= :: Literal -> Literal -> Bool
    Eq,Eq Literal
    Eq Literal =>
    (Literal -> Literal -> Ordering)
    -> (Literal -> Literal -> Bool)
    -> (Literal -> Literal -> Bool)
    -> (Literal -> Literal -> Bool)
    -> (Literal -> Literal -> Bool)
    -> (Literal -> Literal -> Literal)
    -> (Literal -> Literal -> Literal)
    -> Ord Literal
    Literal -> Literal -> Bool
    Literal -> Literal -> Ordering
    Literal -> Literal -> Literal
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Literal -> Literal -> Ordering
    compare :: Literal -> Literal -> Ordering
    $c< :: Literal -> Literal -> Bool
    < :: Literal -> Literal -> Bool
    $c<= :: Literal -> Literal -> Bool
    <= :: Literal -> Literal -> Bool
    $c> :: Literal -> Literal -> Bool
    > :: Literal -> Literal -> Bool
    $c>= :: Literal -> Literal -> Bool
    >= :: Literal -> Literal -> Bool
    $cmax :: Literal -> Literal -> Literal
    max :: Literal -> Literal -> Literal
    $cmin :: Literal -> Literal -> Literal
    min :: Literal -> Literal -> Literal
    Ord,Int -> Literal -> ShowS
    [Literal] -> ShowS
    Literal -> String
    (Int -> Literal -> ShowS)
    -> (Literal -> String) -> ([Literal] -> ShowS) -> Show Literal
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Literal -> ShowS
    showsPrec :: Int -> Literal -> ShowS
    $cshow :: Literal -> String
    show :: Literal -> String
    $cshowList :: [Literal] -> ShowS
    showList :: [Literal] -> ShowS
    Show,(forall x. Literal -> Rep Literal x)
    -> (forall x. Rep Literal x -> Literal) -> Generic Literal
    forall x. Rep Literal x -> Literal
    forall x. Literal -> Rep Literal x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Literal -> Rep Literal x
    from :: forall x. Literal -> Rep Literal x
    $cto :: forall x. Rep Literal x -> Literal
    to :: forall x. Rep Literal x -> Literal
    Generic,Literal -> ()
    (Literal -> ()) -> NFData Literal
    forall a. (a -> ()) -> NFData a
    $crnf :: Literal -> ()
    rnf :: Literal -> ()
    NFData,Eq Literal
    Eq Literal =>
    (Int -> Literal -> Int) -> (Literal -> Int) -> Hashable Literal
    Int -> Literal -> Int
    Literal -> Int
    forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
    $chashWithSalt :: Int -> Literal -> Int
    hashWithSalt :: Int -> Literal -> Int
    $chash :: Literal -> Int
    hash :: Literal -> Int
    Hashable,Get Literal
    [Literal] -> Put
    Literal -> Put
    (Literal -> Put)
    -> Get Literal -> ([Literal] -> Put) -> Binary Literal
    forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
    $cput :: Literal -> Put
    put :: Literal -> Put
    $cget :: Get Literal
    get :: Get Literal
    $cputList :: [Literal] -> Put
    putList :: [Literal] -> Put
    Binary)