{-# LANGUAGE CPP #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Language.C.Inline.FunPtr
( mkFunPtr
, mkFunPtrFromName
, peekFunPtr
, uniqueFfiImportName
) where
import Data.Maybe (isJust)
import Foreign.Ptr (FunPtr)
import System.Environment (lookupEnv)
import qualified Language.Haskell.TH as TH
import qualified Language.Haskell.TH.Syntax as TH
mkFunPtr :: TH.TypeQ -> TH.ExpQ
mkFunPtr :: TypeQ -> ExpQ
mkFunPtr TypeQ
hsTy = do
Name
ffiImportName <- Q Name
uniqueFfiImportName
Bool
usingGhcide <- forall a. IO a -> Q a
TH.runIO forall a b. (a -> b) -> a -> b
$ forall a. Maybe a -> Bool
isJust forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe String)
lookupEnv String
"__GHCIDE__"
if Bool
usingGhcide
then do
[e|error "inline-c: A 'usingGhcide' mkFunPtr stub was evaluated -- this should not happen" :: $(hsTy) -> IO (FunPtr $(hsTy)) |]
else do
Dec
dec <- forall (m :: * -> *).
Quote m =>
Callconv -> Safety -> String -> Name -> m Type -> m Dec
TH.forImpD Callconv
TH.CCall Safety
TH.Safe String
"wrapper" Name
ffiImportName [t| $(hsTy) -> IO (FunPtr $(hsTy)) |]
[Dec] -> Q ()
TH.addTopDecls [Dec
dec]
forall (m :: * -> *). Quote m => Name -> m Exp
TH.varE Name
ffiImportName
mkFunPtrFromName :: TH.Name -> TH.ExpQ
mkFunPtrFromName :: Name -> ExpQ
mkFunPtrFromName Name
name = do
Info
i <- Name -> Q Info
TH.reify Name
name
case Info
i of
#if MIN_VERSION_template_haskell(2,11,0)
TH.VarI Name
_ Type
ty Maybe Dec
_ -> [| $(mkFunPtr (return ty)) $(TH.varE name) |]
#else
TH.VarI _ ty _ _ -> [| $(mkFunPtr (return ty)) $(TH.varE name) |]
#endif
Info
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"mkFunPtrFromName: expecting a variable as argument."
peekFunPtr :: TH.TypeQ -> TH.ExpQ
peekFunPtr :: TypeQ -> ExpQ
peekFunPtr TypeQ
hsTy = do
Name
ffiImportName <- Q Name
uniqueFfiImportName
Bool
usingGhcide <- forall a. IO a -> Q a
TH.runIO forall a b. (a -> b) -> a -> b
$ forall a. Maybe a -> Bool
isJust forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe String)
lookupEnv String
"__GHCIDE__"
if Bool
usingGhcide
then do
[e|error "inline-c: A 'usingGhcide' peekFunPtr stub was evaluated -- this should not happen" :: FunPtr $(hsTy) -> $(hsTy) |]
else do
Dec
dec <- forall (m :: * -> *).
Quote m =>
Callconv -> Safety -> String -> Name -> m Type -> m Dec
TH.forImpD Callconv
TH.CCall Safety
TH.Safe String
"dynamic" Name
ffiImportName [t| FunPtr $(hsTy) -> $(hsTy) |]
[Dec] -> Q ()
TH.addTopDecls [Dec
dec]
forall (m :: * -> *). Quote m => Name -> m Exp
TH.varE Name
ffiImportName
uniqueFfiImportName :: TH.Q TH.Name
uniqueFfiImportName :: Q Name
uniqueFfiImportName = forall (m :: * -> *). Quote m => String -> m Name
TH.newName forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *). Quote m => String -> m Name
TH.newName String
"inline_c_ffi"