packages feed

gpu-vulkan-0.1.0.137: src/Gpu/Vulkan/TypeEnum/TypeValues.hs

{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.TypeEnum.TypeValues (typeValues) where

import Language.Haskell.TH
import Data.Proxy
import Data.Char

typeValues :: String -> String -> [String] -> Q [Dec]
typeValues mdl tp elms =
	(\a b c -> a ++ b ++ c)	
		<$> ((: []) <$> mkType tp elms)
		<*> ((:)	<$> mkClass mdl tp
				<*> sequence (mkInstance mdl tp <$> elms))
		<*> sequence [
			sigFoo mdl tp,
			funD (mkName $ hd toLower tp ++ "ToType") (foo <$> elms) ]

mkType :: String -> [String] -> Q Dec
mkType tp elms = dataD (pure []) (mkName tp) [] Nothing
	((`normalC` []) . mkName <$> elms) [derivClause Nothing [conT ''Show]]

mkClass :: String -> String -> Q Dec
mkClass mdl tp = do
	t <- newName "t"
	classD (cxt []) (mkName $ tp ++ "ToValue")
		[kindedTV t (ConT $ mkName tp)]
		[]
		[sigD (mkName $ hd toLower tp ++ "ToValue") . conT . mkName $ mdl ++ "." ++ tp]

hd :: (a -> a) -> [a] -> [a]
hd _ [] = []
hd f (x : xs) = f x : xs

mkInstance :: String -> String -> String -> Q Dec
mkInstance mdl tp ss =
	instanceD (pure []) (conT (mkName $ tp ++ "ToValue") `appT` promotedT (mkName ss)) [
		valD	(varP . mkName $ hd toLower tp ++ "ToValue")
			(normalB . conE . mkName $ mdl ++ "." ++ ss) []
		]

sigFoo :: String -> String -> Q Dec
sigFoo mdl tp = do
	t <- newName "t"
	a <- newName "a"
	tv <- kindedInvisTV t SpecifiedSpec (conT $ mkName tp)
	sigD (mkName $ hd toLower tp ++ "ToType")
		$ conT (mkName $ mdl ++ "." ++ tp)
			`arrT` ((forallT [tv]
				(cxt [conT (mkName $ tp ++ "ToValue") `appT` varT t])
				((conT ''Proxy `appT` varT t) `arrT` varT a))
		`arrT` varT a)

foo :: String -> Q Clause
foo nm = do
	f <- newName "f"
	clause
		[conP (mkName $ "E." ++ nm) [], varP f]
		(normalB $ varE f `appE`
			(conE 'Proxy `appTypeE` promotedT (mkName nm)))
		[]

arrT :: Q Type -> Q Type -> Q Type
t1 `arrT` t2 = arrowT `appT` t1 `appT` t2