melf-1.2.0: src/Data/Elf/Constants/TH.hs
{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
{-# LANGUAGE TemplateHaskell #-}
module Data.Elf.Constants.TH ( mkDeclarations
, BaseWord(..)
) where
import Control.Monad
import Language.Haskell.TH
data BaseWord = BaseWord8 | BaseWord16 | BaseWord32 | BaseWord64
newNamePE :: String -> Q (Q Pat, Q Exp)
newNamePE s = do
n <- newName s
return (varP n, varE n)
mkDeclarations :: BaseWord -> String -> String -> String -> [(String, Integer)] -> Q [Dec]
mkDeclarations baseType typeNameString patternPrefixString defaultPatternNameString enums = do
let typeName = mkName typeNameString
let patternName s = mkName (patternPrefixString ++ s)
let defaultPatternName = mkName defaultPatternNameString
let
baseTypeT :: Q Type
baseTypeT =
case baseType of
BaseWord8 -> conT $ mkName "Word8"
BaseWord16 -> conT $ mkName "Word16"
BaseWord32 -> conT $ mkName "Word32"
BaseWord64 -> conT $ mkName "Word64"
let
newTypeDef =
newtypeD
(cxt [])
typeName
[]
Nothing
(normalC typeName [ bangType (bang noSourceUnpackedness noSourceStrictness) baseTypeT ])
[ derivClause Nothing [ conT (mkName "Eq")
, conT (mkName "Ord")
, conT (mkName "Enum")
, conT (mkName "Num")
, conT (mkName "Real")
, conT (mkName "Integral")
, conT (mkName "Bits")
, conT (mkName "FiniteBits")
]
]
let
mkShowClause (s, n) =
clause
[ conP typeName [litP $ IntegerL n] ]
(normalB [| patternPrefixString ++ s |])
[]
let
showClauses :: [Q Clause]
showClauses = map mkShowClause enums
(nP, nE) <- newNamePE "n"
let
defaultShowClause =
clause
[ conP typeName [nP] ]
(normalB [| defaultPatternNameString ++ " " ++ show $(nE) |])
[]
let showInstanceFunctions = funD (mkName "show") (showClauses ++ [ defaultShowClause ])
let showInstance = instanceD (cxt []) (appT (conT (mkName "Show")) (conT typeName)) [ showInstanceFunctions ]
let
mkBinaryInstance :: Q Type -> Q Pat -> Q Exp -> Q Exp -> Q Dec
mkBinaryInstance typeT putP putE getE =
instanceD
(cxt [])
(appT (conT (mkName "Binary")) typeT)
[ binaryInstanceGet, binaryInstancePut ]
where
binaryInstancePut =
funD
(mkName "put")
[ clause
[putP]
(normalB putE)
[]
]
binaryInstanceGet =
funD
(mkName "get")
[ clause
[]
(normalB getE)
[]
]
let
binaryInstancesXe putLe getLe putBe getBe =
[ do
(n3P, n3E) <- newNamePE "n"
mkBinaryInstance
(appT (conT $ mkName "Le") (conT typeName))
(conP (mkName "Le") [conP typeName [n3P]])
[| $putLe $n3E |]
[| $(conE $ mkName "Le") <$> ($(conE typeName) <$> $getLe) |]
, do
(n3P, n3E) <- newNamePE "n"
mkBinaryInstance
(appT (conT $ mkName "Be") (conT typeName))
(conP (mkName "Be") [conP typeName [n3P]])
[| $putBe $n3E |]
[| $(conE $ mkName "Be") <$> ($(conE typeName) <$> $getBe) |]
]
let
binaryInstances =
case baseType of
BaseWord8 ->
[ do
(n3P, n3E) <- newNamePE "n"
mkBinaryInstance
(conT typeName)
(conP typeName [n3P])
[| putWord8 $n3E |]
[| $(conE typeName) <$> getWord8 |]
]
BaseWord16 -> binaryInstancesXe [| putWord16le |] [| getWord16le |] [| putWord16be |] [| getWord16be |]
BaseWord32 -> binaryInstancesXe [| putWord32le |] [| getWord32le |] [| putWord32be |] [| getWord32be |]
BaseWord64 -> binaryInstancesXe [| putWord64le |] [| getWord64le |] [| putWord64be |] [| getWord64be |]
let
mkPatterns (s, n) =
[ patSynSigD
(patternName s)
(conT typeName)
, patSynD
(patternName s)
(prefixPatSyn [])
implBidir
(conP typeName [litP $ IntegerL n])
]
let
defaultPatternSig =
patSynSigD
defaultPatternName
(appT (appT arrowT baseTypeT) (conT typeName))
localName3 <- newName "n"
let
defaultPatternDef :: Q Dec
defaultPatternDef =
patSynD
defaultPatternName
(prefixPatSyn [localName3])
implBidir
(conP typeName [varP localName3])
let patterns = join (map mkPatterns enums) ++ [ defaultPatternSig, defaultPatternDef ]
sequence $ newTypeDef : showInstance : patterns ++ binaryInstances