module Language.C.Inline.State (
State,
initialiseState,
setForeignTable, stashHeader, stashMarshaller, stashObjC_h, stashObjC_m, stashHS,
extendJumpTable,
getForeignTable, getForeignLabels, getHeaders, getMarshallers, lookupMarshaller, getHoistedObjC, getHoistedHS
) where
import Control.Applicative
import Data.IORef
import Foreign.C as C
import Language.Haskell.TH as TH
import Language.Haskell.TH.Syntax as TH
import System.IO.Unsafe (unsafePerformIO)
import Language.C.Quote as QC
type CustomMarshaller = ( TH.Type
, TH.Type
, QC.Type
, TH.Name
, TH.Name)
data State
= State
{ foreignTable :: Q TH.Exp
, foreignLabels :: [Name]
, headers :: [String]
, marshallers :: [CustomMarshaller]
, hoistedObjC_h :: [QC.Definition]
, hoistedObjC_m :: [QC.Definition]
, hoistedHS :: [TH.Dec]
}
state :: IORef State
state = unsafePerformIO $
newIORef initialState
initialState :: State
initialState
= State
{ foreignTable = error "Language.C.Inline.State: internal error: 'foreignTable' undefined"
, foreignLabels = []
, headers = []
, marshallers = []
, hoistedObjC_h = []
, hoistedObjC_m = []
, hoistedHS = []
}
initialiseState :: Q ()
initialiseState = modifyState (const initialState)
readState :: (State -> a) -> Q a
readState read = runIO $ read <$> readIORef state
modifyState :: (State -> State) -> Q ()
modifyState modify = runIO $ modifyIORef state modify
setForeignTable :: Q TH.Exp -> Q ()
setForeignTable e = modifyState (\s -> s {foreignTable = e})
stashHeader :: String -> Q ()
stashHeader header = modifyState (\s -> s {headers = header : headers s})
stashMarshaller :: CustomMarshaller -> Q ()
stashMarshaller marshaller = modifyState (\s -> s {marshallers = marshaller : marshallers s})
stashObjC_h :: [QC.Definition] -> Q ()
stashObjC_h defs = modifyState (\s -> s {hoistedObjC_h = hoistedObjC_h s ++ defs})
stashObjC_m :: [QC.Definition] -> Q ()
stashObjC_m defs = modifyState (\s -> s {hoistedObjC_m = hoistedObjC_m s ++ defs})
stashHS :: [TH.DecQ] -> Q ()
stashHS decQs
= do
{ decs <- sequence decQs
; modifyState (\s -> s {hoistedHS = hoistedHS s ++ decs})
}
extendJumpTable :: Name -> Q Int
extendJumpTable foreignName
= do
{ modifyState (\s -> s {foreignLabels = foreignLabels s ++ [foreignName]})
; length <$> readState foreignLabels
}
getForeignTable :: Q (Q TH.Exp)
getForeignTable = readState foreignTable
getForeignLabels :: Q [Name]
getForeignLabels = readState foreignLabels
getHeaders :: Q [String]
getHeaders = reverse <$> readState headers
getMarshallers :: Q [CustomMarshaller]
getMarshallers = readState marshallers
lookupMarshaller :: TH.Type -> Q (Maybe CustomMarshaller)
lookupMarshaller ty
= do
{ marshallers <- getMarshallers
; case filter (\(hsTy, _, _, _, _) -> hsTy == ty) marshallers of
[] -> return Nothing
marshaller:_ -> return $ Just marshaller
}
getHoistedObjC :: Q ([QC.Definition], [QC.Definition])
getHoistedObjC = (,) <$> readState hoistedObjC_h <*> readState hoistedObjC_m
getHoistedHS :: Q [TH.Dec]
getHoistedHS = readState hoistedHS