{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE MonoLocalBinds #-}
module Language.C.Inline.Internal
(
setContext
, getContext
, Substitutions(..)
, substitute
, getHaskellType
, emitVerbatim
, emitBlock
, Code(..)
, inlineCode
, inlineExp
, inlineItems
, SomeEq
, toSomeEq
, fromSomeEq
, ParameterType(..)
, ParseTypedC(..)
, parseTypedC
, runParserInQ
, splitTypedC
, lineDirective
, here
, shiftLines
, genericQuote
, funPtrQuote
) where
import Control.Applicative
import Control.Monad (forM, void, msum)
import Control.Monad.State (evalStateT, StateT, get, put)
import Control.Monad.Trans.Class (lift)
import Data.Foldable (forM_)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe, isJust)
import Data.Traversable (for)
import Data.Typeable (Typeable, cast)
import qualified Language.Haskell.TH as TH
import qualified Language.Haskell.TH.Quote as TH
import qualified Language.Haskell.TH.Syntax as TH
import System.Environment (lookupEnv)
import System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO)
import qualified Text.Parsec as Parsec
import qualified Text.Parsec.Pos as Parsec
import qualified Text.Parser.Char as Parser
import qualified Text.Parser.Combinators as Parser
import qualified Text.Parser.LookAhead as Parser
import qualified Text.Parser.Token as Parser
import Prettyprinter ((<+>))
import qualified Prettyprinter as PP
import qualified Prettyprinter.Render.String as PP
import qualified Data.List as L
import qualified Data.Char as C
import Data.Hashable (Hashable)
import Foreign.Ptr (FunPtr)
import qualified Data.Map as M
#define USE_GETQ (__GLASGOW_HASKELL__ > 710 || (__GLASGOW_HASKELL__ == 710 && __GLASGOW_HASKELL_PATCHLEVEL1__ >= 3))
#if !USE_GETQ
import Control.Concurrent.MVar (MVar, newMVar, modifyMVar_, readMVar)
#endif
import Language.C.Inline.Context
import Language.C.Inline.FunPtr
import Language.C.Inline.HaskellIdentifier
import qualified Language.C.Types as C
data ModuleState = ModuleState
{ ModuleState -> Context
msContext :: Context
, ModuleState -> Int
msGeneratedNames :: Int
, ModuleState -> [String]
msFileChunks :: [String]
} deriving (Typeable)
getModuleState :: TH.Q (Maybe ModuleState)
putModuleState :: ModuleState -> TH.Q ()
#if USE_GETQ
getModuleState :: Q (Maybe ModuleState)
getModuleState = forall a. Typeable a => Q (Maybe a)
TH.getQ
putModuleState :: ModuleState -> Q ()
putModuleState = forall a. Typeable a => a -> Q ()
TH.putQ
#else
type ModuleId = String
getModuleId :: TH.Q ModuleId
getModuleId = TH.loc_filename <$> TH.location
{-# NOINLINE moduleStatesVar #-}
moduleStatesVar :: MVar (Map.Map ModuleId ModuleState)
moduleStatesVar = unsafePerformIO $ newMVar Map.empty
getModuleState = do
moduleStates <- TH.runIO (readMVar moduleStatesVar)
moduleId <- getModuleId
return (Map.lookup moduleId moduleStates)
putModuleState ms = do
moduleId <- getModuleId
TH.runIO (modifyMVar_ moduleStatesVar (return . Map.insert moduleId ms))
#endif
initialiseModuleState
:: Maybe Context
-> TH.Q Context
initialiseModuleState :: Maybe Context -> Q Context
initialiseModuleState Maybe Context
mbContext = do
Maybe ModuleState
mbModuleState <- Q (Maybe ModuleState)
getModuleState
case Maybe ModuleState
mbModuleState of
Just ModuleState
moduleState -> forall (m :: * -> *) a. Monad m => a -> m a
return (ModuleState -> Context
msContext ModuleState
moduleState)
Maybe ModuleState
Nothing -> do
Q () -> Q ()
TH.addModFinalizer forall a b. (a -> b) -> a -> b
$ do
Maybe ModuleState
mbMs <- Q (Maybe ModuleState)
getModuleState
ModuleState
ms <- case Maybe ModuleState
mbMs of
Maybe ModuleState
Nothing -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: ModuleState not present (initialiseModuleState)"
Just ModuleState
ms -> forall (m :: * -> *) a. Monad m => a -> m a
return ModuleState
ms
let lang :: ForeignSrcLang
lang = forall a. a -> Maybe a -> a
fromMaybe ForeignSrcLang
TH.LangC (Context -> Maybe ForeignSrcLang
ctxForeignSrcLang Context
context)
addForeignSource :: ForeignSrcLang -> String -> Q ()
addForeignSource =
#if MIN_VERSION_base(4,12,0)
ForeignSrcLang -> String -> Q ()
TH.addForeignSource
#else
TH.addForeignFile
#endif
src :: String
src = (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (forall a. [a] -> [a]
reverse (ModuleState -> [String]
msFileChunks ModuleState
ms)))
case (ForeignSrcLang
lang, Context -> Maybe (String -> Q String)
ctxRawObjectCompile Context
context) of
(ForeignSrcLang
TH.RawObject, Just String -> Q String
compile) -> String -> Q String
compile String
src forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ForeignSrcLang -> String -> Q ()
TH.addForeignFilePath ForeignSrcLang
lang
(ForeignSrcLang
_, Maybe (String -> Q String)
_) -> ForeignSrcLang -> String -> Q ()
addForeignSource ForeignSrcLang
lang String
src
let moduleState :: ModuleState
moduleState = ModuleState
{ msContext :: Context
msContext = Context
context
, msGeneratedNames :: Int
msGeneratedNames = Int
0
, msFileChunks :: [String]
msFileChunks = forall a. Monoid a => a
mempty
}
ModuleState -> Q ()
putModuleState ModuleState
moduleState
forall (m :: * -> *) a. Monad m => a -> m a
return Context
context
where
context :: Context
context = forall a. a -> Maybe a -> a
fromMaybe Context
baseCtx Maybe Context
mbContext
getContext :: TH.Q Context
getContext :: Q Context
getContext = Maybe Context -> Q Context
initialiseModuleState forall a. Maybe a
Nothing
modifyModuleState :: (ModuleState -> (ModuleState, a)) -> TH.Q a
modifyModuleState :: forall a. (ModuleState -> (ModuleState, a)) -> Q a
modifyModuleState ModuleState -> (ModuleState, a)
f = do
Maybe ModuleState
mbModuleState <- Q (Maybe ModuleState)
getModuleState
case Maybe ModuleState
mbModuleState of
Maybe ModuleState
Nothing -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: ModuleState not present (modifyModuleState)"
Just ModuleState
ms -> do
let (ModuleState
ms', a
x) = ModuleState -> (ModuleState, a)
f ModuleState
ms
ModuleState -> Q ()
putModuleState ModuleState
ms'
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
setContext :: Context -> TH.Q ()
setContext :: Context -> Q ()
setContext Context
ctx = do
Maybe ModuleState
mbModuleState <- Q (Maybe ModuleState)
getModuleState
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ Maybe ModuleState
mbModuleState forall a b. (a -> b) -> a -> b
$ \ModuleState
_ms ->
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: The module has already been initialised (setContext)."
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ Maybe Context -> Q Context
initialiseModuleState forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just Context
ctx
bumpGeneratedNames :: TH.Q Int
bumpGeneratedNames :: Q Int
bumpGeneratedNames = do
forall a. (ModuleState -> (ModuleState, a)) -> Q a
modifyModuleState forall a b. (a -> b) -> a -> b
$ \ModuleState
ms ->
let c' :: Int
c' = ModuleState -> Int
msGeneratedNames ModuleState
ms
in (ModuleState
ms{msGeneratedNames :: Int
msGeneratedNames = Int
c' forall a. Num a => a -> a -> a
+ Int
1}, Int
c')
emitVerbatim :: String -> TH.DecsQ
emitVerbatim :: String -> DecsQ
emitVerbatim String
s = do
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Maybe Context -> Q Context
initialiseModuleState forall a. Maybe a
Nothing)
let chunk :: String
chunk = String
"\n" forall a. [a] -> [a] -> [a]
++ String
s forall a. [a] -> [a] -> [a]
++ String
"\n"
forall a. (ModuleState -> (ModuleState, a)) -> Q a
modifyModuleState forall a b. (a -> b) -> a -> b
$ \ModuleState
ms ->
(ModuleState
ms{msFileChunks :: [String]
msFileChunks = String
chunk forall a. a -> [a] -> [a]
: ModuleState -> [String]
msFileChunks ModuleState
ms}, ())
forall (m :: * -> *) a. Monad m => a -> m a
return []
emitBlock :: TH.QuasiQuoter
emitBlock :: QuasiQuoter
emitBlock = TH.QuasiQuoter
{ quoteExp :: String -> Q Exp
TH.quoteExp = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: quoteExp not implemented (quoteCode)"
, quotePat :: String -> Q Pat
TH.quotePat = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: quotePat not implemented (quoteCode)"
, quoteType :: String -> Q Type
TH.quoteType = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: quoteType not implemented (quoteCode)"
, quoteDec :: String -> DecsQ
TH.quoteDec = String -> DecsQ
emitVerbatim
}
data Code = Code
{ Code -> Safety
codeCallSafety :: TH.Safety
, Code -> Maybe Loc
codeLoc :: Maybe TH.Loc
, Code -> Q Type
codeType :: TH.TypeQ
, Code -> String
codeFunName :: String
, Code -> String
codeDefs :: String
, Code -> Bool
codeFunPtr :: Bool
}
inlineCode :: Code -> TH.ExpQ
inlineCode :: Code -> Q Exp
inlineCode Code{Bool
String
Maybe Loc
Q Type
Safety
codeFunPtr :: Bool
codeDefs :: String
codeFunName :: String
codeType :: Q Type
codeLoc :: Maybe Loc
codeCallSafety :: Safety
codeFunPtr :: Code -> Bool
codeDefs :: Code -> String
codeFunName :: Code -> String
codeType :: Code -> Q Type
codeLoc :: Code -> Maybe Loc
codeCallSafety :: Code -> Safety
..} = do
Context
ctx <- Q Context
getContext
let out :: String -> String
out = forall a. a -> Maybe a -> a
fromMaybe forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ Context -> Maybe (String -> String)
ctxOutput Context
ctx
let directive :: String
directive = forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" Loc -> String
lineDirective Maybe Loc
codeLoc
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ String -> DecsQ
emitVerbatim forall a b. (a -> b) -> a -> b
$ String -> String
out forall a b. (a -> b) -> a -> b
$ String
directive forall a. [a] -> [a] -> [a]
++ String
codeDefs
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' inlineCode stub was evaluated -- this should not happen" :: $(if codeFunPtr then [t| FunPtr $(codeType) |] else codeType) |]
else do
Dec
dec <- if Bool
codeFunPtr
then forall (m :: * -> *).
Quote m =>
Callconv -> Safety -> String -> Name -> m Type -> m Dec
TH.forImpD Callconv
TH.CCall Safety
codeCallSafety (String
"&" forall a. [a] -> [a] -> [a]
++ String
codeFunName) Name
ffiImportName [t| FunPtr $(codeType) |]
else forall (m :: * -> *).
Quote m =>
Callconv -> Safety -> String -> Name -> m Type -> m Dec
TH.forImpD Callconv
TH.CCall Safety
codeCallSafety String
codeFunName Name
ffiImportName Q Type
codeType
[Dec] -> Q ()
TH.addTopDecls [Dec
dec]
forall (m :: * -> *). Quote m => Name -> m Exp
TH.varE Name
ffiImportName
uniqueCName :: Maybe String -> TH.Q String
uniqueCName :: Maybe String -> Q String
uniqueCName Maybe String
mbPostfix = do
Int
c' <- Q Int
bumpGeneratedNames
String
module_ <- Loc -> String
TH.loc_module forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Q Loc
TH.location
let replaceDot :: Char -> Char
replaceDot Char
'.' = Char
'_'
replaceDot Char
c = Char
c
let postfix :: String
postfix = case Maybe String
mbPostfix of
Maybe String
Nothing -> String
""
Just String
s -> String
"_" forall a. [a] -> [a] -> [a]
++ String
s forall a. [a] -> [a] -> [a]
++ String
"_"
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String
"inline_c_" forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
replaceDot String
module_ forall a. [a] -> [a] -> [a]
++ String
"_" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
c' forall a. [a] -> [a] -> [a]
++ String
postfix
inlineExp
:: TH.Safety
-> TH.Loc
-> TH.TypeQ
-> C.Type C.CIdentifier
-> [(C.CIdentifier, C.Type C.CIdentifier)]
-> String
-> TH.ExpQ
inlineExp :: Safety
-> Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp
inlineExp Safety
callSafety Loc
loc Q Type
type_ Type CIdentifier
cRetType [(CIdentifier, Type CIdentifier)]
cParams String
cExp =
Safety
-> Bool
-> Maybe String
-> Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp
inlineItems Safety
callSafety Bool
False forall a. Maybe a
Nothing Loc
loc Q Type
type_ Type CIdentifier
cRetType [(CIdentifier, Type CIdentifier)]
cParams String
cItems
where
cItems :: String
cItems = case Type CIdentifier
cRetType of
C.TypeSpecifier Specifiers
_quals TypeSpecifier
C.Void -> String
cExp forall a. [a] -> [a] -> [a]
++ String
";"
Type CIdentifier
_ -> String
"return (" forall a. [a] -> [a] -> [a]
++ String
cExp forall a. [a] -> [a] -> [a]
++ String
");"
inlineItems
:: TH.Safety
-> Bool
-> Maybe String
-> TH.Loc
-> TH.TypeQ
-> C.Type C.CIdentifier
-> [(C.CIdentifier, C.Type C.CIdentifier)]
-> String
-> TH.ExpQ
inlineItems :: Safety
-> Bool
-> Maybe String
-> Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp
inlineItems Safety
callSafety Bool
funPtr Maybe String
mbPostfix Loc
loc Q Type
type_ Type CIdentifier
cRetType [(CIdentifier, Type CIdentifier)]
cParams String
cItems = do
let mkParam :: (i, Type i) -> ParameterDeclaration i
mkParam (i
id', Type i
paramTy) = forall i. Maybe i -> Type i -> ParameterDeclaration i
C.ParameterDeclaration (forall a. a -> Maybe a
Just i
id') Type i
paramTy
let proto :: Type CIdentifier
proto = forall i. Type i -> [ParameterDeclaration i] -> Type i
C.Proto Type CIdentifier
cRetType (forall a b. (a -> b) -> [a] -> [b]
map forall {i}. (i, Type i) -> ParameterDeclaration i
mkParam [(CIdentifier, Type CIdentifier)]
cParams)
Context
ctx <- Q Context
getContext
String
funName <- Maybe String -> Q String
uniqueCName Maybe String
mbPostfix
CIdentifier
cFunName <- case Bool -> String -> Either String CIdentifier
C.cIdentifierFromString (Context -> Bool
ctxEnableCpp Context
ctx) String
funName of
Left String
err -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"inlineItems: impossible, generated bad C identifier " forall a. [a] -> [a] -> [a]
++
String
"funName:\n" forall a. [a] -> [a] -> [a]
++ String
err
Right CIdentifier
x -> forall (m :: * -> *) a. Monad m => a -> m a
return CIdentifier
x
let decl :: ParameterDeclaration CIdentifier
decl = forall i. Maybe i -> Type i -> ParameterDeclaration i
C.ParameterDeclaration (forall a. a -> Maybe a
Just CIdentifier
cFunName) Type CIdentifier
proto
let defs :: String
defs = forall ann. Doc ann -> String
prettyOneLine (forall a ann. Pretty a => a -> Doc ann
PP.pretty ParameterDeclaration CIdentifier
decl) forall a. [a] -> [a] -> [a]
++ String
" { " forall a. [a] -> [a] -> [a]
++ String
cItems forall a. [a] -> [a] -> [a]
++ String
" }\n"
Code -> Q Exp
inlineCode forall a b. (a -> b) -> a -> b
$ Code
{ codeCallSafety :: Safety
codeCallSafety = Safety
callSafety
, codeLoc :: Maybe Loc
codeLoc = forall a. a -> Maybe a
Just Loc
loc
, codeType :: Q Type
codeType = Q Type
type_
, codeFunName :: String
codeFunName = String
funName
, codeDefs :: String
codeDefs = String
defs
, codeFunPtr :: Bool
codeFunPtr = Bool
funPtr
}
runParserInQ
:: (Hashable ident)
=> String
-> C.CParserContext ident
-> (forall m. C.CParser ident m => m a) -> TH.Q a
runParserInQ :: forall ident a.
Hashable ident =>
String
-> CParserContext ident
-> (forall (m :: * -> *). CParser ident m => m a)
-> Q a
runParserInQ String
s CParserContext ident
ctx forall (m :: * -> *). CParser ident m => m a
p = do
Loc
loc <- Q Loc
TH.location
let (Int
line, Int
col) = Loc -> (Int, Int)
TH.loc_start Loc
loc
let parsecLoc :: SourcePos
parsecLoc = String -> Int -> Int -> SourcePos
Parsec.newPos (Loc -> String
TH.loc_filename Loc
loc) Int
line Int
col
let p' :: ReaderT (CParserContext ident) (ParsecT String () Identity) a
p' = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *) s u. Monad m => SourcePos -> ParsecT s u m ()
Parsec.setPosition SourcePos
parsecLoc) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *). CParser ident m => m a
p forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall (m :: * -> *). Parsing m => m ()
Parser.eof
case forall s i a.
Stream s Identity Char =>
CParserContext i
-> String
-> s
-> ReaderT (CParserContext i) (Parsec s ()) a
-> Either ParseError a
C.runCParser CParserContext ident
ctx (Loc -> String
TH.loc_filename Loc
loc) String
s ReaderT (CParserContext ident) (ParsecT String () Identity) a
p' of
Left ParseError
err -> do
forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show ParseError
err
Right a
res -> do
forall (m :: * -> *) a. Monad m => a -> m a
return a
res
data SomeEq = forall a. (Typeable a, Eq a) => SomeEq a
instance Eq SomeEq where
SomeEq a
x == :: SomeEq -> SomeEq -> Bool
== SomeEq a
y = case forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast a
x of
Maybe a
Nothing -> Bool
False
Just a
x' -> a
x' forall a. Eq a => a -> a -> Bool
== a
y
instance Show SomeEq where
show :: SomeEq -> String
show SomeEq
_ = String
"<<SomeEq>>"
toSomeEq :: (Eq a, Typeable a) => a -> SomeEq
toSomeEq :: forall a. (Eq a, Typeable a) => a -> SomeEq
toSomeEq a
x = forall a. (Typeable a, Eq a) => a -> SomeEq
SomeEq a
x
fromSomeEq :: (Eq a, Typeable a) => SomeEq -> Maybe a
fromSomeEq :: forall a. (Eq a, Typeable a) => SomeEq -> Maybe a
fromSomeEq (SomeEq a
x) = forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast a
x
data ParameterType
= Plain HaskellIdentifier
| AntiQuote AntiQuoterId SomeEq
deriving (Int -> ParameterType -> String -> String
[ParameterType] -> String -> String
ParameterType -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [ParameterType] -> String -> String
$cshowList :: [ParameterType] -> String -> String
show :: ParameterType -> String
$cshow :: ParameterType -> String
showsPrec :: Int -> ParameterType -> String -> String
$cshowsPrec :: Int -> ParameterType -> String -> String
Show, ParameterType -> ParameterType -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ParameterType -> ParameterType -> Bool
$c/= :: ParameterType -> ParameterType -> Bool
== :: ParameterType -> ParameterType -> Bool
$c== :: ParameterType -> ParameterType -> Bool
Eq)
data ParseTypedC = ParseTypedC
{ ParseTypedC -> Type CIdentifier
ptcReturnType :: C.Type C.CIdentifier
, ParseTypedC -> [(CIdentifier, Type CIdentifier, ParameterType)]
ptcParameters :: [(C.CIdentifier, C.Type C.CIdentifier, ParameterType)]
, ParseTypedC -> String
ptcBody :: String
}
newtype Substitutions = Substitutions { Substitutions -> Map String (String -> String)
unSubstitutions :: M.Map String (String -> String) }
applySubstitutions :: String -> TH.Q String
applySubstitutions :: String -> Q String
applySubstitutions String
str = do
Map String (String -> String)
subs <- forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Monoid a => a
mempty Substitutions -> Map String (String -> String)
unSubstitutions forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Typeable a => Q (Maybe a)
TH.getQ
let substitution :: ParsecT String () Identity String
substitution = forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (a -> b) -> [a] -> [b]
map (forall k a. Map k a -> [(k, a)]
M.toList Map String (String -> String)
subs) forall a b. (a -> b) -> a -> b
$ \( String
subName, String -> String
subFunc ) ->
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
Parsec.try forall a b. (a -> b) -> a -> b
$ do
String
_ <- forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
Parsec.string (Char
'@' forall a. a -> [a] -> [a]
: String
subName forall a. [a] -> [a] -> [a]
++ String
"(")
String
subArg <- forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
Parsec.manyTill forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
Parsec.anyChar (forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
Parsec.char Char
')')
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> String
subFunc String
subArg)
let someChar :: ParsecT String u Identity String
someChar = (forall a. a -> [a] -> [a]
:[]) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
Parsec.anyChar
case forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
Parsec.parse (forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (ParsecT String () Identity String
substitution forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall {u}. ParsecT String u Identity String
someChar)) String
"" String
str of
Left ParseError
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Substitution failed (should be impossible)"
Right [String]
chunks -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String]
chunks)
substitute :: [ ( String, String -> String ) ] -> TH.Q a -> TH.Q a
substitute :: forall a. [(String, String -> String)] -> Q a -> Q a
substitute [(String, String -> String)]
subsList Q a
cont = do
Map String (String -> String)
oldSubs <- forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. Monoid a => a
mempty Substitutions -> Map String (String -> String)
unSubstitutions forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Typeable a => Q (Maybe a)
TH.getQ
let subs :: Map String (String -> String)
subs = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(String, String -> String)]
subsList
let conflicting :: Map String (String -> String)
conflicting = forall k a b. Ord k => Map k a -> Map k b -> Map k a
M.intersection Map String (String -> String)
subs Map String (String -> String)
oldSubs
Substitutions
newSubs <-
if forall k a. Map k a -> Bool
M.null Map String (String -> String)
conflicting
then forall (m :: * -> *) a. Monad m => a -> m a
return (Map String (String -> String) -> Substitutions
Substitutions (forall k a. Ord k => Map k a -> Map k a -> Map k a
M.union Map String (String -> String)
oldSubs Map String (String -> String)
subs))
else forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"Conflicting substitutions `" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall k a. Map k a -> [k]
M.keys Map String (String -> String)
conflicting) forall a. [a] -> [a] -> [a]
++ String
"`")
forall a. Typeable a => a -> Q ()
TH.putQ Substitutions
newSubs forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Q a
cont forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall a. Typeable a => a -> Q ()
TH.putQ (Map String (String -> String) -> Substitutions
Substitutions Map String (String -> String)
oldSubs)
getHaskellType :: Bool -> String -> TH.TypeQ
getHaskellType :: Bool -> String -> Q Type
getHaskellType Bool
pureFunctions String
cTypeStr = do
Context
ctx <- Q Context
getContext
let cParseCtx :: CParserContext CIdentifier
cParseCtx = Bool -> TypeNames -> CParserContext CIdentifier
C.cCParserContext (Context -> Bool
ctxEnableCpp Context
ctx) (TypesTable -> TypeNames
typeNamesFromTypesTable (Context -> TypesTable
ctxTypesTable Context
ctx))
Type CIdentifier
cType <- forall ident a.
Hashable ident =>
String
-> CParserContext ident
-> (forall (m :: * -> *). CParser ident m => m a)
-> Q a
runParserInQ String
cTypeStr CParserContext CIdentifier
cParseCtx forall i (m :: * -> *). (CParser i m, Pretty i) => m (Type i)
C.parseType
Context -> Purity -> Type CIdentifier -> Q Type
cToHs Context
ctx (if Bool
pureFunctions then Purity
Pure else Purity
IO) Type CIdentifier
cType
parseTypedC
:: forall m. C.CParser HaskellIdentifier m
=> Bool -> AntiQuoters -> m ParseTypedC
parseTypedC :: forall (m :: * -> *).
CParser HaskellIdentifier m =>
Bool -> AntiQuoters -> m ParseTypedC
parseTypedC Bool
useCpp AntiQuoters
antiQs = do
forall (m :: * -> *). CharParsing m => m ()
Parser.spaces
Type CIdentifier
cRetType <- forall (n :: * -> *).
MonadFail n =>
Type HaskellIdentifier -> n (Type CIdentifier)
purgeHaskellIdentifiers forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall i (m :: * -> *). (CParser i m, Pretty i) => m (Type i)
C.parseType
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'{'
([(CIdentifier, Type CIdentifier, ParameterType)]
cParams, String
cBody) <- forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseBody Int
0
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Type CIdentifier
-> [(CIdentifier, Type CIdentifier, ParameterType)]
-> String
-> ParseTypedC
ParseTypedC Type CIdentifier
cRetType [(CIdentifier, Type CIdentifier, ParameterType)]
cParams String
cBody
where
parseBody
:: StateT Int m ([(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String)
parseBody :: StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseBody = do
String
s <- forall (m :: * -> *) a end. Alternative m => m a -> m end -> m [a]
Parser.manyTill forall (m :: * -> *). CharParsing m => m Char
Parser.anyChar forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) a. LookAheadParsing m => m a -> m a
Parser.lookAhead (forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'}' forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'$')
([(CIdentifier, Type CIdentifier, ParameterType)]
decls, String
s') <- forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum
[ do forall (m :: * -> *) a. Parsing m => m a -> m a
Parser.try forall a b. (a -> b) -> a -> b
$ do
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). TokenParsing m => Char -> m Char
Parser.symbolic Char
'}'
forall (m :: * -> *). Parsing m => m ()
Parser.eof
forall (m :: * -> *) a. Monad m => a -> m a
return ([], String
"")
, do forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'}'
([(CIdentifier, Type CIdentifier, ParameterType)]
decls, String
s') <- StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseBody
forall (m :: * -> *) a. Monad m => a -> m a
return ([(CIdentifier, Type CIdentifier, ParameterType)]
decls, String
"}" forall a. [a] -> [a] -> [a]
++ String
s')
, do forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'$'
([(CIdentifier, Type CIdentifier, ParameterType)]
decls1, String
s1) <- forall a. StateT Int m ([a], String)
parseEscapedDollar forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseAntiQuote forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseTypedCapture
([(CIdentifier, Type CIdentifier, ParameterType)]
decls2, String
s2) <- StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseBody
forall (m :: * -> *) a. Monad m => a -> m a
return ([(CIdentifier, Type CIdentifier, ParameterType)]
decls1 forall a. [a] -> [a] -> [a]
++ [(CIdentifier, Type CIdentifier, ParameterType)]
decls2, String
s1 forall a. [a] -> [a] -> [a]
++ String
s2)
]
forall (m :: * -> *) a. Monad m => a -> m a
return ([(CIdentifier, Type CIdentifier, ParameterType)]
decls, String
s forall a. [a] -> [a] -> [a]
++ String
s')
where
parseAntiQuote
:: StateT Int m ([(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String)
parseAntiQuote :: StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseAntiQuote = forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum
[ do forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Parsing m => m a -> m a
Parser.try (forall (m :: * -> *). CharParsing m => String -> m String
Parser.string forall a b. (a -> b) -> a -> b
$ String
antiQId forall a. [a] -> [a] -> [a]
++ String
":") forall (m :: * -> *) a. Parsing m => m a -> String -> m a
Parser.<?> String
"anti quoter id"
(CIdentifier
s, Type CIdentifier
cTy, a
x) <- forall a.
AntiQuoter a
-> forall (m :: * -> *).
CParser HaskellIdentifier m =>
m (CIdentifier, Type CIdentifier, a)
aqParser AntiQuoter a
antiQ
CIdentifier
id' <- CIdentifier -> StateT Int m CIdentifier
freshId CIdentifier
s
forall (m :: * -> *) a. Monad m => a -> m a
return ([(CIdentifier
id', Type CIdentifier
cTy, String -> SomeEq -> ParameterType
AntiQuote String
antiQId (forall a. (Eq a, Typeable a) => a -> SomeEq
toSomeEq a
x))], CIdentifier -> String
C.unCIdentifier CIdentifier
id')
| (String
antiQId, SomeAntiQuoter AntiQuoter a
antiQ) <- forall k a. Map k a -> [(k, a)]
Map.toList AntiQuoters
antiQs
]
parseEscapedDollar :: StateT Int m ([a], String)
parseEscapedDollar :: forall a. StateT Int m ([a], String)
parseEscapedDollar = do
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'$'
forall (m :: * -> *) a. Monad m => a -> m a
return ([], String
"$")
parseTypedCapture
:: StateT Int m ([(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String)
parseTypedCapture :: StateT
Int m ([(CIdentifier, Type CIdentifier, ParameterType)], String)
parseTypedCapture = do
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). TokenParsing m => Char -> m Char
Parser.symbolic Char
'('
ParameterDeclaration HaskellIdentifier
decl <- forall i (m :: * -> *).
(CParser i m, Pretty i) =>
m (ParameterDeclaration i)
C.parseParameterDeclaration
Type CIdentifier
declType <- forall (n :: * -> *).
MonadFail n =>
Type HaskellIdentifier -> n (Type CIdentifier)
purgeHaskellIdentifiers forall a b. (a -> b) -> a -> b
$ forall i. ParameterDeclaration i -> Type i
C.parameterDeclarationType ParameterDeclaration HaskellIdentifier
decl
HaskellIdentifier
hId <- case forall i. ParameterDeclaration i -> Maybe i
C.parameterDeclarationId ParameterDeclaration HaskellIdentifier
decl of
Maybe HaskellIdentifier
Nothing -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ forall ann. Doc ann -> String
pretty80 forall a b. (a -> b) -> a -> b
$
Doc Any
"Un-named captured variable in decl" forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
PP.pretty ParameterDeclaration HaskellIdentifier
decl
Just HaskellIdentifier
hId -> forall (m :: * -> *) a. Monad m => a -> m a
return HaskellIdentifier
hId
CIdentifier
id' <- CIdentifier -> StateT Int m CIdentifier
freshId forall a b. (a -> b) -> a -> b
$ Bool -> HaskellIdentifier -> CIdentifier
mangleHaskellIdentifier Bool
useCpp HaskellIdentifier
hId
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
')'
forall (m :: * -> *) a. Monad m => a -> m a
return ([(CIdentifier
id', Type CIdentifier
declType, HaskellIdentifier -> ParameterType
Plain HaskellIdentifier
hId)], CIdentifier -> String
C.unCIdentifier CIdentifier
id')
freshId :: CIdentifier -> StateT Int m CIdentifier
freshId CIdentifier
s = do
Int
c <- forall s (m :: * -> *). MonadState s m => m s
get
forall s (m :: * -> *). MonadState s m => s -> m ()
put forall a b. (a -> b) -> a -> b
$ Int
c forall a. Num a => a -> a -> a
+ Int
1
case Bool -> String -> Either String CIdentifier
C.cIdentifierFromString Bool
useCpp (CIdentifier -> String
C.unCIdentifier CIdentifier
s forall a. [a] -> [a] -> [a]
++ String
"_inline_c_" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
c) of
Left String
_err -> forall a. HasCallStack => String -> a
error String
"freshId: The impossible happened"
Right CIdentifier
x -> forall (m :: * -> *) a. Monad m => a -> m a
return CIdentifier
x
purgeHaskellIdentifiers
#if MIN_VERSION_base(4,13,0)
:: forall n. MonadFail n
#else
:: forall n. (Applicative n, Monad n)
#endif
=> C.Type HaskellIdentifier -> n (C.Type C.CIdentifier)
purgeHaskellIdentifiers :: forall (n :: * -> *).
MonadFail n =>
Type HaskellIdentifier -> n (Type CIdentifier)
purgeHaskellIdentifiers Type HaskellIdentifier
cTy = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for Type HaskellIdentifier
cTy forall a b. (a -> b) -> a -> b
$ \HaskellIdentifier
hsIdent -> do
let hsIdentS :: String
hsIdentS = HaskellIdentifier -> String
unHaskellIdentifier HaskellIdentifier
hsIdent
case Bool -> String -> Either String CIdentifier
C.cIdentifierFromString Bool
useCpp String
hsIdentS of
Left String
err -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"Haskell identifier " forall a. [a] -> [a] -> [a]
++ String
hsIdentS forall a. [a] -> [a] -> [a]
++ String
" in illegal position" forall a. [a] -> [a] -> [a]
++
String
"in C type\n" forall a. [a] -> [a] -> [a]
++ forall ann. Doc ann -> String
pretty80 (forall a ann. Pretty a => a -> Doc ann
PP.pretty Type HaskellIdentifier
cTy) forall a. [a] -> [a] -> [a]
++ String
"\n" forall a. [a] -> [a] -> [a]
++
String
"A C identifier was expected, but:\n" forall a. [a] -> [a] -> [a]
++ String
err
Right CIdentifier
cIdent -> forall (m :: * -> *) a. Monad m => a -> m a
return CIdentifier
cIdent
quoteCode
:: (String -> TH.ExpQ)
-> TH.QuasiQuoter
quoteCode :: (String -> Q Exp) -> QuasiQuoter
quoteCode String -> Q Exp
p = TH.QuasiQuoter
{ quoteExp :: String -> Q Exp
TH.quoteExp = String -> Q Exp
p
, quotePat :: String -> Q Pat
TH.quotePat = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: quotePat not implemented (quoteCode)"
, quoteType :: String -> Q Type
TH.quoteType = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: quoteType not implemented (quoteCode)"
, quoteDec :: String -> DecsQ
TH.quoteDec = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"inline-c: quoteDec not implemented (quoteCode)"
}
cToHs :: Context -> Purity -> C.Type C.CIdentifier -> TH.TypeQ
cToHs :: Context -> Purity -> Type CIdentifier -> Q Type
cToHs Context
ctx Purity
purity Type CIdentifier
cTy = do
Maybe Type
mbHsTy <- Purity -> TypesTable -> Type CIdentifier -> Q (Maybe Type)
convertType Purity
purity (Context -> TypesTable
ctxTypesTable Context
ctx) Type CIdentifier
cTy
case Maybe Type
mbHsTy of
Maybe Type
Nothing -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"Could not resolve Haskell type for C type " forall a. [a] -> [a] -> [a]
++ forall ann. Doc ann -> String
pretty80 (forall a ann. Pretty a => a -> Doc ann
PP.pretty Type CIdentifier
cTy)
Just Type
hsTy -> forall (m :: * -> *) a. Monad m => a -> m a
return Type
hsTy
genericQuote
:: Purity
-> (TH.Loc -> TH.TypeQ -> C.Type C.CIdentifier -> [(C.CIdentifier, C.Type C.CIdentifier)] -> String -> TH.ExpQ)
-> TH.QuasiQuoter
genericQuote :: Purity
-> (Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp)
-> QuasiQuoter
genericQuote Purity
purity Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp
build = (String -> Q Exp) -> QuasiQuoter
quoteCode forall a b. (a -> b) -> a -> b
$ \String
rawStr -> do
Context
ctx <- Q Context
getContext
Loc
here <- Q Loc
TH.location
String
s <- String -> Q String
applySubstitutions String
rawStr
ParseTypedC Type CIdentifier
cType [(CIdentifier, Type CIdentifier, ParameterType)]
cParams String
cExp <-
forall ident a.
Hashable ident =>
String
-> CParserContext ident
-> (forall (m :: * -> *). CParser ident m => m a)
-> Q a
runParserInQ String
s
(Bool -> TypeNames -> CParserContext HaskellIdentifier
haskellCParserContext (Context -> Bool
ctxEnableCpp Context
ctx) (TypesTable -> TypeNames
typeNamesFromTypesTable (Context -> TypesTable
ctxTypesTable Context
ctx)))
(forall (m :: * -> *).
CParser HaskellIdentifier m =>
Bool -> AntiQuoters -> m ParseTypedC
parseTypedC (Context -> Bool
ctxEnableCpp Context
ctx) (Context -> AntiQuoters
ctxAntiQuoters Context
ctx))
Type
hsType <- Context -> Purity -> Type CIdentifier -> Q Type
cToHs Context
ctx Purity
purity Type CIdentifier
cType
[(Type, Exp)]
hsParams <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [(CIdentifier, Type CIdentifier, ParameterType)]
cParams forall a b. (a -> b) -> a -> b
$ \(CIdentifier
_cId, Type CIdentifier
cTy, ParameterType
parTy) -> do
case ParameterType
parTy of
Plain HaskellIdentifier
s' -> do
Type
hsTy <- Context -> Purity -> Type CIdentifier -> Q Type
cToHs Context
ctx Purity
purity Type CIdentifier
cTy
let hsName :: Name
hsName = String -> Name
TH.mkName (HaskellIdentifier -> String
unHaskellIdentifier HaskellIdentifier
s')
Exp
hsExp <- [| \cont -> cont ($(TH.varE hsName) :: $(return hsTy)) |]
forall (m :: * -> *) a. Monad m => a -> m a
return (Type
hsTy, Exp
hsExp)
AntiQuote String
antiId SomeEq
dyn -> do
case forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
antiId (Context -> AntiQuoters
ctxAntiQuoters Context
ctx) of
Maybe SomeAntiQuoter
Nothing ->
forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"IMPOSSIBLE: could not find anti-quoter " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
antiId forall a. [a] -> [a] -> [a]
++
String
". (genericQuote)"
Just (SomeAntiQuoter AntiQuoter a
antiQ) -> case forall a. (Eq a, Typeable a) => SomeEq -> Maybe a
fromSomeEq SomeEq
dyn of
Maybe a
Nothing ->
forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"IMPOSSIBLE: could not cast value for anti-quoter " forall a. [a] -> [a] -> [a]
++
forall a. Show a => a -> String
show String
antiId forall a. [a] -> [a] -> [a]
++ String
". (genericQuote)"
Just a
x ->
forall a.
AntiQuoter a
-> Purity -> TypesTable -> Type CIdentifier -> a -> Q (Type, Exp)
aqMarshaller AntiQuoter a
antiQ Purity
purity (Context -> TypesTable
ctxTypesTable Context
ctx) Type CIdentifier
cTy a
x
let hsFunType :: Q Type
hsFunType = Type -> [Type] -> Q Type
convertCFunSig Type
hsType forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst [(Type, Exp)]
hsParams
let cParams' :: [(CIdentifier, Type CIdentifier)]
cParams' = [(CIdentifier
cId, Type CIdentifier
cTy) | (CIdentifier
cId, Type CIdentifier
cTy, ParameterType
_) <- [(CIdentifier, Type CIdentifier, ParameterType)]
cParams]
Exp
ioCall <- Context -> Q Exp -> [Exp] -> [Name] -> Q Exp
buildFunCall Context
ctx (Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp
build Loc
here Q Type
hsFunType Type CIdentifier
cType [(CIdentifier, Type CIdentifier)]
cParams' String
cExp) (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [(Type, Exp)]
hsParams) []
case Purity
purity of
Purity
Pure -> [| unsafeDupablePerformIO $(return ioCall) |]
Purity
IO -> forall (m :: * -> *) a. Monad m => a -> m a
return Exp
ioCall
where
buildFunCall :: Context -> TH.ExpQ -> [TH.Exp] -> [TH.Name] -> TH.ExpQ
buildFunCall :: Context -> Q Exp -> [Exp] -> [Name] -> Q Exp
buildFunCall Context
_ctx Q Exp
f [] [Name]
args =
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\Q Exp
f' Name
arg -> [| $f' $(TH.varE arg) |]) Q Exp
f [Name]
args
buildFunCall Context
ctx Q Exp
f (Exp
hsExp : [Exp]
params) [Name]
args =
[| $(return hsExp) $ \arg ->
$(buildFunCall ctx f params (args ++ ['arg]))
|]
convertCFunSig :: TH.Type -> [TH.Type] -> TH.TypeQ
convertCFunSig :: Type -> [Type] -> Q Type
convertCFunSig Type
retType [Type]
params0 = do
[Type] -> Q Type
go [Type]
params0
where
go :: [Type] -> Q Type
go [] =
[t| IO $(return retType) |]
go (Type
paramType : [Type]
params) = do
[t| $(return paramType) -> $(go params) |]
splitTypedC :: String -> (String, String, Int)
splitTypedC :: String -> (String, String, Int)
splitTypedC String
s = (String -> String
trim String
ty, String
bodyIndent forall a. Semigroup a => a -> a -> a
<> String
body, Int
bodyLineShift)
where (String
ty, String
body) = forall a. (a -> Bool) -> [a] -> ([a], [a])
span (forall a. Eq a => a -> a -> Bool
/= Char
'{') String
s
trim :: String -> String
trim String
x = forall a. (a -> Bool) -> [a] -> [a]
L.dropWhileEnd Char -> Bool
C.isSpace (forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
C.isSpace String
x)
bodyLineShift :: Int
bodyLineShift = forall (t :: * -> *) a. Foldable t => t a -> Int
length (forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Eq a => a -> a -> Bool
== Char
'\n') String
ty)
bodyIndent :: String
bodyIndent =
let precedingSpaceReversed :: String
precedingSpaceReversed =
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (\Char
c -> Char -> Bool
C.isSpace Char
c) forall a b. (a -> b) -> a -> b
$
forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$
String
ty
(String
precedingSpacesTabsReversed, String
precedingLine) =
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` (String
"\n\r" :: [Char])) String
precedingSpaceReversed
in case String
precedingLine of
(Char
'\n':String
_) -> forall a. [a] -> [a]
reverse String
precedingSpacesTabsReversed
(Char
'\r':String
_) -> forall a. [a] -> [a]
reverse String
precedingSpacesTabsReversed
String
_ -> String
""
data FunPtrDecl = FunPtrDecl
{ FunPtrDecl -> Type CIdentifier
funPtrReturnType :: C.Type C.CIdentifier
, FunPtrDecl -> [(CIdentifier, Type CIdentifier)]
funPtrParameters :: [(C.CIdentifier, C.Type C.CIdentifier)]
, FunPtrDecl -> String
funPtrBody :: String
, FunPtrDecl -> Maybe String
funPtrName :: Maybe String
} deriving (FunPtrDecl -> FunPtrDecl -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FunPtrDecl -> FunPtrDecl -> Bool
$c/= :: FunPtrDecl -> FunPtrDecl -> Bool
== :: FunPtrDecl -> FunPtrDecl -> Bool
$c== :: FunPtrDecl -> FunPtrDecl -> Bool
Eq, Int -> FunPtrDecl -> String -> String
[FunPtrDecl] -> String -> String
FunPtrDecl -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [FunPtrDecl] -> String -> String
$cshowList :: [FunPtrDecl] -> String -> String
show :: FunPtrDecl -> String
$cshow :: FunPtrDecl -> String
showsPrec :: Int -> FunPtrDecl -> String -> String
$cshowsPrec :: Int -> FunPtrDecl -> String -> String
Show)
funPtrQuote :: TH.Safety -> TH.QuasiQuoter
funPtrQuote :: Safety -> QuasiQuoter
funPtrQuote Safety
callSafety = (String -> Q Exp) -> QuasiQuoter
quoteCode forall a b. (a -> b) -> a -> b
$ \String
rawCode -> do
Loc
loc <- Q Loc
TH.location
Context
ctx <- Q Context
getContext
String
code <- String -> Q String
applySubstitutions String
rawCode
FunPtrDecl{String
[(CIdentifier, Type CIdentifier)]
Maybe String
Type CIdentifier
funPtrName :: Maybe String
funPtrBody :: String
funPtrParameters :: [(CIdentifier, Type CIdentifier)]
funPtrReturnType :: Type CIdentifier
funPtrName :: FunPtrDecl -> Maybe String
funPtrBody :: FunPtrDecl -> String
funPtrParameters :: FunPtrDecl -> [(CIdentifier, Type CIdentifier)]
funPtrReturnType :: FunPtrDecl -> Type CIdentifier
..} <- forall ident a.
Hashable ident =>
String
-> CParserContext ident
-> (forall (m :: * -> *). CParser ident m => m a)
-> Q a
runParserInQ String
code (Bool -> TypeNames -> CParserContext CIdentifier
C.cCParserContext (Context -> Bool
ctxEnableCpp Context
ctx) (TypesTable -> TypeNames
typeNamesFromTypesTable (Context -> TypesTable
ctxTypesTable Context
ctx))) forall (m :: * -> *). CParser CIdentifier m => m FunPtrDecl
parse
Type
hsRetType <- Context -> Purity -> Type CIdentifier -> Q Type
cToHs Context
ctx Purity
IO Type CIdentifier
funPtrReturnType
[Type]
hsParams <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [(CIdentifier, Type CIdentifier)]
funPtrParameters (\(CIdentifier
_ident, Type CIdentifier
typ_) -> Context -> Purity -> Type CIdentifier -> Q Type
cToHs Context
ctx Purity
IO Type CIdentifier
typ_)
let hsFunType :: Q Type
hsFunType = Type -> [Type] -> Q Type
convertCFunSig Type
hsRetType [Type]
hsParams
Safety
-> Bool
-> Maybe String
-> Loc
-> Q Type
-> Type CIdentifier
-> [(CIdentifier, Type CIdentifier)]
-> String
-> Q Exp
inlineItems Safety
callSafety Bool
True Maybe String
funPtrName Loc
loc Q Type
hsFunType Type CIdentifier
funPtrReturnType [(CIdentifier, Type CIdentifier)]
funPtrParameters String
funPtrBody
where
convertCFunSig :: TH.Type -> [TH.Type] -> TH.TypeQ
convertCFunSig :: Type -> [Type] -> Q Type
convertCFunSig Type
retType [Type]
params0 = do
[Type] -> Q Type
go [Type]
params0
where
go :: [Type] -> Q Type
go [] =
[t| IO $(return retType) |]
go (Type
paramType : [Type]
params) = do
[t| $(return paramType) -> $(go params) |]
parse :: C.CParser C.CIdentifier m => m FunPtrDecl
parse :: forall (m :: * -> *). CParser CIdentifier m => m FunPtrDecl
parse = do
forall (m :: * -> *). CharParsing m => m ()
Parser.spaces
C.ParameterDeclaration Maybe CIdentifier
mbName Type CIdentifier
protoTyp <- forall i (m :: * -> *).
(CParser i m, Pretty i) =>
m (ParameterDeclaration i)
C.parseParameterDeclaration
case Type CIdentifier
protoTyp of
C.Proto Type CIdentifier
retType [ParameterDeclaration CIdentifier]
paramList -> do
[(CIdentifier, Type CIdentifier)]
args <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [ParameterDeclaration CIdentifier]
paramList forall a b. (a -> b) -> a -> b
$ \ParameterDeclaration CIdentifier
decl -> case forall i. ParameterDeclaration i -> Maybe i
C.parameterDeclarationId ParameterDeclaration CIdentifier
decl of
Maybe CIdentifier
Nothing -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ forall ann. Doc ann -> String
pretty80 forall a b. (a -> b) -> a -> b
$
Doc Any
"Un-named captured variable in decl" forall ann. Doc ann -> Doc ann -> Doc ann
<+> forall a ann. Pretty a => a -> Doc ann
PP.pretty ParameterDeclaration CIdentifier
decl
Just CIdentifier
declId -> forall (m :: * -> *) a. Monad m => a -> m a
return (CIdentifier
declId, forall i. ParameterDeclaration i -> Type i
C.parameterDeclarationType ParameterDeclaration CIdentifier
decl)
forall (f :: * -> *) a. Functor f => f a -> f ()
void (forall (m :: * -> *). TokenParsing m => Char -> m Char
Parser.symbolic Char
'{')
String
body <- forall (m :: * -> *). CParser CIdentifier m => m String
parseBody
forall (m :: * -> *) a. Monad m => a -> m a
return FunPtrDecl
{ funPtrReturnType :: Type CIdentifier
funPtrReturnType = Type CIdentifier
retType
, funPtrParameters :: [(CIdentifier, Type CIdentifier)]
funPtrParameters = [(CIdentifier, Type CIdentifier)]
args
, funPtrBody :: String
funPtrBody = String
body
, funPtrName :: Maybe String
funPtrName = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CIdentifier -> String
C.unCIdentifier Maybe CIdentifier
mbName
}
Type CIdentifier
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"Expecting function declaration"
parseBody :: C.CParser C.CIdentifier m => m String
parseBody :: forall (m :: * -> *). CParser CIdentifier m => m String
parseBody = do
String
s <- forall (m :: * -> *) a end. Alternative m => m a -> m end -> m [a]
Parser.manyTill forall (m :: * -> *). CharParsing m => m Char
Parser.anyChar forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) a. LookAheadParsing m => m a -> m a
Parser.lookAhead (forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'}')
String
s' <- forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum
[ do forall (m :: * -> *) a. Parsing m => m a -> m a
Parser.try forall a b. (a -> b) -> a -> b
$ do
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). TokenParsing m => Char -> m Char
Parser.symbolic Char
'}'
forall (m :: * -> *). Parsing m => m ()
Parser.eof
forall (m :: * -> *) a. Monad m => a -> m a
return String
""
, do forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). CharParsing m => Char -> m Char
Parser.char Char
'}'
String
s' <- forall (m :: * -> *). CParser CIdentifier m => m String
parseBody
forall (m :: * -> *) a. Monad m => a -> m a
return (String
"}" forall a. [a] -> [a] -> [a]
++ String
s')
]
forall (m :: * -> *) a. Monad m => a -> m a
return (String
s forall a. [a] -> [a] -> [a]
++ String
s')
lineDirective :: TH.Loc -> String
lineDirective :: Loc -> String
lineDirective Loc
l = String
"#line " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ Loc -> (Int, Int)
TH.loc_start Loc
l) forall a. [a] -> [a] -> [a]
++ String
" " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (Loc -> String
TH.loc_filename Loc
l ) forall a. [a] -> [a] -> [a]
++ String
"\n"
here :: TH.ExpQ
here :: Q Exp
here = [| $(TH.location >>= \(TH.Loc a b c (d1, d2) (e1, e2)) ->
[|Loc
$(TH.lift a)
$(TH.lift b)
$(TH.lift c)
($(TH.lift d1), $(TH.lift d2))
($(TH.lift e1), $(TH.lift e2))
|])
|]
shiftLines :: Int -> TH.Loc -> TH.Loc
shiftLines :: Int -> Loc -> Loc
shiftLines Int
n Loc
l = Loc
l
{ loc_start :: (Int, Int)
TH.loc_start =
let (Int
startLn, Int
startCol) = Loc -> (Int, Int)
TH.loc_start Loc
l
in (Int
startLn forall a. Num a => a -> a -> a
+ Int
n, Int
startCol)
, loc_end :: (Int, Int)
TH.loc_end =
let (Int
endLn, Int
endCol) = Loc -> (Int, Int)
TH.loc_end Loc
l
in (Int
endLn forall a. Num a => a -> a -> a
+ Int
n, Int
endCol)
}
pretty80 :: PP.Doc ann -> String
pretty80 :: forall ann. Doc ann -> String
pretty80 Doc ann
x = forall ann. SimpleDocStream ann -> String
PP.renderString forall a b. (a -> b) -> a -> b
$ forall ann. LayoutOptions -> Doc ann -> SimpleDocStream ann
PP.layoutSmart (PP.LayoutOptions { layoutPageWidth :: PageWidth
PP.layoutPageWidth = Int -> Double -> PageWidth
PP.AvailablePerLine Int
80 Double
0.8 }) Doc ann
x
prettyOneLine :: PP.Doc ann -> String
prettyOneLine :: forall ann. Doc ann -> String
prettyOneLine Doc ann
x = forall ann. SimpleDocStream ann -> String
PP.renderString forall a b. (a -> b) -> a -> b
$ forall ann1 ann2. Doc ann1 -> SimpleDocStream ann2
PP.layoutCompact Doc ann
x