gpu-vulkan-middle-0.1.0.54: src/Gpu/Vulkan/PhysicalDevice/Struct/ThTest.hs
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BlockArguments, LambdaCase, TupleSections #-}
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
module Gpu.Vulkan.PhysicalDevice.Struct.ThTest where
import Language.Haskell.TH
import Foreign.Ptr
import Foreign.Storable.PeekPoke
import Data.TypeLevel.Maybe qualified as TMaybe
-- import Gpu.Vulkan.PhysicalDevice.Struct.Core qualified as C
import Gpu.Vulkan.Base.Middle.Internal
import qualified Gpu.Vulkan.Sample.Enum as Sample
import Data.Word
import Data.Int
import Data.List.Length
import Data.Char
import Control.Arrow
-- import Data.Maybe
import Data.Foldable
import Control.Monad
fromJust' :: String -> Maybe a -> a
fromJust' msg = \case Nothing -> error msg; Just x -> x
makeStructure :: String -> DecsQ
makeStructure nm = do
dct <- readStructData nm
sequence [
mkData nm dct, mkDataShow nm, mkDataNoNext nm dct,
mkFromCoreType Production nm, mkFromCoreBody Production nm dct,
mkToCoreType Production nm, mkToCoreBody Production nm dct,
mkFromNoNextType nm, mkFromNoNextBody nm dct ]
mkData :: String -> DictFieldName -> DecQ
mkData nm dct = do
mn <- newName "mn"
let varBangTypes = getVarBangTypes "" nm dct
dataD (cxt [])
(mkName nm)
[plainTV mn] Nothing
[recC (mkName nm) $
(varBangType (mkName $ nm' ++ "Next")
(bangType noBang
(conT ''TMaybe.M `appT` varT mn))) :
(drop 2 varBangTypes)] []
where nm' = appHead toLower nm
mkDataShow :: String -> DecQ
mkDataShow nm = standaloneDerivD
(cxt [conT ''Show `appT` (conT ''TMaybe.M `appT` varT (mkName "mn"))])
(conT ''Show `appT` (conT (mkName nm) `appT` varT (mkName "mn")))
mkDataNoNext :: String -> DictFieldName -> DecQ
mkDataNoNext nm dct = do
let varBangTypes = getVarBangTypes "NoNext" nm dct
dataD (cxt []) (mkName nmnnx) [] Nothing
[recC (mkName nmnnx) $ drop 2 varBangTypes]
[derivClause Nothing [conT ''Show]]
where nmnnx = nm ++ "NoNext"
getVarBangTypes :: String -> String -> DictFieldName -> [VarBangTypeQ]
getVarBangTypes sfx dtnm ds = uncurry (member $ dtnm ++ sfx) <$> ds
mkFromCoreType :: Debug -> String -> DecQ
mkFromCoreType dbg nm = do
cnm <- fromJust' "foo" <$> lookupTypeName' dbg ("C." ++ nm)
sigD (mkName $ nm' ++ "FromCore")
(conT cnm `arrT` conT (mkName $ nm ++ "NoNext"))
where nm' = appHead toLower nm
mkFromCoreBody :: Debug -> String -> DictFieldName -> DecQ
mkFromCoreBody dbg nm dct = do
let ds = drop 2 dct
xs <- replicateM (length ds) $ newName "x"
let fs = (\(tp, _) -> typeToFun tp) <$> ds
nvs = zip (map snd ds) xs
nws = zip (zip (map snd ds) xs) fs
cnm <- fromJust' "bar" <$> lookupValueName' dbg ("C." ++ nm)
funD (mkName $ nm' ++ "FromCore") . (: []) . ($ [])
. clause [mkFromCorePat cnm nvs] . normalB
$ recConE (mkName $ nm ++ "NoNext") (exFieldExps "NoNext" nm nws)
where
nm' = appHead toLower nm
mkFromCorePat cnm nvs = recP cnm $ exFieldPats dbg nm nvs
mkToCoreType :: Debug -> String -> DecQ
mkToCoreType dbg nm = do
mn <- newName "mn"
cnm <- fromJust' "baz" <$> lookupTypeName' dbg ("C." ++ nm)
sigD (mkName $ nm' ++ "ToCore")
(forallT []
(cxt [conT ''WithPoked `appT`
(conT ''TMaybe.M `appT` varT mn)])
(conT (mkName nm) `appT` varT mn `arrT`
(conT cnm `arrT` conT ''IO `appT` conT ''()) `arrT`
conT ''IO `appT` conT ''()))
where nm' = appHead toLower nm
mkToCoreBody :: Debug -> String -> DictFieldName -> DecQ
mkToCoreBody dbg nm ds = do
f <- newName "f"
cnm <- fromJust' "poooo" <$> lookupValueName' dbg ("C." ++ nm)
stype <- fromJust' "hogefuga" <$> lookupValueName' dbg ("C." ++ nm' ++ "SType")
pnext <- fromJust' "oops" <$> lookupValueName' dbg ("C." ++ nm' ++ "PNext")
xs <- replicateM (length ds) $ newName "x"
let pes = (\(tp, _) -> typeToPatExp tp) <$> ds
nvs = zip (zip (map snd ds) xs) pes
[mnxt, pnxt, pnxt'] <- newName `mapM` ["mnxt", "pnxt", "pnxt'"]
funD (mkName $ nm' ++ "ToCore")
. (: []) . ($ []) . clause [mkToCorePat mnxt nvs, varP f] . normalB
$ varE 'withPoked' `appE` varE mnxt `appE`
lamE [varP pnxt] (
varE 'withPtrS `appE` varE pnxt `appE`
lamE [viewP (varE 'castPtr) (varP pnxt')] (
varE f `appE`
recConE cnm (
((stype ,) <$> conE '()) : ((pnext ,) <$> varE pnxt') :
toFieldExps dbg nm (drop 2 nvs) ) ) )
where
nm' = appHead toLower nm
mkToCorePat mnxt nvs = recP (mkName nm)
$ fieldPat (mkName $ nm' ++ "Next") (varP mnxt) : toFieldPats nm (drop 2 nvs)
type DictFieldName = [(String, FieldName)]
readStructData :: String -> Q DictFieldName
readStructData dtnm = runIO $ map ((id *** readName) . (separate '|')) . lines <$>
(readFile $ "th/vkPhysicalDevice" ++ dtnm ++ ".txt")
data Debug = Production | Debug deriving Show
lookupValueName' :: Debug -> String -> Q (Maybe Name)
lookupValueName' = \case
-- Production -> lookupValueName
Production -> pure . Just . mkName
Debug -> pure . Just . mkName
lookupTypeName' :: Debug -> String -> Q (Maybe Name)
lookupTypeName' = \case
Production -> lookupTypeName
Debug -> pure . Just . mkName
sample :: String
sample = "DescriptorIndexingFeatures"
newtype DeviceSize = DeviceSize { unDeviceSize :: Word64 } deriving Show
newtype Size = Size Word64 deriving Show
infixr 8 `arrT`
arrT :: TypeQ -> TypeQ -> TypeQ
t1 `arrT` t2 = arrowT `appT` t1 `appT` t2
data FieldName = Atom String | List String Integer deriving Show
member :: String -> String -> FieldName -> VarBangTypeQ
member dtnm tp_ fn = varBangType (mkName nm) $ bangType noBang tp
where
pfx = appHead toLower dtnm
(nm, tp) = getNameType pfx tp_ fn
appHead :: (a -> a) -> [a] -> [a]
appHead f = \case [] -> []; x : xs -> f x : xs
getNameType :: String -> String -> FieldName -> (String, TypeQ)
getNameType pfx tp (Atom fn) = (pfx ++ capitalize fn, fst $ lookup' tp dict)
getNameType pfx tp (List fn nb) = (pfx ++ capitalize fn,
conT ''LengthL `appT` litT (numTyLit nb) `appT` fst (lookup' tp dict))
lookup' :: (Show a, Eq a) => a -> [(a, b)] -> b
lookup' x d = case lookup x d of
Nothing -> error $ "no such key: " ++ show x
Just y -> y
dict :: Dict
dict = dictGenToDict dictGen
dictGenToDict :: DictGen -> Dict
dictGenToDict = map \(tp, tfr, _to) -> (tp, tfr)
dict2 :: Dict2
dict2 = dictGenToDict2 dictGen
dictGenToDict2 :: DictGen -> Dict2
dictGenToDict2 = map \(tp, _tfr, to) -> (tp, to)
type Dict = [(String, (TypeQ, Name -> ExpQ))]
type Dict2 = [(String, (Name -> PatQ, Name -> ExpQ))]
type DictGen = [(String, (TypeQ, Name -> ExpQ), (Name -> PatQ, Name -> ExpQ))]
dictGen :: [(String, (TypeQ, Name -> ExpQ), (Name -> PatQ, Name -> ExpQ))]
dictGen = [
("uint32_t", (conT ''Word32, varE), (varP, varE)),
("int32_t", (conT ''Int32, varE), (varP, varE)),
("float", (conT ''Float, varE), (varP, varE)),
("VkBool32", (conT ''Bool, appE (varE 'bool32ToBool) . varE),
(varP, appE (varE 'boolToBool32) . varE)),
("size_t", (conT ''Size, appE (conE 'Size) . varE),
(conP 'Size . (: []) . varP, varE)),
("VkDeviceSize", (conT ''DeviceSize, appE (conE 'DeviceSize) . varE),
(conP 'DeviceSize . (: []) . varP, varE)),
("VkSampleCountFlags",
(conT ''Sample.CountFlags,
appE (conE 'Sample.CountFlagBits) . varE),
(conP 'Sample.CountFlagBits . (: []) . varP, varE)) ]
capitalize :: String -> String
capitalize "" = ""
capitalize (c : cs) = toUpper c : cs
noBang :: BangQ
noBang = bang noSourceUnpackedness noSourceStrictness
readName :: String -> FieldName
readName ('A' : ' ' : nm) = Atom nm
readName ('L' : ' ' : nmnb) = case words nmnb of
[nm, nb] -> List nm (read nb); _ -> error "bad"
readName _ = error "bad"
separate :: Eq a => a -> [a] -> ([a], [a])
separate c str = case span (/= c) str of
(pre, _ : pst) -> (pre, pst)
_ -> error "no separater"
toFieldExps :: Debug -> String -> [((FieldName, Name), (Name -> PatQ, Name -> ExpQ))] -> [Q (Name, Exp)]
toFieldExps dbg dtnm = map . uncurry $ uncurry (toFieldExp1 dbg $ appHead toLower dtnm)
toFieldExp1 :: Debug -> String -> FieldName -> Name -> (Name -> PatQ, Name -> ExpQ) -> Q (Name, Exp)
toFieldExp1 dbg pfx (Atom nm) x (_, f) = do
n <- fromJust' "ukki" <$> lookupValueName' dbg ("C." ++ pfx ++ capitalize nm)
fieldExp n (f x)
toFieldExp1 dbg pfx (List nm _) x (pf, f) = do
n <- fromJust' "sarusaru" <$> lookupValueName' dbg ("C." ++ pfx ++ capitalize nm)
y <- newName "y"
fieldExp n $ lam1E (pf y) (f y) .<$> (varE 'toList `appE` varE x)
typeToFun :: String -> (Name -> ExpQ)
typeToFun nm = case lookup nm dict of Just (_, f) -> f; Nothing -> error "bad"
exFieldPats :: Debug -> String -> [(FieldName, Name)] -> [Q FieldPat]
exFieldPats dbg dtnm = map $ uncurry (exFieldPat1 dbg $ appHead toLower dtnm)
exFieldPat1 :: Debug -> String -> FieldName -> Name -> Q FieldPat
exFieldPat1 dbg pfx fn x = do
let nm = case fn of
Atom n -> n
List n _ -> n
n <- fromJust' ("C." ++ pfx ++ capitalize nm) <$> lookupValueName' dbg ("C." ++ pfx ++ capitalize nm)
fieldPat n (varP x)
typeToPatExp :: String -> (Name -> PatQ, Name -> ExpQ)
typeToPatExp = fromJust' "nande" . (`lookup` dict2)
toFieldPats :: String -> [((FieldName, Name), (Name -> PatQ, a))] -> [Q FieldPat]
toFieldPats dtnm = map . uncurry $ uncurry (toFieldPat1 $ appHead toLower dtnm)
toFieldPat1 :: String -> FieldName -> Name -> ((Name -> PatQ), a) -> Q FieldPat
toFieldPat1 pfx (Atom nm) x (f, _) = fieldPat (mkName $ pfx ++ capitalize nm) (f x)
toFieldPat1 pfx (List nm _) x _ = fieldPat (mkName $ pfx ++ capitalize nm) (varP x)
exFieldExps :: String -> String -> [((FieldName, Name), Name -> ExpQ)] -> [Q (Name, Exp)]
exFieldExps sfx dtnm = map . uncurry $ uncurry (exFieldExp1 sfx $ appHead toLower dtnm)
listToLengthL :: ListToLengthL n => [a] -> LengthL n a
listToLengthL xs = case splitL xs of
Right (ln, []) -> ln
_ -> error "bad"
exFieldExp1 :: String -> String -> FieldName -> Name -> (Name -> ExpQ) -> Q (Name, Exp)
exFieldExp1 sfx pfx (Atom nm) x f = fieldExp (mkName $ pfx ++ sfx ++ capitalize nm) (f x)
exFieldExp1 sfx pfx (List nm _) x f = do
y <- newName "y"
fieldExp (mkName $ pfx ++ sfx ++ capitalize nm)
. appE (varE 'listToLengthL) $ lam1E (varP y) (f y) .<$> varE x
(.<$>) :: ExpQ -> ExpQ -> ExpQ
f .<$> x = infixApp f (varE '(<$>)) x
mkFromNoNextType :: String -> DecQ
mkFromNoNextType nm = do
mn <- newName "mn"
sigD (mkName $ nm' ++ "FromNoNext") $
(conT ''TMaybe.M `appT` varT mn) `arrT`
conT (mkName $ nm ++ "NoNext") `arrT`
(conT (mkName nm) `appT` varT mn)
where nm' = appHead toLower nm
mkFromNoNextBody :: String -> DictFieldName -> DecQ
mkFromNoNextBody nm dct = do
mnxt <- newName "mnxt"
xs <- replicateM (length dct) $ newName "x"
funD (mkName $ nm' ++ "FromNoNext") . (: []) . ($ [])
. clause [varP mnxt, mkFromNoNextPat nm (drop 2 dct) xs] . normalB
. recConE (mkName nm) $
((mkName (nm' ++ "Next") ,) <$> varE mnxt) :
(<$> zip (dictFieldNameToNames $ drop 2 dct) xs) \(fnm, x) ->
(mkName (nm' ++ capitalize fnm) ,) <$> varE x
where nm' = appHead toLower nm
mkFromNoNextPat :: String -> DictFieldName -> [Name] -> PatQ
mkFromNoNextPat nm dct xs = recP (mkName $ nm ++ "NoNext")
$ (<$> zip (dictFieldNameToNames dct) xs) \(fnm, x) ->
fieldPat (mkName $ nm' ++ "NoNext" ++ capitalize fnm) (varP x)
where nm' = appHead toLower nm
dictFieldNameToNames :: DictFieldName -> [String]
dictFieldNameToNames = (dfntn <$>)
where dfntn (_, fn) = case fn of Atom n -> n; List n _ -> n