{-# LANGUAGE DeriveGeneric #-}

module Generic.Address (GenericAddress(..), AddressWord64(..)) where

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

-- | A type for encapsulating an immediate (allows to always show hex)
newtype AddressWord64 = AddressWord64 Word64
  deriving (AddressWord64 -> AddressWord64 -> Bool
(AddressWord64 -> AddressWord64 -> Bool)
-> (AddressWord64 -> AddressWord64 -> Bool) -> Eq AddressWord64
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AddressWord64 -> AddressWord64 -> Bool
$c/= :: AddressWord64 -> AddressWord64 -> Bool
== :: AddressWord64 -> AddressWord64 -> Bool
$c== :: AddressWord64 -> AddressWord64 -> Bool
Eq, Eq AddressWord64
Eq AddressWord64
-> (AddressWord64 -> AddressWord64 -> Ordering)
-> (AddressWord64 -> AddressWord64 -> Bool)
-> (AddressWord64 -> AddressWord64 -> Bool)
-> (AddressWord64 -> AddressWord64 -> Bool)
-> (AddressWord64 -> AddressWord64 -> Bool)
-> (AddressWord64 -> AddressWord64 -> AddressWord64)
-> (AddressWord64 -> AddressWord64 -> AddressWord64)
-> Ord AddressWord64
AddressWord64 -> AddressWord64 -> Bool
AddressWord64 -> AddressWord64 -> Ordering
AddressWord64 -> AddressWord64 -> AddressWord64
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
min :: AddressWord64 -> AddressWord64 -> AddressWord64
$cmin :: AddressWord64 -> AddressWord64 -> AddressWord64
max :: AddressWord64 -> AddressWord64 -> AddressWord64
$cmax :: AddressWord64 -> AddressWord64 -> AddressWord64
>= :: AddressWord64 -> AddressWord64 -> Bool
$c>= :: AddressWord64 -> AddressWord64 -> Bool
> :: AddressWord64 -> AddressWord64 -> Bool
$c> :: AddressWord64 -> AddressWord64 -> Bool
<= :: AddressWord64 -> AddressWord64 -> Bool
$c<= :: AddressWord64 -> AddressWord64 -> Bool
< :: AddressWord64 -> AddressWord64 -> Bool
$c< :: AddressWord64 -> AddressWord64 -> Bool
compare :: AddressWord64 -> AddressWord64 -> Ordering
$ccompare :: AddressWord64 -> AddressWord64 -> Ordering
$cp1Ord :: Eq AddressWord64
Ord, (forall x. AddressWord64 -> Rep AddressWord64 x)
-> (forall x. Rep AddressWord64 x -> AddressWord64)
-> Generic AddressWord64
forall x. Rep AddressWord64 x -> AddressWord64
forall x. AddressWord64 -> Rep AddressWord64 x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AddressWord64 x -> AddressWord64
$cfrom :: forall x. AddressWord64 -> Rep AddressWord64 x
Generic)

instance Cereal.Serialize AddressWord64
instance NFData AddressWord64


-- | An unresolved address, within the operand of an instruction, based on polymorphic type `storage`.
data GenericAddress storage =
    AddressStorage storage                                         -- ^ Reading a pointer from a storage
  | AddressImm Word64                                              -- ^ Immediate value 
  | AddressMinus (GenericAddress storage) (GenericAddress storage) -- ^ Minus
  | AddressPlus (GenericAddress storage) (GenericAddress storage)  -- ^ Plus
  | AddressTimes (GenericAddress storage) (GenericAddress storage) -- ^ Times
  deriving (GenericAddress storage -> GenericAddress storage -> Bool
(GenericAddress storage -> GenericAddress storage -> Bool)
-> (GenericAddress storage -> GenericAddress storage -> Bool)
-> Eq (GenericAddress storage)
forall storage.
Eq storage =>
GenericAddress storage -> GenericAddress storage -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GenericAddress storage -> GenericAddress storage -> Bool
$c/= :: forall storage.
Eq storage =>
GenericAddress storage -> GenericAddress storage -> Bool
== :: GenericAddress storage -> GenericAddress storage -> Bool
$c== :: forall storage.
Eq storage =>
GenericAddress storage -> GenericAddress storage -> Bool
Eq, Eq (GenericAddress storage)
Eq (GenericAddress storage)
-> (GenericAddress storage -> GenericAddress storage -> Ordering)
-> (GenericAddress storage -> GenericAddress storage -> Bool)
-> (GenericAddress storage -> GenericAddress storage -> Bool)
-> (GenericAddress storage -> GenericAddress storage -> Bool)
-> (GenericAddress storage -> GenericAddress storage -> Bool)
-> (GenericAddress storage
    -> GenericAddress storage -> GenericAddress storage)
-> (GenericAddress storage
    -> GenericAddress storage -> GenericAddress storage)
-> Ord (GenericAddress storage)
GenericAddress storage -> GenericAddress storage -> Bool
GenericAddress storage -> GenericAddress storage -> Ordering
GenericAddress storage
-> GenericAddress storage -> GenericAddress 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 (GenericAddress storage)
forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Bool
forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Ordering
forall storage.
Ord storage =>
GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
min :: GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
$cmin :: forall storage.
Ord storage =>
GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
max :: GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
$cmax :: forall storage.
Ord storage =>
GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
>= :: GenericAddress storage -> GenericAddress storage -> Bool
$c>= :: forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Bool
> :: GenericAddress storage -> GenericAddress storage -> Bool
$c> :: forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Bool
<= :: GenericAddress storage -> GenericAddress storage -> Bool
$c<= :: forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Bool
< :: GenericAddress storage -> GenericAddress storage -> Bool
$c< :: forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Bool
compare :: GenericAddress storage -> GenericAddress storage -> Ordering
$ccompare :: forall storage.
Ord storage =>
GenericAddress storage -> GenericAddress storage -> Ordering
$cp1Ord :: forall storage. Ord storage => Eq (GenericAddress storage)
Ord, (forall x.
 GenericAddress storage -> Rep (GenericAddress storage) x)
-> (forall x.
    Rep (GenericAddress storage) x -> GenericAddress storage)
-> Generic (GenericAddress storage)
forall x. Rep (GenericAddress storage) x -> GenericAddress storage
forall x. GenericAddress storage -> Rep (GenericAddress storage) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall storage x.
Rep (GenericAddress storage) x -> GenericAddress storage
forall storage x.
GenericAddress storage -> Rep (GenericAddress storage) x
$cto :: forall storage x.
Rep (GenericAddress storage) x -> GenericAddress storage
$cfrom :: forall storage x.
GenericAddress storage -> Rep (GenericAddress storage) x
Generic)

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

instance Show storage => Show (GenericAddress storage) where
  show :: GenericAddress storage -> String
show (AddressStorage storage
st) = storage -> String
forall a. Show a => a -> String
show storage
st
  show (AddressImm Word64
imm) = Word64 -> String
forall a. (Integral a, Show a) => a -> String
showHex Word64
imm
  show (AddressMinus GenericAddress storage
a0 GenericAddress storage
a1) = GenericAddress storage -> String
forall a. Show a => a -> String
show GenericAddress storage
a0 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
a1
  show (AddressPlus GenericAddress storage
a0 GenericAddress storage
a1) = GenericAddress storage -> String
forall a. Show a => a -> String
show GenericAddress storage
a0 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
a1
  show (AddressTimes GenericAddress storage
a0 GenericAddress storage
a1) = GenericAddress storage -> String
forall a. Show a => a -> String
show GenericAddress storage
a0 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
a1

instance Show AddressWord64 where
  show :: AddressWord64 -> String
show (AddressWord64 Word64
a) = Word64 -> String
forall a. (Integral a, Show a) => a -> String
showHex Word64
a

instance Functor GenericAddress where
  fmap :: (a -> b) -> GenericAddress a -> GenericAddress b
fmap a -> b
f (AddressStorage a
s) = b -> GenericAddress b
forall storage. storage -> GenericAddress storage
AddressStorage (b -> GenericAddress b) -> b -> GenericAddress b
forall a b. (a -> b) -> a -> b
$ a -> b
f a
s
  fmap a -> b
f (AddressImm Word64
val) = Word64 -> GenericAddress b
forall storage. Word64 -> GenericAddress storage
AddressImm Word64
val
  fmap a -> b
f (AddressMinus GenericAddress a
a1 GenericAddress a
a2) = GenericAddress b -> GenericAddress b -> GenericAddress b
forall storage.
GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
AddressMinus (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
a1) (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
a2)
  fmap a -> b
f (AddressPlus GenericAddress a
a1 GenericAddress a
a2) = GenericAddress b -> GenericAddress b -> GenericAddress b
forall storage.
GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
AddressPlus (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
a1) (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
a2)
  fmap a -> b
f (AddressTimes GenericAddress a
a1 GenericAddress a
a2) = GenericAddress b -> GenericAddress b -> GenericAddress b
forall storage.
GenericAddress storage
-> GenericAddress storage -> GenericAddress storage
AddressTimes (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
a1) (a -> b
f (a -> b) -> GenericAddress a -> GenericAddress b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenericAddress a
a2)