----------------------------------------------------------------------------- -- | -- Module : Data.SBV.BitVectors.PrettyNum -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer : erkokl@gmail.com -- Stability : experimental -- Portability : portable -- -- Number representations in hex/bin ----------------------------------------------------------------------------- {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE PatternGuards #-} module Data.SBV.BitVectors.PrettyNum (PrettyNum(..), readBin) where import Data.Maybe(fromJust) import Data.Char(ord) import Data.List(isPrefixOf) import Data.Int import Data.Word import Numeric import Data.SBV.BitVectors.Bit import Data.SBV.BitVectors.Data import Data.SBV.BitVectors.Model () -- instances only -- | PrettyNum class captures printing of numbers in hex and binary formats; also supporting negative numbers. -- -- Minimal complete definition: 'hexS' and 'binS' class PrettyNum a where -- | Show a number in hexadecimal (starting with @0x@) hexS :: a -> String -- | Show a number in binary (starting with @0b@) binS :: a -> String -- | IO version of 'hexS' hex :: a -> IO () hex = putStrLn . hexS -- | IO version of 'binS' bin :: a -> IO () bin = putStrLn . binS -- Why not default methods? Because defaults need "Integral a" and Bool/Bit are not.. instance PrettyNum Bool where {hexS = show; binS = show} instance PrettyNum Bit where {hexS = show; binS = show} instance PrettyNum Word8 where {hexS = shex; binS = sbin} instance PrettyNum Int8 where {hexS = shex; binS = sbin} instance PrettyNum Word16 where {hexS = shex; binS = sbin} instance PrettyNum Int16 where {hexS = shex; binS = sbin} instance PrettyNum Word32 where {hexS = shex; binS = sbin} instance PrettyNum Int32 where {hexS = shex; binS = sbin} instance PrettyNum Word64 where {hexS = shex; binS = sbin} instance PrettyNum Int64 where {hexS = shex; binS = sbin} instance PrettyNum CW where hexS (W1 i) = hexS $ bit2Bool i hexS (W8 i) = hexS i hexS (W16 i) = hexS i hexS (W32 i) = hexS i hexS (W64 i) = hexS i hexS (I8 i) = hexS i hexS (I16 i) = hexS i hexS (I32 i) = hexS i hexS (I64 i) = hexS i binS (W1 i) = binS $ bit2Bool i binS (W8 i) = binS i binS (W16 i) = binS i binS (W32 i) = binS i binS (W64 i) = binS i binS (I8 i) = binS i binS (I16 i) = binS i binS (I32 i) = binS i binS (I64 i) = binS i instance (SymWord a, PrettyNum a) => PrettyNum (SBV a) where hexS s = maybe (show s) (hexS :: a -> String) $ unliteral s binS s = maybe (show s) (binS :: a -> String) $ unliteral s shex :: (HasSignAndSize a, Integral a) => a -> String shex a | a < 0 = "-0x" ++ pad l (s16 (abs ((fromIntegral a) :: Integer))) ++ t | True = "0x" ++ pad l (s16 a) ++ t where t = " :: " ++ (if hasSign a then "Int" else "Word") ++ show (l*4) l = sizeOf a `div` 4 sbin :: (HasSignAndSize a, Integral a) => a -> String sbin a | a < 0 = "-0b" ++ pad l (s2 (abs ((fromIntegral a) :: Integer))) ++ t | True = "0b" ++ pad l (s2 a) ++ t where t = " :: " ++ (if hasSign a then "Int" else "Word") ++ show l l = sizeOf a pad :: Int -> String -> String pad l s = replicate (l - length s) '0' ++ s s2, s16 :: Integral a => a -> String s2 v = showIntAtBase 2 dig v "" where dig = fromJust . flip lookup [(0, '0'), (1, '1')] s16 v = showHex v "" -- | A more convenient interface for reading binary numbers, also supports negative numbers readBin :: Num a => String -> a readBin ('-':s) = -(readBin s) readBin s = case readInt 2 isDigit cvt s' of [(a, "")] -> a _ -> error $ "SBV.readBin: Cannot read a binary number from: " ++ show s where cvt c = ord c - ord '0' isDigit = (`elem` "01") s' | "0b" `isPrefixOf` s = drop 2 s | True = s