{-# LANGUAGE CPP #-}
module Foreign.Hoppy.Generator.Language.Haskell (
Managed (..),
getModuleName,
toModuleName,
Partial (..),
Output (..),
Generator,
runGenerator,
evalGenerator,
execGenerator,
renderPartial,
askInterface,
askModule,
askModuleName,
getModuleForExtName,
withErrorContext,
inFunction,
HsExport,
addExport,
addExport',
addExports,
addImports,
addExtension,
sayLn,
saysLn,
ln,
indent,
indentSpaces,
sayLet,
toHsEnumTypeName,
toHsEnumTypeName',
toHsEnumCtorName,
toHsEnumCtorName',
toHsBitspaceTypeName,
toHsBitspaceTypeName',
toHsBitspaceValueName,
toHsBitspaceValueName',
toHsBitspaceToNumName,
toHsBitspaceToNumName',
toHsBitspaceClassName,
toHsBitspaceClassName',
toHsBitspaceFromValueName,
toHsBitspaceFromValueName',
toHsValueClassName,
toHsValueClassName',
toHsWithValuePtrName,
toHsWithValuePtrName',
toHsPtrClassName,
toHsPtrClassName',
toHsCastMethodName,
toHsCastMethodName',
toHsDownCastClassName,
toHsDownCastClassName',
toHsDownCastMethodName,
toHsDownCastMethodName',
toHsCastPrimitiveName,
toHsCastPrimitiveName',
toHsConstCastFnName,
toHsConstCastFnName',
toHsDataTypeName,
toHsDataTypeName',
toHsDataCtorName,
toHsDataCtorName',
toHsClassDeleteFnName',
toHsClassDeleteFnPtrName',
toHsCtorName,
toHsCtorName',
toHsMethodName,
toHsMethodName',
toHsClassEntityName,
toHsClassEntityName',
toHsCallbackCtorName,
toHsCallbackCtorName',
toHsCallbackNewFunPtrFnName,
toHsCallbackNewFunPtrFnName',
toHsFnName,
toHsFnName',
toArgName,
HsTypeSide (..),
cppTypeToHsTypeAndUse,
getClassHaskellConversion,
callbackToTFn,
prettyPrint,
) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Arrow (first)
#if MIN_VERSION_mtl(2,2,1)
import Control.Monad.Except (Except, catchError, runExcept, throwError)
#else
import Control.Monad.Error (catchError, throwError)
#endif
import Control.Monad.Reader (ReaderT, ask, runReaderT)
import Control.Monad.Writer (WriterT, censor, runWriterT, tell)
import Data.Char (toUpper)
import Data.Foldable (forM_)
import Data.Function (on)
import Data.Functor (($>))
import Data.List (intercalate, intersperse)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust)
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid (Monoid, mappend, mconcat, mempty)
#endif
import qualified Data.Set as S
import Data.Tuple (swap)
import Foreign.Hoppy.Generator.Common
import Foreign.Hoppy.Generator.Spec.Base
import Foreign.Hoppy.Generator.Types
import qualified Language.Haskell.Pretty as P
import Language.Haskell.Syntax (
HsName (HsIdent),
HsQName (Special, UnQual),
HsSpecialCon (HsUnitCon),
HsType (HsTyApp, HsTyCon, HsTyFun),
)
data Managed =
Unmanaged
| Managed
deriving (Bounded, Enum, Eq, Ord)
getModuleName :: Interface -> Module -> String
getModuleName interface m =
intercalate "." $
interfaceHaskellModuleBase interface ++
fromMaybe [toModuleName $ moduleName m] (moduleHaskellName m)
toModuleName :: String -> String
toModuleName (x:xs) = toUpper x : xs
toModuleName "" = ""
renderImports :: HsImportSet -> [String]
renderImports = map renderModuleImport . M.assocs . getHsImportSet
where
renderModuleImport :: (HsImportKey, HsImportSpecs) -> String
renderModuleImport (key, specs) =
let moduleName = hsImportModule key
maybeQualifiedName = hsImportQualifiedName key
isQual = isJust maybeQualifiedName
importPrefix = if hsImportSource specs
then "import {-# SOURCE #-} "
else "import "
importQualifiedPrefix =
if hsImportSource specs
then "import {-# SOURCE #-} qualified "
else "import qualified "
in case getHsImportSpecs specs of
Nothing -> case maybeQualifiedName of
Nothing -> importPrefix ++ moduleName
Just qualifiedName ->
concat [importQualifiedPrefix, moduleName, " as ", qualifiedName]
Just specMap ->
let specWords :: [String]
specWords = concatWithCommas $ map renderSpecAsWords $ M.assocs specMap
singleLineImport :: String
singleLineImport =
concat $
(if isQual then importQualifiedPrefix else importPrefix) :
moduleName : " (" : intersperse " " specWords ++
case maybeQualifiedName of
Nothing -> [")"]
Just qualifiedName -> [") as ", qualifiedName]
in if null $ drop maxLineLength singleLineImport
then singleLineImport
else intercalate "\n" $
(importPrefix ++ moduleName ++ " (") :
groupWordsIntoLines specWords ++
case maybeQualifiedName of
Nothing -> [" )"]
Just qualifiedName -> [" ) as " ++ qualifiedName]
renderSpecAsWords :: (HsImportName, HsImportVal) -> [String]
renderSpecAsWords (name, val) = case val of
HsImportVal -> [name]
HsImportValSome parts -> case parts of
[] -> [name ++ " ()"]
[part] -> [concat [name, " (", part, ")"]]
part0:parts -> let (parts', [partN]) = splitAt (length parts - 1) parts
in concat [name, " (", part0, ","] :
map (++ ",") parts' ++
[partN ++ ")"]
HsImportValAll -> [name ++ " (..)"]
concatWithCommas :: [[String]] -> [String]
concatWithCommas [] = []
concatWithCommas ss =
let (ss', ssLast@[_]) = splitAt (length ss - 1) ss
in concat $ map (onLast (++ ",")) ss' ++ ssLast
onLast :: (a -> a) -> [a] -> [a]
onLast _ [] = []
onLast f xs = let (xs', [x]) = splitAt (length xs - 1) xs
in xs' ++ [f x]
groupWordsIntoLines :: [String] -> [String]
groupWordsIntoLines [] = []
groupWordsIntoLines words =
let (wordCount, line, _) =
last $
takeWhile (\(wordCount, _, len) -> wordCount <= 1 || len <= maxLineLength) $
scanl (\(wordCount, acc, len) word ->
(wordCount + 1,
concat [acc, " ", word],
len + 1 + length word))
(0, "", 0)
words
in line : groupWordsIntoLines (drop wordCount words)
maxLineLength :: Int
maxLineLength = 100
#if MIN_VERSION_mtl(2,2,1)
type Generator = ReaderT Env (WriterT Output (Except ErrorMsg))
#else
type Generator = ReaderT Env (WriterT Output (Either ErrorMsg))
#endif
data Env = Env
{ envInterface :: Interface
, envModule :: Module
, envModuleName :: String
}
askInterface :: Generator Interface
askInterface = envInterface <$> ask
askModule :: Generator Module
askModule = envModule <$> ask
askModuleName :: Generator String
askModuleName = envModuleName <$> ask
getModuleForExtName :: ExtName -> Generator Module
getModuleForExtName extName = inFunction "getModuleForExtName" $ do
iface <- askInterface
case M.lookup extName $ interfaceNamesToModules iface of
Just mod -> return mod
Nothing -> throwError $ "Can't find module for " ++ show extName
data Partial = Partial
{ partialModuleHsName :: String
, partialOutput :: Output
}
instance Eq Partial where
(==) = (==) `on` partialModuleHsName
instance Ord Partial where
compare = compare `on` partialModuleHsName
data Output = Output
{ outputExports :: [HsExport]
, outputImports :: HsImportSet
, outputBody :: [String]
, outputExtensions :: S.Set String
}
instance Monoid Output where
mempty = Output mempty mempty mempty mempty
(Output e i b x) `mappend` (Output e' i' b' x') =
Output (e `mappend` e') (i `mappend` i') (b `mappend` b') (x `mappend` x')
mconcat os =
Output (mconcat $ map outputExports os)
(mconcat $ map outputImports os)
(mconcat $ map outputBody os)
(mconcat $ map outputExtensions os)
runGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg (Partial, a)
runGenerator iface mod generator =
let modName = getModuleName iface mod
in fmap (first (Partial modName) . swap) $
#if MIN_VERSION_mtl(2,2,1)
runExcept $
#endif
flip catchError (\msg -> throwError $ msg ++ ".") $
runWriterT $ runReaderT generator $ Env iface mod modName
evalGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg a
evalGenerator iface mod = fmap snd . runGenerator iface mod
execGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg Partial
execGenerator iface mod = fmap fst . runGenerator iface mod
renderPartial :: Partial -> String
renderPartial partial =
let modName = partialModuleHsName partial
output = partialOutput partial
imports = outputImports output
body =
intercalate "\n" $ concat
[ [ "---------- GENERATED FILE, EDITS WILL BE LOST ----------"
, ""
]
, case S.elems $ outputExtensions output of
[] -> []
extensions -> [ concat $ "{-# LANGUAGE " : intersperse ", " extensions ++ [" #-}"]
, ""
]
, case outputExports output of
[] -> [concat ["module ", modName, " where"]]
exports ->
concat ["module ", modName, " ("] :
map (\export -> concat [" ", export, ","]) exports ++
[" ) where"]
, if M.null $ getHsImportSet imports
then []
else "" : renderImports imports
, [""]
, outputBody output
]
in body
withErrorContext :: String -> Generator a -> Generator a
withErrorContext msg' action = catchError action $ \msg -> throwError $ concat [msg, "; ", msg']
inFunction :: String -> Generator a -> Generator a
inFunction fnName = withErrorContext $ "in " ++ fnName
type HsExport = String
addExport :: HsExport -> Generator ()
addExport = addExports . (:[])
addExport' :: HsExport -> Generator ()
addExport' x = addExports [x ++ " (..)"]
addExports :: [HsExport] -> Generator ()
addExports exports = tell $ mempty { outputExports = exports }
addImports :: HsImportSet -> Generator ()
addImports imports = tell mempty { outputImports = imports }
addExtension :: String -> Generator ()
addExtension extensionName =
tell $ mempty { outputExtensions = S.singleton extensionName }
sayLn :: String -> Generator ()
sayLn x =
if '\n' `elem` x
then inFunction "sayLn" $ throwError $ concat
["Refusing to speak '\n', received ", show x, " (use (mapM_ sayLn . lines) instead)"]
else tell $ mempty { outputBody = [x] }
saysLn :: [String] -> Generator ()
saysLn = sayLn . concat
ln :: Generator ()
ln = sayLn ""
indent :: Generator a -> Generator a
indent = censor $ \o -> o { outputBody = map (\x -> ' ':' ':x) $ outputBody o }
indentSpaces :: Int -> Generator a -> Generator a
indentSpaces n = censor $ \o -> o { outputBody = map (\x -> indentation ++ x) $ outputBody o }
where indentation = replicate n ' '
sayLet :: [Generator ()] -> Maybe (Generator ()) -> Generator ()
sayLet bindings maybeBody = do
sayLn "let"
indent $ sequence_ bindings
forM_ maybeBody $ \body ->
indent $ do
sayLn "in"
indent body
getExtNameModule :: ExtName -> Generator Module
getExtNameModule extName = inFunction "getExtNameModule" $ do
iface <- askInterface
fromMaybeM (throwError $ "Couldn't find module for " ++ show extName ++
" (is it included in a module's export list?)") $
M.lookup extName $
interfaceNamesToModules iface
getModuleImportName :: Module -> Generator String
getModuleImportName mod = do
iface <- askInterface
fromMaybeM (throwError $ "Couldn't find a Haskell import name for " ++ show mod ++
" (is it included in the interface's module list?)") $
M.lookup mod $
interfaceHaskellModuleImportNames iface
importHsModuleForExtName :: ExtName -> Generator (Maybe String)
importHsModuleForExtName extName = do
currentModule <- askModule
owningModule <- getExtNameModule extName
if currentModule == owningModule
then return Nothing
else do iface <- askInterface
let fullName = getModuleName iface owningModule
qualifiedName <- getModuleImportName owningModule
addImports $ hsQualifiedImport fullName qualifiedName
return $ Just qualifiedName
addExtNameModule :: ExtName -> String -> Generator String
addExtNameModule extName hsEntity = do
maybeImportName <- importHsModuleForExtName extName
return $ case maybeImportName of
Nothing -> hsEntity
Just importName -> concat [importName, ".", hsEntity]
toHsTypeName :: Constness -> ExtName -> Generator String
toHsTypeName cst extName =
inFunction "toHsTypeName" $
addExtNameModule extName $ toHsTypeName' cst extName
toHsTypeName' :: Constness -> ExtName -> String
toHsTypeName' cst extName =
(case cst of
Const -> (++ "Const")
Nonconst -> id) $
case fromExtName extName of
x:xs -> toUpper x:xs
[] -> []
toHsEnumTypeName :: CppEnum -> Generator String
toHsEnumTypeName enum =
inFunction "toHsEnumTypeName" $
addExtNameModule (enumExtName enum) $ toHsEnumTypeName' enum
toHsEnumTypeName' :: CppEnum -> String
toHsEnumTypeName' = toHsTypeName' Nonconst . enumExtName
toHsEnumCtorName :: CppEnum -> [String] -> Generator String
toHsEnumCtorName enum words =
inFunction "toHsEnumCtorName" $
addExtNameModule (enumExtName enum) $ toHsEnumCtorName' enum words
toHsEnumCtorName' :: CppEnum -> [String] -> String
toHsEnumCtorName' enum words =
concat $ enumValuePrefix enum : map capitalize words
toHsBitspaceTypeName :: Bitspace -> Generator String
toHsBitspaceTypeName bitspace =
inFunction "toHsBitspaceTypeName" $
addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceTypeName' bitspace
toHsBitspaceTypeName' :: Bitspace -> String
toHsBitspaceTypeName' = toHsTypeName' Nonconst . bitspaceExtName
toHsBitspaceValueName :: Bitspace -> [String] -> Generator String
toHsBitspaceValueName bitspace words =
inFunction "toHsBitspaceValueName" $
addExtNameModule (bitspaceExtName bitspace) $
toHsBitspaceValueName' bitspace words
toHsBitspaceValueName' :: Bitspace -> [String] -> String
toHsBitspaceValueName' bitspace words =
lowerFirst $ concat $ bitspaceValuePrefix bitspace : map capitalize words
toHsBitspaceToNumName :: Bitspace -> Generator String
toHsBitspaceToNumName bitspace =
inFunction "toHsBitspaceToNumName" $
addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceToNumName' bitspace
toHsBitspaceToNumName' :: Bitspace -> String
toHsBitspaceToNumName' = ("from" ++) . toHsBitspaceTypeName'
toHsBitspaceClassName :: Bitspace -> Generator String
toHsBitspaceClassName bitspace =
inFunction "toHsBitspaceClassName" $
addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceClassName' bitspace
toHsBitspaceClassName' :: Bitspace -> String
toHsBitspaceClassName' bitspace = 'I':'s':toHsBitspaceTypeName' bitspace
toHsBitspaceFromValueName :: Bitspace -> Generator String
toHsBitspaceFromValueName bitspace =
inFunction "toHsBitspaceFromValueName" $
addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceFromValueName' bitspace
toHsBitspaceFromValueName' :: Bitspace -> String
toHsBitspaceFromValueName' = ("to" ++) . toHsBitspaceTypeName'
toHsValueClassName :: Class -> Generator String
toHsValueClassName cls =
inFunction "toHsValueClassName" $
addExtNameModule (classExtName cls) $ toHsValueClassName' cls
toHsValueClassName' :: Class -> String
toHsValueClassName' cls = toHsDataTypeName' Nonconst cls ++ "Value"
toHsWithValuePtrName :: Class -> Generator String
toHsWithValuePtrName cls =
inFunction "toHsWithValuePtrName" $
addExtNameModule (classExtName cls) $ toHsWithValuePtrName' cls
toHsWithValuePtrName' :: Class -> String
toHsWithValuePtrName' cls = concat ["with", toHsDataTypeName' Nonconst cls, "Ptr"]
toHsPtrClassName :: Constness -> Class -> Generator String
toHsPtrClassName cst cls =
inFunction "toHsPtrClassName" $
addExtNameModule (classExtName cls) $ toHsPtrClassName' cst cls
toHsPtrClassName' :: Constness -> Class -> String
toHsPtrClassName' cst cls = toHsDataTypeName' cst cls ++ "Ptr"
toHsCastMethodName :: Constness -> Class -> Generator String
toHsCastMethodName cst cls =
inFunction "toHsCastMethodName" $
addExtNameModule (classExtName cls) $ toHsCastMethodName' cst cls
toHsCastMethodName' :: Constness -> Class -> String
toHsCastMethodName' cst cls = "to" ++ toHsDataTypeName' cst cls
toHsDownCastClassName :: Constness -> Class -> Generator String
toHsDownCastClassName cst cls =
inFunction "toHsDownCastClassName" $
addExtNameModule (classExtName cls) $ toHsDownCastClassName' cst cls
toHsDownCastClassName' :: Constness -> Class -> String
toHsDownCastClassName' cst cls =
concat [toHsDataTypeName' Nonconst cls,
"Super",
case cst of
Const -> "Const"
Nonconst -> ""]
toHsDownCastMethodName :: Constness -> Class -> Generator String
toHsDownCastMethodName cst cls =
inFunction "toHsDownCastMethodName" $
addExtNameModule (classExtName cls) $ toHsDownCastMethodName' cst cls
toHsDownCastMethodName' :: Constness -> Class -> String
toHsDownCastMethodName' cst cls = "downTo" ++ toHsDataTypeName' cst cls
toHsCastPrimitiveName :: Class -> Class -> Class -> Generator String
toHsCastPrimitiveName descendentClass from to =
inFunction "toHsCastPrimitiveName" $
addExtNameModule (classExtName descendentClass) $ toHsCastPrimitiveName' from to
toHsCastPrimitiveName' :: Class -> Class -> String
toHsCastPrimitiveName' from to =
concat ["cast", toHsDataTypeName' Nonconst from, "To", toHsDataTypeName' Nonconst to]
toHsConstCastFnName :: Constness -> Class -> Generator String
toHsConstCastFnName cst cls =
inFunction "toHsConstCastFnName" $
addExtNameModule (classExtName cls) $ toHsConstCastFnName' cst cls
toHsConstCastFnName' :: Constness -> Class -> String
toHsConstCastFnName' cst cls =
concat ["cast", toHsDataTypeName' Nonconst cls,
case cst of
Const -> "ToConst"
Nonconst -> "ToNonconst"]
toHsDataTypeName :: Constness -> Class -> Generator String
toHsDataTypeName cst cls =
inFunction "toHsDataTypeName" $
addExtNameModule (classExtName cls) $ toHsDataTypeName' cst cls
toHsDataTypeName' :: Constness -> Class -> String
toHsDataTypeName' cst cls = toHsTypeName' cst $ classExtName cls
toHsDataCtorName :: Managed -> Constness -> Class -> Generator String
toHsDataCtorName m cst cls =
inFunction "toHsDataCtorName" $
addExtNameModule (classExtName cls) $ toHsDataCtorName' m cst cls
toHsDataCtorName' :: Managed -> Constness -> Class -> String
toHsDataCtorName' m cst cls = case m of
Unmanaged -> base
Managed -> base ++ "Gc"
where base = toHsDataTypeName' cst cls
toHsClassDeleteFnName' :: Class -> String
toHsClassDeleteFnName' cls = 'd':'e':'l':'e':'t':'e':'\'':toHsDataTypeName' Nonconst cls
toHsClassDeleteFnPtrName' :: Class -> String
toHsClassDeleteFnPtrName' cls =
'd':'e':'l':'e':'t':'e':'P':'t':'r':'\'':toHsDataTypeName' Nonconst cls
toHsCtorName :: Class -> Ctor -> Generator String
toHsCtorName cls ctor =
inFunction "toHsCtorName" $
toHsClassEntityName cls $ fromExtName $ ctorExtName ctor
toHsCtorName' :: Class -> Ctor -> String
toHsCtorName' cls ctor =
toHsClassEntityName' cls $ fromExtName $ ctorExtName ctor
toHsMethodName :: Class -> Method -> Generator String
toHsMethodName cls method =
inFunction "toHsMethodName" $
toHsClassEntityName cls $ fromExtName $ methodExtName method
toHsMethodName' :: Class -> Method -> String
toHsMethodName' cls method =
toHsClassEntityName' cls $ fromExtName $ methodExtName method
toHsClassEntityName :: IsFnName String name => Class -> name -> Generator String
toHsClassEntityName cls name =
addExtNameModule (classExtName cls) $ toHsClassEntityName' cls name
toHsClassEntityName' :: IsFnName String name => Class -> name -> String
toHsClassEntityName' cls name =
lowerFirst $ fromExtName $
classEntityForeignName' cls $
case toFnName name of
FnName name -> toExtName name
FnOp op -> operatorPreferredExtName op
toHsCallbackCtorName :: Callback -> Generator String
toHsCallbackCtorName callback =
inFunction "toHsCallbackCtorName" $
addExtNameModule (callbackExtName callback) $ toHsCallbackCtorName' callback
toHsCallbackCtorName' :: Callback -> String
toHsCallbackCtorName' callback =
toHsFnName' $ toExtName $ fromExtName (callbackExtName callback) ++ "_new"
toHsCallbackNewFunPtrFnName :: Callback -> Generator String
toHsCallbackNewFunPtrFnName callback =
inFunction "toHsCallbackNewFunPtrFnName" $
addExtNameModule (callbackExtName callback) $ toHsCallbackNewFunPtrFnName' callback
toHsCallbackNewFunPtrFnName' :: Callback -> String
toHsCallbackNewFunPtrFnName' callback =
toHsFnName' $ toExtName $ fromExtName (callbackExtName callback) ++ "_newFunPtr"
toHsFnName :: ExtName -> Generator String
toHsFnName extName =
inFunction "toHsFnName" $
addExtNameModule extName $ toHsFnName' extName
toHsFnName' :: ExtName -> String
toHsFnName' = lowerFirst . fromExtName
toArgName :: Int -> String
toArgName = ("arg'" ++) . show
data HsTypeSide =
HsCSide
| HsHsSide
deriving (Eq, Show)
cppTypeToHsTypeAndUse :: HsTypeSide -> Type -> Generator HsType
cppTypeToHsTypeAndUse side t =
withErrorContext (concat ["converting ", show t, " to ", show side, " type"]) $
case t of
Internal_TVoid -> return $ HsTyCon $ Special HsUnitCon
Internal_TBool -> case side of
HsCSide -> addImports hsImportForRuntime $> HsTyCon (UnQual $ HsIdent "HoppyFHR.CBool")
HsHsSide -> addImports hsImportForPrelude $> HsTyCon (UnQual $ HsIdent "HoppyP.Bool")
Internal_TChar -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CChar")
Internal_TUChar -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CUChar")
Internal_TShort -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CShort")
Internal_TUShort ->
addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CUShort")
Internal_TInt -> case side of
HsCSide -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CInt")
HsHsSide -> addImports hsImportForPrelude $> HsTyCon (UnQual $ HsIdent "HoppyP.Int")
Internal_TUInt -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CUInt")
Internal_TLong -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CLong")
Internal_TULong -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CULong")
Internal_TLLong -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CLLong")
Internal_TULLong ->
addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CULLong")
Internal_TFloat -> case side of
HsCSide -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CFloat")
HsHsSide -> addImports hsImportForPrelude $> HsTyCon (UnQual $ HsIdent "HoppyP.Float")
Internal_TDouble -> case side of
HsCSide -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CDouble")
HsHsSide -> addImports hsImportForPrelude $> HsTyCon (UnQual $ HsIdent "HoppyP.Double")
Internal_TInt8 -> addImports hsImportForInt $> HsTyCon (UnQual $ HsIdent "HoppyDI.Int8")
Internal_TInt16 -> addImports hsImportForInt $> HsTyCon (UnQual $ HsIdent "HoppyDI.Int16")
Internal_TInt32 -> addImports hsImportForInt $> HsTyCon (UnQual $ HsIdent "HoppyDI.Int32")
Internal_TInt64 -> addImports hsImportForInt $> HsTyCon (UnQual $ HsIdent "HoppyDI.Int64")
Internal_TWord8 -> addImports hsImportForWord $> HsTyCon (UnQual $ HsIdent "HoppyDW.Word8")
Internal_TWord16 -> addImports hsImportForWord $> HsTyCon (UnQual $ HsIdent "HoppyDW.Word16")
Internal_TWord32 -> addImports hsImportForWord $> HsTyCon (UnQual $ HsIdent "HoppyDW.Word32")
Internal_TWord64 -> addImports hsImportForWord $> HsTyCon (UnQual $ HsIdent "HoppyDW.Word64")
Internal_TPtrdiff ->
addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CPtrdiff")
Internal_TSize -> addImports hsImportForForeignC $> HsTyCon (UnQual $ HsIdent "HoppyFC.CSize")
Internal_TSSize ->
addImports hsImportForSystemPosixTypes $> HsTyCon (UnQual $ HsIdent "HoppySPT.CSsize")
Internal_TEnum e -> HsTyCon . UnQual . HsIdent <$> case side of
HsCSide -> addImports hsImportForForeignC $> "HoppyFC.CInt"
HsHsSide -> toHsEnumTypeName e
Internal_TBitspace b -> case side of
HsCSide -> cppTypeToHsTypeAndUse side $ bitspaceType b
HsHsSide -> do
typeName <- toHsBitspaceTypeName b
return $ HsTyCon $ UnQual $ HsIdent typeName
Internal_TPtr (Internal_TObj cls) -> do
typeName <- toHsTypeName Nonconst $ classExtName cls
let dataType = HsTyCon $ UnQual $ HsIdent typeName
case side of
HsCSide -> do
addImports hsImportForForeign
return $ HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.Ptr") dataType
HsHsSide -> return dataType
Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> do
typeName <- toHsTypeName Const $ classExtName cls
let dataType = HsTyCon $ UnQual $ HsIdent typeName
case side of
HsCSide -> do
addImports hsImportForForeign
return $ HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.Ptr") dataType
HsHsSide -> return dataType
Internal_TPtr fn@(Internal_TFn {}) -> do
addImports hsImportForForeign
HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") <$> cppTypeToHsTypeAndUse HsCSide fn
Internal_TPtr t' -> do
addImports hsImportForForeign
HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.Ptr") <$> cppTypeToHsTypeAndUse HsCSide t'
Internal_TRef t' -> cppTypeToHsTypeAndUse side $ ptrT t'
Internal_TFn paramTypes retType -> do
paramHsTypes <- mapM (cppTypeToHsTypeAndUse side) paramTypes
retHsType <- cppTypeToHsTypeAndUse side retType
addImports hsImportForPrelude
return $
foldr HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") retHsType) paramHsTypes
Internal_TCallback cb -> do
hsType <- cppTypeToHsTypeAndUse side =<< callbackToTFn side cb
case side of
HsHsSide -> return hsType
HsCSide -> do
addImports hsImportForRuntime
return $ HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyFHR.CCallback") hsType
Internal_TObj cls -> case side of
HsCSide -> cppTypeToHsTypeAndUse side $ ptrT $ constT t
HsHsSide -> case classHaskellConversionType $ getClassHaskellConversion cls of
Just typeGen -> typeGen
Nothing ->
throwError $ concat
["Expected a Haskell type for ", show cls, " but there isn't one"]
Internal_TObjToHeap cls -> cppTypeToHsTypeAndUse side $ ptrT $ objT cls
Internal_TToGc t' -> case t' of
Internal_TRef _ -> cppTypeToHsTypeAndUse side t'
Internal_TPtr _ -> cppTypeToHsTypeAndUse side t'
Internal_TObj cls -> cppTypeToHsTypeAndUse side $ ptrT $ objT cls
_ -> throwError $ tToGcInvalidFormErrorMessage Nothing t'
Internal_TConst t' -> cppTypeToHsTypeAndUse side t'
getClassHaskellConversion :: Class -> ClassHaskellConversion
getClassHaskellConversion = classHaskellConversion . classConversion
callbackToTFn :: HsTypeSide -> Callback -> Generator Type
callbackToTFn side cb = do
needsExcParams <- case side of
HsCSide -> mayThrow
HsHsSide -> return False
return $ Internal_TFn ((if needsExcParams then addExcParams else id) $ callbackParams cb)
(callbackReturn cb)
where mayThrow = case callbackThrows cb of
Just t -> return t
Nothing -> moduleCallbacksThrow <$> askModule >>= \mt -> case mt of
Just t -> return t
Nothing -> interfaceCallbacksThrow <$> askInterface
addExcParams = (++ [ptrT intT, ptrT $ ptrT voidT])
prettyPrint :: P.Pretty a => a -> String
prettyPrint = collapseSpaces . filter (/= '\n') . P.prettyPrint
where collapseSpaces (' ':xs) = ' ' : collapseSpaces (dropWhile (== ' ') xs)
collapseSpaces (x:xs) = x : collapseSpaces xs
collapseSpaces [] = []