{-# LANGUAGE DeriveGeneric #-}

module Generic.Operand (GenericOperand(..)) where

import           Generic.Address (GenericAddress)
import           Data.Word (Word64)
import           GHC.Generics (Generic)
import qualified Data.Serialize as Cereal
import           Base (showHex)
import           Generic.HasSize (HasSize(sizeof))
import           Control.DeepSeq

-- | A generic statepart, based on polymorphic type `storage`.
data GenericOperand storage =
    Memory (GenericAddress storage) Int -- ^ A region in memory, whose address is stored in the given state part and whose size in bytes is given in the Int
  | EffectiveAddress (GenericAddress storage)     -- ^ An address itself, but not the value stored at the address.
  | Storage storage                      -- ^ A storage location such as a register or a variable
  | Immediate Word64                       -- ^ An immediate value
  deriving (GenericOperand storage -> GenericOperand storage -> Bool
(GenericOperand storage -> GenericOperand storage -> Bool)
-> (GenericOperand storage -> GenericOperand storage -> Bool)
-> Eq (GenericOperand storage)
forall storage.
Eq storage =>
GenericOperand storage -> GenericOperand storage -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GenericOperand storage -> GenericOperand storage -> Bool
$c/= :: forall storage.
Eq storage =>
GenericOperand storage -> GenericOperand storage -> Bool
== :: GenericOperand storage -> GenericOperand storage -> Bool
$c== :: forall storage.
Eq storage =>
GenericOperand storage -> GenericOperand storage -> Bool
Eq, Eq (GenericOperand storage)
Eq (GenericOperand storage)
-> (GenericOperand storage -> GenericOperand storage -> Ordering)
-> (GenericOperand storage -> GenericOperand storage -> Bool)
-> (GenericOperand storage -> GenericOperand storage -> Bool)
-> (GenericOperand storage -> GenericOperand storage -> Bool)
-> (GenericOperand storage -> GenericOperand storage -> Bool)
-> (GenericOperand storage
    -> GenericOperand storage -> GenericOperand storage)
-> (GenericOperand storage
    -> GenericOperand storage -> GenericOperand storage)
-> Ord (GenericOperand storage)
GenericOperand storage -> GenericOperand storage -> Bool
GenericOperand storage -> GenericOperand storage -> Ordering
GenericOperand storage
-> GenericOperand storage -> GenericOperand storage
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
forall storage. Ord storage => Eq (GenericOperand storage)
forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Bool
forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Ordering
forall storage.
Ord storage =>
GenericOperand storage
-> GenericOperand storage -> GenericOperand storage
min :: GenericOperand storage
-> GenericOperand storage -> GenericOperand storage
$cmin :: forall storage.
Ord storage =>
GenericOperand storage
-> GenericOperand storage -> GenericOperand storage
max :: GenericOperand storage
-> GenericOperand storage -> GenericOperand storage
$cmax :: forall storage.
Ord storage =>
GenericOperand storage
-> GenericOperand storage -> GenericOperand storage
>= :: GenericOperand storage -> GenericOperand storage -> Bool
$c>= :: forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Bool
> :: GenericOperand storage -> GenericOperand storage -> Bool
$c> :: forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Bool
<= :: GenericOperand storage -> GenericOperand storage -> Bool
$c<= :: forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Bool
< :: GenericOperand storage -> GenericOperand storage -> Bool
$c< :: forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Bool
compare :: GenericOperand storage -> GenericOperand storage -> Ordering
$ccompare :: forall storage.
Ord storage =>
GenericOperand storage -> GenericOperand storage -> Ordering
$cp1Ord :: forall storage. Ord storage => Eq (GenericOperand storage)
Ord, (forall x.
 GenericOperand storage -> Rep (GenericOperand storage) x)
-> (forall x.
    Rep (GenericOperand storage) x -> GenericOperand storage)
-> Generic (GenericOperand storage)
forall x. Rep (GenericOperand storage) x -> GenericOperand storage
forall x. GenericOperand storage -> Rep (GenericOperand storage) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall storage x.
Rep (GenericOperand storage) x -> GenericOperand storage
forall storage x.
GenericOperand storage -> Rep (GenericOperand storage) x
$cto :: forall storage x.
Rep (GenericOperand storage) x -> GenericOperand storage
$cfrom :: forall storage x.
GenericOperand storage -> Rep (GenericOperand storage) x
Generic)

instance (Cereal.Serialize storage) => Cereal.Serialize (GenericOperand storage)
instance (NFData storage) => NFData (GenericOperand storage)

instance Show storage => Show (GenericOperand storage) where
  show :: GenericOperand storage -> String
show (EffectiveAddress GenericAddress storage
addr) = String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ GenericAddress storage -> String
forall a. Show a => a -> String
show GenericAddress storage
addr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"
  show (Storage storage
st) = storage -> String
forall a. Show a => a -> String
show storage
st
  show (Immediate Word64
imm) = Word64 -> String
forall a. (Integral a, Show a) => a -> String
showHex Word64
imm
  show (Memory GenericAddress storage
addr Int
si) =
    Int -> String
forall a. (Eq a, Num a, Show a) => a -> String
showSize Int
si String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" [" String -> ShowS
forall a. [a] -> [a] -> [a]
++ GenericAddress storage -> String
forall a. Show a => a -> String
show GenericAddress storage
addr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"," String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
si String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"
    where
      showSize :: a -> String
showSize a
1 = String
"BYTE PTR"
      showSize a
2 = String
"WORD PTR"
      showSize a
4 = String
"DWORD PTR"
      showSize a
8 = String
"QWORD PTR"
      showSize a
16 = String
"XMMWORD PTR"
      showSize a
32 = String
"YMMWORD PTR"
      showSize a
si = a -> String
forall a. Show a => a -> String
show (a
si a -> a -> a
forall a. Num a => a -> a -> a
* a
8) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" PTR"

instance (HasSize storage) => HasSize (GenericOperand storage) where
  sizeof :: GenericOperand storage -> Int
sizeof (Storage storage
r) = storage -> Int
forall a. HasSize a => a -> Int
sizeof storage
r
  sizeof (Memory GenericAddress storage
_ Int
si) = Int
si
  sizeof (EffectiveAddress GenericAddress storage
_) = Int
8
  sizeof (Immediate Word64
_) = Int
8

instance Functor GenericOperand where
  fmap :: (a -> b) -> GenericOperand a -> GenericOperand b
fmap a -> b
f (Memory GenericAddress a
addr Int
size) = GenericAddress b -> Int -> GenericOperand b
forall storage.
GenericAddress storage -> Int -> GenericOperand storage
Memory (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
addr) Int
size
  fmap a -> b
f (EffectiveAddress GenericAddress a
addr) = GenericAddress b -> GenericOperand b
forall storage. GenericAddress storage -> GenericOperand storage
EffectiveAddress (GenericAddress b -> GenericOperand b)
-> GenericAddress b -> GenericOperand b
forall a b. (a -> b) -> a -> b
$ a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
addr
  fmap a -> b
f (Storage a
s) = b -> GenericOperand b
forall storage. storage -> GenericOperand storage
Storage (b -> GenericOperand b) -> b -> GenericOperand b
forall a b. (a -> b) -> a -> b
$ a -> b
f a
s
  fmap a -> b
_ (Immediate Word64
imm) = Word64 -> GenericOperand b
forall storage. Word64 -> GenericOperand storage
Immediate Word64
imm