{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE CPP #-}
module Language.R.Internal.FunWrappers.TH
( thWrappers
, thWrapper
, thWrapperLiteral
, thWrapperLiterals
) where
import Internal.Error
import qualified Foreign.R.Type as R
import Control.Monad (replicateM)
import Foreign (FunPtr)
import Language.Haskell.TH
nSEXP0 :: Q Type
nSEXP0 = conT (mkName "SEXP0")
thWrappers :: Int -> Int -> Q [Dec]
thWrappers n m = mapM thWrapper [n..m]
thWrapper :: Int -> Q Dec
thWrapper n = do
let vars = map (mkName . return) $ take (n + 1) ['a'..]
ty = go (map varT vars)
forImpD cCall safe "wrapper" (mkName $ "wrap" ++ show n) $
[t| $ty -> IO (FunPtr $ty) |]
where
go :: [Q Type] -> Q Type
go [] = impossible "thWrapper"
go [_] = [t| IO $nSEXP0 |]
go (_:xs) = [t| $nSEXP0 -> $(go xs) |]
thWrapperLiterals :: Int -> Int -> Q [Dec]
thWrapperLiterals n m = mapM thWrapperLiteral [n..m]
thWrapperLiteral :: Int -> Q Dec
thWrapperLiteral n = do
let s = varT =<< newName "s"
names1 <- replicateM (n + 1) $ newName "a"
names2 <- replicateM (n + 1) $ newName "i"
let mkTy [] = impossible "thWrapperLiteral"
mkTy [x] = [t| $nR $s $x |]
mkTy (x:xs) = [t| $x -> $(mkTy xs) |]
ctx = cxt $
#if MIN_VERSION_template_haskell(2,10,0)
[AppT (ConT (mkName "NFData")) <$> varT (last names1)] ++
#else
[classP (mkName "NFData") [varT (last names1)]] ++
#endif
zipWith f (map varT names1) (map varT names2)
where
#if MIN_VERSION_template_haskell(2,10,0)
f tv1 tv2 = foldl AppT (ConT (mkName "Literal")) <$> sequence [tv1, tv2]
#else
f tv1 tv2 = classP (mkName "Literal") [tv1, tv2]
#endif
nR = conT $ mkName "R"
nwrapn = varE $ mkName $ "wrap" ++ show n
nfunToSEXP = varE $ mkName "Language.R.Literal.funToSEXP"
nLiteral = conT $ mkName "Literal"
instanceD ctx [t| $nLiteral $(mkTy $ map varT names1) 'R.ExtPtr |]
[ funD (mkName "mkSEXPIO")
[ clause [] (normalB [| $nfunToSEXP $nwrapn |]) [] ]
, funD (mkName "fromSEXP")
[ clause [] (normalB [| unimplemented "thWrapperLiteral fromSEXP" |]) [] ]
]