{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module Clash.Annotations.BitRepresentation.Internal
( buildCustomReprs
, dataReprAnnToDataRepr'
, constrReprToConstrRepr'
, getConstrRepr
, uncheckedGetConstrRepr
, getDataRepr
, thTypeToType'
, ConstrRepr'(..)
, DataRepr'(..)
, Type'(..)
, CustomReprs
) where
import Clash.Annotations.BitRepresentation
(BitMask, Value, Size, FieldAnn, DataReprAnn(..), ConstrRepr(..))
import Control.DeepSeq (NFData)
import Data.Hashable (Hashable)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import qualified Data.Text as Text
import Data.Typeable (Typeable)
import qualified Language.Haskell.TH.Syntax as TH
import GHC.Generics (Generic)
import GHC.Stack (HasCallStack)
data Type'
= AppTy' Type' Type'
| ConstTy' Text.Text
| LitTy' Integer
| SymLitTy' Text.Text
deriving ((forall x. Type' -> Rep Type' x)
-> (forall x. Rep Type' x -> Type') -> Generic Type'
forall x. Rep Type' x -> Type'
forall x. Type' -> Rep Type' x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Type' x -> Type'
$cfrom :: forall x. Type' -> Rep Type' x
Generic, Type' -> ()
(Type' -> ()) -> NFData Type'
forall a. (a -> ()) -> NFData a
rnf :: Type' -> ()
$crnf :: Type' -> ()
NFData, Type' -> Type' -> Bool
(Type' -> Type' -> Bool) -> (Type' -> Type' -> Bool) -> Eq Type'
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Type' -> Type' -> Bool
$c/= :: Type' -> Type' -> Bool
== :: Type' -> Type' -> Bool
$c== :: Type' -> Type' -> Bool
Eq, Typeable, Eq Type'
Eq Type'
-> (Int -> Type' -> Int) -> (Type' -> Int) -> Hashable Type'
Int -> Type' -> Int
Type' -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Type' -> Int
$chash :: Type' -> Int
hashWithSalt :: Int -> Type' -> Int
$chashWithSalt :: Int -> Type' -> Int
$cp1Hashable :: Eq Type'
Hashable, Eq Type'
Eq Type'
-> (Type' -> Type' -> Ordering)
-> (Type' -> Type' -> Bool)
-> (Type' -> Type' -> Bool)
-> (Type' -> Type' -> Bool)
-> (Type' -> Type' -> Bool)
-> (Type' -> Type' -> Type')
-> (Type' -> Type' -> Type')
-> Ord Type'
Type' -> Type' -> Bool
Type' -> Type' -> Ordering
Type' -> Type' -> Type'
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 :: Type' -> Type' -> Type'
$cmin :: Type' -> Type' -> Type'
max :: Type' -> Type' -> Type'
$cmax :: Type' -> Type' -> Type'
>= :: Type' -> Type' -> Bool
$c>= :: Type' -> Type' -> Bool
> :: Type' -> Type' -> Bool
$c> :: Type' -> Type' -> Bool
<= :: Type' -> Type' -> Bool
$c<= :: Type' -> Type' -> Bool
< :: Type' -> Type' -> Bool
$c< :: Type' -> Type' -> Bool
compare :: Type' -> Type' -> Ordering
$ccompare :: Type' -> Type' -> Ordering
$cp1Ord :: Eq Type'
Ord, Int -> Type' -> ShowS
[Type'] -> ShowS
Type' -> String
(Int -> Type' -> ShowS)
-> (Type' -> String) -> ([Type'] -> ShowS) -> Show Type'
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Type'] -> ShowS
$cshowList :: [Type'] -> ShowS
show :: Type' -> String
$cshow :: Type' -> String
showsPrec :: Int -> Type' -> ShowS
$cshowsPrec :: Int -> Type' -> ShowS
Show)
data DataRepr' = DataRepr'
{ DataRepr' -> Type'
drType :: Type'
, DataRepr' -> Int
drSize :: Size
, DataRepr' -> [ConstrRepr']
drConstrs :: [ConstrRepr']
}
deriving (Int -> DataRepr' -> ShowS
[DataRepr'] -> ShowS
DataRepr' -> String
(Int -> DataRepr' -> ShowS)
-> (DataRepr' -> String)
-> ([DataRepr'] -> ShowS)
-> Show DataRepr'
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DataRepr'] -> ShowS
$cshowList :: [DataRepr'] -> ShowS
show :: DataRepr' -> String
$cshow :: DataRepr' -> String
showsPrec :: Int -> DataRepr' -> ShowS
$cshowsPrec :: Int -> DataRepr' -> ShowS
Show, (forall x. DataRepr' -> Rep DataRepr' x)
-> (forall x. Rep DataRepr' x -> DataRepr') -> Generic DataRepr'
forall x. Rep DataRepr' x -> DataRepr'
forall x. DataRepr' -> Rep DataRepr' x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep DataRepr' x -> DataRepr'
$cfrom :: forall x. DataRepr' -> Rep DataRepr' x
Generic, DataRepr' -> ()
(DataRepr' -> ()) -> NFData DataRepr'
forall a. (a -> ()) -> NFData a
rnf :: DataRepr' -> ()
$crnf :: DataRepr' -> ()
NFData, DataRepr' -> DataRepr' -> Bool
(DataRepr' -> DataRepr' -> Bool)
-> (DataRepr' -> DataRepr' -> Bool) -> Eq DataRepr'
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DataRepr' -> DataRepr' -> Bool
$c/= :: DataRepr' -> DataRepr' -> Bool
== :: DataRepr' -> DataRepr' -> Bool
$c== :: DataRepr' -> DataRepr' -> Bool
Eq, Typeable, Eq DataRepr'
Eq DataRepr'
-> (Int -> DataRepr' -> Int)
-> (DataRepr' -> Int)
-> Hashable DataRepr'
Int -> DataRepr' -> Int
DataRepr' -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: DataRepr' -> Int
$chash :: DataRepr' -> Int
hashWithSalt :: Int -> DataRepr' -> Int
$chashWithSalt :: Int -> DataRepr' -> Int
$cp1Hashable :: Eq DataRepr'
Hashable, Eq DataRepr'
Eq DataRepr'
-> (DataRepr' -> DataRepr' -> Ordering)
-> (DataRepr' -> DataRepr' -> Bool)
-> (DataRepr' -> DataRepr' -> Bool)
-> (DataRepr' -> DataRepr' -> Bool)
-> (DataRepr' -> DataRepr' -> Bool)
-> (DataRepr' -> DataRepr' -> DataRepr')
-> (DataRepr' -> DataRepr' -> DataRepr')
-> Ord DataRepr'
DataRepr' -> DataRepr' -> Bool
DataRepr' -> DataRepr' -> Ordering
DataRepr' -> DataRepr' -> DataRepr'
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 :: DataRepr' -> DataRepr' -> DataRepr'
$cmin :: DataRepr' -> DataRepr' -> DataRepr'
max :: DataRepr' -> DataRepr' -> DataRepr'
$cmax :: DataRepr' -> DataRepr' -> DataRepr'
>= :: DataRepr' -> DataRepr' -> Bool
$c>= :: DataRepr' -> DataRepr' -> Bool
> :: DataRepr' -> DataRepr' -> Bool
$c> :: DataRepr' -> DataRepr' -> Bool
<= :: DataRepr' -> DataRepr' -> Bool
$c<= :: DataRepr' -> DataRepr' -> Bool
< :: DataRepr' -> DataRepr' -> Bool
$c< :: DataRepr' -> DataRepr' -> Bool
compare :: DataRepr' -> DataRepr' -> Ordering
$ccompare :: DataRepr' -> DataRepr' -> Ordering
$cp1Ord :: Eq DataRepr'
Ord)
data ConstrRepr' = ConstrRepr'
{ ConstrRepr' -> Text
crName :: Text.Text
, ConstrRepr' -> Int
crPosition :: Int
, ConstrRepr' -> BitMask
crMask :: BitMask
, ConstrRepr' -> BitMask
crValue :: Value
, ConstrRepr' -> [BitMask]
crFieldAnns :: [FieldAnn]
}
deriving (Int -> ConstrRepr' -> ShowS
[ConstrRepr'] -> ShowS
ConstrRepr' -> String
(Int -> ConstrRepr' -> ShowS)
-> (ConstrRepr' -> String)
-> ([ConstrRepr'] -> ShowS)
-> Show ConstrRepr'
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ConstrRepr'] -> ShowS
$cshowList :: [ConstrRepr'] -> ShowS
show :: ConstrRepr' -> String
$cshow :: ConstrRepr' -> String
showsPrec :: Int -> ConstrRepr' -> ShowS
$cshowsPrec :: Int -> ConstrRepr' -> ShowS
Show, (forall x. ConstrRepr' -> Rep ConstrRepr' x)
-> (forall x. Rep ConstrRepr' x -> ConstrRepr')
-> Generic ConstrRepr'
forall x. Rep ConstrRepr' x -> ConstrRepr'
forall x. ConstrRepr' -> Rep ConstrRepr' x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ConstrRepr' x -> ConstrRepr'
$cfrom :: forall x. ConstrRepr' -> Rep ConstrRepr' x
Generic, ConstrRepr' -> ()
(ConstrRepr' -> ()) -> NFData ConstrRepr'
forall a. (a -> ()) -> NFData a
rnf :: ConstrRepr' -> ()
$crnf :: ConstrRepr' -> ()
NFData, ConstrRepr' -> ConstrRepr' -> Bool
(ConstrRepr' -> ConstrRepr' -> Bool)
-> (ConstrRepr' -> ConstrRepr' -> Bool) -> Eq ConstrRepr'
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ConstrRepr' -> ConstrRepr' -> Bool
$c/= :: ConstrRepr' -> ConstrRepr' -> Bool
== :: ConstrRepr' -> ConstrRepr' -> Bool
$c== :: ConstrRepr' -> ConstrRepr' -> Bool
Eq, Typeable, Eq ConstrRepr'
Eq ConstrRepr'
-> (ConstrRepr' -> ConstrRepr' -> Ordering)
-> (ConstrRepr' -> ConstrRepr' -> Bool)
-> (ConstrRepr' -> ConstrRepr' -> Bool)
-> (ConstrRepr' -> ConstrRepr' -> Bool)
-> (ConstrRepr' -> ConstrRepr' -> Bool)
-> (ConstrRepr' -> ConstrRepr' -> ConstrRepr')
-> (ConstrRepr' -> ConstrRepr' -> ConstrRepr')
-> Ord ConstrRepr'
ConstrRepr' -> ConstrRepr' -> Bool
ConstrRepr' -> ConstrRepr' -> Ordering
ConstrRepr' -> ConstrRepr' -> ConstrRepr'
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 :: ConstrRepr' -> ConstrRepr' -> ConstrRepr'
$cmin :: ConstrRepr' -> ConstrRepr' -> ConstrRepr'
max :: ConstrRepr' -> ConstrRepr' -> ConstrRepr'
$cmax :: ConstrRepr' -> ConstrRepr' -> ConstrRepr'
>= :: ConstrRepr' -> ConstrRepr' -> Bool
$c>= :: ConstrRepr' -> ConstrRepr' -> Bool
> :: ConstrRepr' -> ConstrRepr' -> Bool
$c> :: ConstrRepr' -> ConstrRepr' -> Bool
<= :: ConstrRepr' -> ConstrRepr' -> Bool
$c<= :: ConstrRepr' -> ConstrRepr' -> Bool
< :: ConstrRepr' -> ConstrRepr' -> Bool
$c< :: ConstrRepr' -> ConstrRepr' -> Bool
compare :: ConstrRepr' -> ConstrRepr' -> Ordering
$ccompare :: ConstrRepr' -> ConstrRepr' -> Ordering
$cp1Ord :: Eq ConstrRepr'
Ord, Eq ConstrRepr'
Eq ConstrRepr'
-> (Int -> ConstrRepr' -> Int)
-> (ConstrRepr' -> Int)
-> Hashable ConstrRepr'
Int -> ConstrRepr' -> Int
ConstrRepr' -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: ConstrRepr' -> Int
$chash :: ConstrRepr' -> Int
hashWithSalt :: Int -> ConstrRepr' -> Int
$chashWithSalt :: Int -> ConstrRepr' -> Int
$cp1Hashable :: Eq ConstrRepr'
Hashable)
constrReprToConstrRepr' :: Int -> ConstrRepr -> ConstrRepr'
constrReprToConstrRepr' :: Int -> ConstrRepr -> ConstrRepr'
constrReprToConstrRepr' Int
n (ConstrRepr Name
name BitMask
mask BitMask
value [BitMask]
fieldanns) =
Text -> Int -> BitMask -> BitMask -> [BitMask] -> ConstrRepr'
ConstrRepr' (Name -> Text
thToText Name
name) Int
n BitMask
mask BitMask
value ((BitMask -> BitMask) -> [BitMask] -> [BitMask]
forall a b. (a -> b) -> [a] -> [b]
map BitMask -> BitMask
forall a b. (Integral a, Num b) => a -> b
fromIntegral [BitMask]
fieldanns)
dataReprAnnToDataRepr' :: DataReprAnn -> DataRepr'
dataReprAnnToDataRepr' :: DataReprAnn -> DataRepr'
dataReprAnnToDataRepr' (DataReprAnn Type
typ Int
size [ConstrRepr]
constrs) =
Type' -> Int -> [ConstrRepr'] -> DataRepr'
DataRepr' (Type -> Type'
thTypeToType' Type
typ) Int
size ((Int -> ConstrRepr -> ConstrRepr')
-> [Int] -> [ConstrRepr] -> [ConstrRepr']
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> ConstrRepr -> ConstrRepr'
constrReprToConstrRepr' [Int
0..] [ConstrRepr]
constrs)
thToText :: TH.Name -> Text.Text
thToText :: Name -> Text
thToText (TH.Name (TH.OccName String
name') (TH.NameG NameSpace
_namespace PkgName
_pkgName (TH.ModName String
modName))) =
String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
modName String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"." String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name'
thToText Name
name' = String -> Text
forall a. HasCallStack => String -> a
error (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Unexpected pattern: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Name -> String
forall a. Show a => a -> String
show Name
name'
thTypeToType' :: TH.Type -> Type'
thTypeToType' :: Type -> Type'
thTypeToType' Type
ty = Type -> Type'
go Type
ty
where
go :: Type -> Type'
go (TH.ConT Name
name') = Text -> Type'
ConstTy' (Name -> Text
thToText Name
name')
go (TH.PromotedT Name
name') = Text -> Type'
ConstTy' (Name -> Text
thToText Name
name')
go (TH.AppT Type
ty1 Type
ty2) = Type' -> Type' -> Type'
AppTy' (Type -> Type'
go Type
ty1) (Type -> Type'
go Type
ty2)
go (TH.LitT (TH.NumTyLit BitMask
n)) = BitMask -> Type'
LitTy' BitMask
n
go (TH.LitT (TH.StrTyLit String
lit)) = Text -> Type'
SymLitTy' (String -> Text
Text.pack String
lit)
go Type
_ = String -> Type'
forall a. HasCallStack => String -> a
error (String -> Type') -> String -> Type'
forall a b. (a -> b) -> a -> b
$ String
"Unsupported type: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Type -> String
forall a. Show a => a -> String
show Type
ty
type CustomReprs =
( Map.Map Type' DataRepr'
, Map.Map Text.Text ConstrRepr'
)
getDataRepr :: Type' -> CustomReprs -> Maybe DataRepr'
getDataRepr :: Type' -> CustomReprs -> Maybe DataRepr'
getDataRepr Type'
name (Map Type' DataRepr'
reprs, Map Text ConstrRepr'
_) = Type' -> Map Type' DataRepr' -> Maybe DataRepr'
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Type'
name Map Type' DataRepr'
reprs
getConstrRepr :: Text.Text -> CustomReprs -> Maybe ConstrRepr'
getConstrRepr :: Text -> CustomReprs -> Maybe ConstrRepr'
getConstrRepr Text
name (Map Type' DataRepr'
_, Map Text ConstrRepr'
reprs) = Text -> Map Text ConstrRepr' -> Maybe ConstrRepr'
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
name Map Text ConstrRepr'
reprs
uncheckedGetConstrRepr
:: HasCallStack
=> Text.Text
-> CustomReprs
-> ConstrRepr'
uncheckedGetConstrRepr :: Text -> CustomReprs -> ConstrRepr'
uncheckedGetConstrRepr Text
name (Map Type' DataRepr'
_, Map Text ConstrRepr'
reprs) =
ConstrRepr' -> Maybe ConstrRepr' -> ConstrRepr'
forall a. a -> Maybe a -> a
fromMaybe
(String -> ConstrRepr'
forall a. HasCallStack => String -> a
error (String
"Could not find custom representation for" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
Text.unpack Text
name))
(Text -> Map Text ConstrRepr' -> Maybe ConstrRepr'
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
name Map Text ConstrRepr'
reprs)
addCustomRepr :: CustomReprs -> DataRepr' -> CustomReprs
addCustomRepr :: CustomReprs -> DataRepr' -> CustomReprs
addCustomRepr (Map Type' DataRepr'
dMap, Map Text ConstrRepr'
cMap) d :: DataRepr'
d@(DataRepr' Type'
name Int
_size [ConstrRepr']
constrReprs) =
let insertConstr :: ConstrRepr' -> Map Text ConstrRepr' -> Map Text ConstrRepr'
insertConstr c :: ConstrRepr'
c@(ConstrRepr' Text
name' Int
_ BitMask
_ BitMask
_ [BitMask]
_) Map Text ConstrRepr'
cMap' = Text -> ConstrRepr' -> Map Text ConstrRepr' -> Map Text ConstrRepr'
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Text
name' ConstrRepr'
c Map Text ConstrRepr'
cMap' in
(Type' -> DataRepr' -> Map Type' DataRepr' -> Map Type' DataRepr'
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Type'
name DataRepr'
d Map Type' DataRepr'
dMap, (ConstrRepr' -> Map Text ConstrRepr' -> Map Text ConstrRepr')
-> Map Text ConstrRepr' -> [ConstrRepr'] -> Map Text ConstrRepr'
forall (t :: Type -> Type) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ConstrRepr' -> Map Text ConstrRepr' -> Map Text ConstrRepr'
insertConstr Map Text ConstrRepr'
cMap [ConstrRepr']
constrReprs)
buildCustomReprs :: [DataRepr'] -> CustomReprs
buildCustomReprs :: [DataRepr'] -> CustomReprs
buildCustomReprs = (CustomReprs -> DataRepr' -> CustomReprs)
-> CustomReprs -> [DataRepr'] -> CustomReprs
forall (t :: Type -> Type) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl CustomReprs -> DataRepr' -> CustomReprs
addCustomRepr (Map Type' DataRepr'
forall k a. Map k a
Map.empty, Map Text ConstrRepr'
forall k a. Map k a
Map.empty)