{-# 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 :: String -> Q (Q Pat, Q Exp) newNamePE String s = do Name n <- forall (m :: * -> *). Quote m => String -> m Name newName String s forall (m :: * -> *) a. Monad m => a -> m a return (forall (m :: * -> *). Quote m => Name -> m Pat varP Name n, forall (m :: * -> *). Quote m => Name -> m Exp varE Name n) mkDeclarations :: BaseWord -> String -> String -> String -> [(String, Integer)] -> Q [Dec] mkDeclarations :: BaseWord -> String -> String -> String -> [(String, Integer)] -> Q [Dec] mkDeclarations BaseWord baseType String typeNameString String patternPrefixString String defaultPatternNameString [(String, Integer)] enums = do let typeName :: Name typeName = String -> Name mkName String typeNameString let patternName :: String -> Name patternName String s = String -> Name mkName (String patternPrefixString forall a. [a] -> [a] -> [a] ++ String s) let defaultPatternName :: Name defaultPatternName = String -> Name mkName String defaultPatternNameString let baseTypeT :: Q Type baseTypeT :: Q Type baseTypeT = case BaseWord baseType of BaseWord BaseWord8 -> forall (m :: * -> *). Quote m => Name -> m Type conT forall a b. (a -> b) -> a -> b $ String -> Name mkName String "Word8" BaseWord BaseWord16 -> forall (m :: * -> *). Quote m => Name -> m Type conT forall a b. (a -> b) -> a -> b $ String -> Name mkName String "Word16" BaseWord BaseWord32 -> forall (m :: * -> *). Quote m => Name -> m Type conT forall a b. (a -> b) -> a -> b $ String -> Name mkName String "Word32" BaseWord BaseWord64 -> forall (m :: * -> *). Quote m => Name -> m Type conT forall a b. (a -> b) -> a -> b $ String -> Name mkName String "Word64" let newTypeDef :: Q Dec newTypeDef = forall (m :: * -> *). Quote m => m Cxt -> Name -> [TyVarBndr ()] -> Maybe Type -> m Con -> [m DerivClause] -> m Dec newtypeD (forall (m :: * -> *). Quote m => [m Type] -> m Cxt cxt []) Name typeName [] forall a. Maybe a Nothing (forall (m :: * -> *). Quote m => Name -> [m BangType] -> m Con normalC Name typeName [ forall (m :: * -> *). Quote m => m Bang -> m Type -> m BangType bangType (forall (m :: * -> *). Quote m => m SourceUnpackedness -> m SourceStrictness -> m Bang bang forall (m :: * -> *). Quote m => m SourceUnpackedness noSourceUnpackedness forall (m :: * -> *). Quote m => m SourceStrictness noSourceStrictness) Q Type baseTypeT ]) [ forall (m :: * -> *). Quote m => Maybe DerivStrategy -> [m Type] -> m DerivClause derivClause forall a. Maybe a Nothing [ forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Eq") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Ord") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Enum") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Num") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Real") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Integral") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Bits") , forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "FiniteBits") ] ] let mkShowClause :: (t, Integer) -> m Clause mkShowClause (t s, Integer n) = forall (m :: * -> *). Quote m => [m Pat] -> m Body -> [m Dec] -> m Clause clause [ forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [forall (m :: * -> *). Quote m => Lit -> m Pat litP forall a b. (a -> b) -> a -> b $ Integer -> Lit IntegerL Integer n] ] (forall (m :: * -> *). Quote m => m Exp -> m Body normalB [| patternPrefixString ++ s |]) [] let showClauses :: [Q Clause] showClauses :: [Q Clause] showClauses = forall a b. (a -> b) -> [a] -> [b] map forall {m :: * -> *} {t}. (Quote m, Lift t) => (t, Integer) -> m Clause mkShowClause [(String, Integer)] enums (Q Pat nP, Q Exp nE) <- String -> Q (Q Pat, Q Exp) newNamePE String "n" let defaultShowClause :: Q Clause defaultShowClause = forall (m :: * -> *). Quote m => [m Pat] -> m Body -> [m Dec] -> m Clause clause [ forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [Q Pat nP] ] (forall (m :: * -> *). Quote m => m Exp -> m Body normalB [| defaultPatternNameString ++ " " ++ show $(nE) |]) [] let showInstanceFunctions :: Q Dec showInstanceFunctions = forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec funD (String -> Name mkName String "show") ([Q Clause] showClauses forall a. [a] -> [a] -> [a] ++ [ Q Clause defaultShowClause ]) let showInstance :: Q Dec showInstance = forall (m :: * -> *). Quote m => m Cxt -> m Type -> [m Dec] -> m Dec instanceD (forall (m :: * -> *). Quote m => [m Type] -> m Cxt cxt []) (forall (m :: * -> *). Quote m => m Type -> m Type -> m Type appT (forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Show")) (forall (m :: * -> *). Quote m => Name -> m Type conT Name typeName)) [ Q Dec showInstanceFunctions ] let mkBinaryInstance :: Q Type -> Q Pat -> Q Exp -> Q Exp -> Q Dec mkBinaryInstance :: Q Type -> Q Pat -> Q Exp -> Q Exp -> Q Dec mkBinaryInstance Q Type typeT Q Pat putP Q Exp putE Q Exp getE = forall (m :: * -> *). Quote m => m Cxt -> m Type -> [m Dec] -> m Dec instanceD (forall (m :: * -> *). Quote m => [m Type] -> m Cxt cxt []) (forall (m :: * -> *). Quote m => m Type -> m Type -> m Type appT (forall (m :: * -> *). Quote m => Name -> m Type conT (String -> Name mkName String "Binary")) Q Type typeT) [ Q Dec binaryInstanceGet, Q Dec binaryInstancePut ] where binaryInstancePut :: Q Dec binaryInstancePut = forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec funD (String -> Name mkName String "put") [ forall (m :: * -> *). Quote m => [m Pat] -> m Body -> [m Dec] -> m Clause clause [Q Pat putP] (forall (m :: * -> *). Quote m => m Exp -> m Body normalB Q Exp putE) [] ] binaryInstanceGet :: Q Dec binaryInstanceGet = forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec funD (String -> Name mkName String "get") [ forall (m :: * -> *). Quote m => [m Pat] -> m Body -> [m Dec] -> m Clause clause [] (forall (m :: * -> *). Quote m => m Exp -> m Body normalB Q Exp getE) [] ] let binaryInstancesXe :: Q Exp -> Q Exp -> Q Exp -> Q Exp -> [Q Dec] binaryInstancesXe Q Exp putLe Q Exp getLe Q Exp putBe Q Exp getBe = [ do (Q Pat n3P, Q Exp n3E) <- String -> Q (Q Pat, Q Exp) newNamePE String "n" Q Type -> Q Pat -> Q Exp -> Q Exp -> Q Dec mkBinaryInstance (forall (m :: * -> *). Quote m => m Type -> m Type -> m Type appT (forall (m :: * -> *). Quote m => Name -> m Type conT forall a b. (a -> b) -> a -> b $ String -> Name mkName String "Le") (forall (m :: * -> *). Quote m => Name -> m Type conT Name typeName)) (forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP (String -> Name mkName String "Le") [forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [Q Pat n3P]]) [| $putLe $n3E |] [| $(conE $ mkName "Le") <$> ($(conE typeName) <$> $getLe) |] , do (Q Pat n3P, Q Exp n3E) <- String -> Q (Q Pat, Q Exp) newNamePE String "n" Q Type -> Q Pat -> Q Exp -> Q Exp -> Q Dec mkBinaryInstance (forall (m :: * -> *). Quote m => m Type -> m Type -> m Type appT (forall (m :: * -> *). Quote m => Name -> m Type conT forall a b. (a -> b) -> a -> b $ String -> Name mkName String "Be") (forall (m :: * -> *). Quote m => Name -> m Type conT Name typeName)) (forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP (String -> Name mkName String "Be") [forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [Q Pat n3P]]) [| $putBe $n3E |] [| $(conE $ mkName "Be") <$> ($(conE typeName) <$> $getBe) |] ] let binaryInstances :: [Q Dec] binaryInstances = case BaseWord baseType of BaseWord BaseWord8 -> [ do (Q Pat n3P, Q Exp n3E) <- String -> Q (Q Pat, Q Exp) newNamePE String "n" Q Type -> Q Pat -> Q Exp -> Q Exp -> Q Dec mkBinaryInstance (forall (m :: * -> *). Quote m => Name -> m Type conT Name typeName) (forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [Q Pat n3P]) [| putWord8 $n3E |] [| $(conE typeName) <$> getWord8 |] ] BaseWord BaseWord16 -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> [Q Dec] binaryInstancesXe [| putWord16le |] [| getWord16le |] [| putWord16be |] [| getWord16be |] BaseWord BaseWord32 -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> [Q Dec] binaryInstancesXe [| putWord32le |] [| getWord32le |] [| putWord32be |] [| getWord32be |] BaseWord BaseWord64 -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> [Q Dec] binaryInstancesXe [| putWord64le |] [| getWord64le |] [| putWord64be |] [| getWord64be |] let mkPatterns :: (String, Integer) -> [m Dec] mkPatterns (String s, Integer n) = [ forall (m :: * -> *). Quote m => Name -> m Type -> m Dec patSynSigD (String -> Name patternName String s) (forall (m :: * -> *). Quote m => Name -> m Type conT Name typeName) , forall (m :: * -> *). Quote m => Name -> m PatSynArgs -> m PatSynDir -> m Pat -> m Dec patSynD (String -> Name patternName String s) (forall (m :: * -> *). Quote m => [Name] -> m PatSynArgs prefixPatSyn []) forall (m :: * -> *). Quote m => m PatSynDir implBidir (forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [forall (m :: * -> *). Quote m => Lit -> m Pat litP forall a b. (a -> b) -> a -> b $ Integer -> Lit IntegerL Integer n]) ] let defaultPatternSig :: Q Dec defaultPatternSig = forall (m :: * -> *). Quote m => Name -> m Type -> m Dec patSynSigD Name defaultPatternName (forall (m :: * -> *). Quote m => m Type -> m Type -> m Type appT (forall (m :: * -> *). Quote m => m Type -> m Type -> m Type appT forall (m :: * -> *). Quote m => m Type arrowT Q Type baseTypeT) (forall (m :: * -> *). Quote m => Name -> m Type conT Name typeName)) Name localName3 <- forall (m :: * -> *). Quote m => String -> m Name newName String "n" let defaultPatternDef :: Q Dec defaultPatternDef :: Q Dec defaultPatternDef = forall (m :: * -> *). Quote m => Name -> m PatSynArgs -> m PatSynDir -> m Pat -> m Dec patSynD Name defaultPatternName (forall (m :: * -> *). Quote m => [Name] -> m PatSynArgs prefixPatSyn [Name localName3]) forall (m :: * -> *). Quote m => m PatSynDir implBidir (forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat conP Name typeName [forall (m :: * -> *). Quote m => Name -> m Pat varP Name localName3]) let patterns :: [Q Dec] patterns = forall (m :: * -> *) a. Monad m => m (m a) -> m a join (forall a b. (a -> b) -> [a] -> [b] map forall {m :: * -> *}. Quote m => (String, Integer) -> [m Dec] mkPatterns [(String, Integer)] enums) forall a. [a] -> [a] -> [a] ++ [ Q Dec defaultPatternSig, Q Dec defaultPatternDef ] forall (t :: * -> *) (m :: * -> *) a. (Traversable t, Monad m) => t (m a) -> m (t a) sequence forall a b. (a -> b) -> a -> b $ Q Dec newTypeDef forall a. a -> [a] -> [a] : Q Dec showInstance forall a. a -> [a] -> [a] : [Q Dec] patterns forall a. [a] -> [a] -> [a] ++ [Q Dec] binaryInstances