packages feed

hoppy-generator 0.2.1 → 0.3.0

raw patch · 11 files changed

+4976/−3400 lines, 11 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Foreign.Hoppy.Generator.Language.Haskell: importHsModuleForExtName :: ExtName -> Generator ()
- Foreign.Hoppy.Generator.Language.Haskell: toHsClassDeleteFnName :: Class -> String
- Foreign.Hoppy.Generator.Language.Haskell: toHsClassDeleteFnPtrName :: Class -> String
- Foreign.Hoppy.Generator.Spec: ClassConversionManual :: a -> ClassConversionMode a
- Foreign.Hoppy.Generator.Spec: ClassConversionNone :: ClassConversionMode a
- Foreign.Hoppy.Generator.Spec: ClassConversionToGc :: ClassConversionMode a
- Foreign.Hoppy.Generator.Spec: ClassConversionToHeap :: ClassConversionMode a
- Foreign.Hoppy.Generator.Spec: callbackToTFn :: Callback -> Type
- Foreign.Hoppy.Generator.Spec: class HasClassyExtName a where getClassyExtName cls x = toExtName $ concat [fromExtName $ classExtName cls, "_", fromExtName $ getClassyExtNameSuffix x]
- Foreign.Hoppy.Generator.Spec: classAddCtors :: [Ctor] -> Class -> Class
- Foreign.Hoppy.Generator.Spec: classAddMethods :: [Method] -> Class -> Class
- Foreign.Hoppy.Generator.Spec: data ClassConversionMode a
- Foreign.Hoppy.Generator.Spec: exportExtName :: Export -> ExtName
- Foreign.Hoppy.Generator.Spec: getClassyExtName :: HasClassyExtName a => Class -> a -> ExtName
- Foreign.Hoppy.Generator.Spec: getClassyExtNameSuffix :: HasClassyExtName a => a -> ExtName
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasAddendum Foreign.Hoppy.Generator.Spec.Bitspace
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasAddendum Foreign.Hoppy.Generator.Spec.Callback
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasAddendum Foreign.Hoppy.Generator.Spec.Class
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasAddendum Foreign.Hoppy.Generator.Spec.CppEnum
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasAddendum Foreign.Hoppy.Generator.Spec.Function
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasAddendum Foreign.Hoppy.Generator.Spec.Variable
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasClassyExtName Foreign.Hoppy.Generator.Spec.Ctor
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasClassyExtName Foreign.Hoppy.Generator.Spec.Method
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.Bitspace
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.Callback
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.Class
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.CppEnum
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.Function
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.Module
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.HasReqs Foreign.Hoppy.Generator.Spec.Variable
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.IsFnName t (Foreign.Hoppy.Generator.Spec.FnName t)
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.IsFnName t Foreign.Hoppy.Generator.Spec.Operator
- Foreign.Hoppy.Generator.Spec: instance Foreign.Hoppy.Generator.Spec.IsFnName t t
- Foreign.Hoppy.Generator.Spec: instance GHC.Base.Monoid Foreign.Hoppy.Generator.Spec.Addendum
- Foreign.Hoppy.Generator.Spec: instance GHC.Base.Monoid Foreign.Hoppy.Generator.Spec.HsImportSet
- Foreign.Hoppy.Generator.Spec: instance GHC.Base.Monoid Foreign.Hoppy.Generator.Spec.Reqs
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Bitspace
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Callback
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Class
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Constness
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.CppEnum
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.ExtName
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.HsImportKey
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.IdPart
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Identifier
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Include
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.MethodApplicability
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.MethodImpl
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Module
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Operator
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Purity
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Staticness
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Type
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Spec.Variable
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Eq name => GHC.Classes.Eq (Foreign.Hoppy.Generator.Spec.FnName name)
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Ord Foreign.Hoppy.Generator.Spec.ExtName
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Ord Foreign.Hoppy.Generator.Spec.HsImportKey
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Ord Foreign.Hoppy.Generator.Spec.Include
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Ord Foreign.Hoppy.Generator.Spec.Module
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Ord Foreign.Hoppy.Generator.Spec.Operator
- Foreign.Hoppy.Generator.Spec: instance GHC.Classes.Ord name => GHC.Classes.Ord (Foreign.Hoppy.Generator.Spec.FnName name)
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Bounded Foreign.Hoppy.Generator.Spec.Constness
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Bounded Foreign.Hoppy.Generator.Spec.MethodApplicability
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Bounded Foreign.Hoppy.Generator.Spec.Operator
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Bounded Foreign.Hoppy.Generator.Spec.Staticness
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Enum Foreign.Hoppy.Generator.Spec.Constness
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Enum Foreign.Hoppy.Generator.Spec.MethodApplicability
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Enum Foreign.Hoppy.Generator.Spec.Operator
- Foreign.Hoppy.Generator.Spec: instance GHC.Enum.Enum Foreign.Hoppy.Generator.Spec.Staticness
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Bitspace
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Callback
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Class
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Constness
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.CppEnum
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Ctor
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Export
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.ExtName
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Function
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.HsImportKey
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.HsImportSet
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.HsImportSpecs
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.HsImportVal
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.IdPart
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Identifier
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Include
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Interface
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Method
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.MethodApplicability
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.MethodImpl
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Module
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Operator
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Purity
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Reqs
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Staticness
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Type
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Variable
- Foreign.Hoppy.Generator.Spec: instance GHC.Show.Show name => GHC.Show.Show (Foreign.Hoppy.Generator.Spec.FnName name)
- Foreign.Hoppy.Generator.Spec: mkProps :: [[Method]] -> [Method]
- Foreign.Hoppy.Generator.Spec: stringOrIdentifier :: Identifier -> Maybe String -> String
+ Foreign.Hoppy.Generator.Language.Cpp: exceptionIdArgName :: String
+ Foreign.Hoppy.Generator.Language.Cpp: exceptionPtrArgName :: String
+ Foreign.Hoppy.Generator.Language.Cpp: exceptionRethrowFnName :: String
+ Foreign.Hoppy.Generator.Language.Cpp: exceptionVarName :: String
+ Foreign.Hoppy.Generator.Language.Haskell: [outputExtensions] :: Output -> Set String
+ Foreign.Hoppy.Generator.Language.Haskell: addExtension :: String -> Generator ()
+ Foreign.Hoppy.Generator.Language.Haskell: askInterface :: Generator Interface
+ Foreign.Hoppy.Generator.Language.Haskell: askModule :: Generator Module
+ Foreign.Hoppy.Generator.Language.Haskell: askModuleName :: Generator String
+ Foreign.Hoppy.Generator.Language.Haskell: callbackToTFn :: HsTypeSide -> Callback -> Generator Type
+ Foreign.Hoppy.Generator.Language.Haskell: getModuleForExtName :: ExtName -> Generator Module
+ Foreign.Hoppy.Generator.Language.Haskell: indentSpaces :: Int -> Generator a -> Generator a
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceClassName' :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceFromValueName' :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceToNumName' :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceTypeName' :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceValueName' :: Bitspace -> [String] -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCallbackCtorName' :: Callback -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCallbackNewFunPtrFnName :: Callback -> Generator String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCallbackNewFunPtrFnName' :: Callback -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCastMethodName' :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCastPrimitiveName' :: Class -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsClassDeleteFnName' :: Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsClassDeleteFnPtrName' :: Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsClassEntityName :: IsFnName String name => Class -> name -> Generator String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsClassEntityName' :: IsFnName String name => Class -> name -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsConstCastFnName' :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCtorName :: Class -> Ctor -> Generator String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCtorName' :: Class -> Ctor -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDataCtorName' :: Managed -> Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDataTypeName' :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDownCastClassName' :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDownCastMethodName' :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsEnumCtorName' :: CppEnum -> [String] -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsEnumTypeName' :: CppEnum -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsFnName' :: ExtName -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsPtrClassName' :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsValueClassName' :: Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsWithValuePtrName' :: Class -> String
+ Foreign.Hoppy.Generator.Spec: CECtor :: Ctor -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: CEMethod :: Method -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: CEProp :: Prop -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: CEVar :: ClassVariable -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: CatchAll :: ExceptionHandler
+ Foreign.Hoppy.Generator.Spec: CatchClass :: Class -> ExceptionHandler
+ Foreign.Hoppy.Generator.Spec: ExceptionHandlers :: [ExceptionHandler] -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: ExceptionId :: Int -> ExceptionId
+ Foreign.Hoppy.Generator.Spec: InterfaceOptions :: ExceptionHandlers -> InterfaceOptions
+ Foreign.Hoppy.Generator.Spec: [exceptionHandlersList] :: ExceptionHandlers -> [ExceptionHandler]
+ Foreign.Hoppy.Generator.Spec: [getExceptionId] :: ExceptionId -> Int
+ Foreign.Hoppy.Generator.Spec: [interfaceOptionsExceptionHandlers] :: InterfaceOptions -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: bitspaceSetValuePrefix :: String -> Bitspace -> Bitspace
+ Foreign.Hoppy.Generator.Spec: bitspaceValuePrefix :: Bitspace -> String
+ Foreign.Hoppy.Generator.Spec: callbackSetThrows :: Bool -> Callback -> Callback
+ Foreign.Hoppy.Generator.Spec: callbackThrows :: Callback -> Maybe Bool
+ Foreign.Hoppy.Generator.Spec: class HandlesExceptions a
+ Foreign.Hoppy.Generator.Spec: class HasExtNames a where getNestedExtNames _ = []
+ Foreign.Hoppy.Generator.Spec: class IsClassEntity a
+ Foreign.Hoppy.Generator.Spec: classAddEntities :: [ClassEntity] -> Class -> Class
+ Foreign.Hoppy.Generator.Spec: classEntities :: Class -> [ClassEntity]
+ Foreign.Hoppy.Generator.Spec: classEntityExtName :: IsClassEntity a => Class -> a -> ExtName
+ Foreign.Hoppy.Generator.Spec: classEntityExtNameSuffix :: IsClassEntity a => a -> ExtName
+ Foreign.Hoppy.Generator.Spec: classEntityForeignName :: IsClassEntity a => Class -> a -> ExtName
+ Foreign.Hoppy.Generator.Spec: classEntityForeignName' :: Class -> ExtName -> ExtName
+ Foreign.Hoppy.Generator.Spec: classEntityPrefix :: Class -> String
+ Foreign.Hoppy.Generator.Spec: classFindCopyCtor :: Class -> Maybe Ctor
+ Foreign.Hoppy.Generator.Spec: classHaskellConversionNone :: ClassHaskellConversion
+ Foreign.Hoppy.Generator.Spec: classIsException :: Class -> Bool
+ Foreign.Hoppy.Generator.Spec: classMakeException :: Class -> Class
+ Foreign.Hoppy.Generator.Spec: classSetEntityPrefix :: String -> Class -> Class
+ Foreign.Hoppy.Generator.Spec: classVarCName :: ClassVariable -> String
+ Foreign.Hoppy.Generator.Spec: classVarExtName :: ClassVariable -> ExtName
+ Foreign.Hoppy.Generator.Spec: classVarGettable :: ClassVariable -> Bool
+ Foreign.Hoppy.Generator.Spec: classVarGetterExtName :: Class -> ClassVariable -> ExtName
+ Foreign.Hoppy.Generator.Spec: classVarGetterForeignName :: Class -> ClassVariable -> ExtName
+ Foreign.Hoppy.Generator.Spec: classVarSetterExtName :: Class -> ClassVariable -> ExtName
+ Foreign.Hoppy.Generator.Spec: classVarSetterForeignName :: Class -> ClassVariable -> ExtName
+ Foreign.Hoppy.Generator.Spec: classVarStatic :: ClassVariable -> Staticness
+ Foreign.Hoppy.Generator.Spec: classVarType :: ClassVariable -> Type
+ Foreign.Hoppy.Generator.Spec: classVariables :: Class -> [ClassVariable]
+ Foreign.Hoppy.Generator.Spec: ctorExceptionHandlers :: Ctor -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: data ClassEntity
+ Foreign.Hoppy.Generator.Spec: data ClassVariable
+ Foreign.Hoppy.Generator.Spec: data ExceptionHandler
+ Foreign.Hoppy.Generator.Spec: data ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: data InterfaceOptions
+ Foreign.Hoppy.Generator.Spec: data Prop
+ Foreign.Hoppy.Generator.Spec: defaultInterfaceOptions :: InterfaceOptions
+ Foreign.Hoppy.Generator.Spec: enumSetValuePrefix :: String -> CppEnum -> CppEnum
+ Foreign.Hoppy.Generator.Spec: enumValuePrefix :: CppEnum -> String
+ Foreign.Hoppy.Generator.Spec: exceptionCatchAllId :: ExceptionId
+ Foreign.Hoppy.Generator.Spec: fnExceptionHandlers :: Function -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: getAddendum :: HasAddendum a => a -> Addendum
+ Foreign.Hoppy.Generator.Spec: getAllExtNames :: HasExtNames a => a -> [ExtName]
+ Foreign.Hoppy.Generator.Spec: getExceptionHandlers :: HandlesExceptions a => a -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: getNestedExtNames :: HasExtNames a => a -> [ExtName]
+ Foreign.Hoppy.Generator.Spec: getPrimaryExtName :: HasExtNames a => a -> ExtName
+ Foreign.Hoppy.Generator.Spec: handleExceptions :: HandlesExceptions a => [ExceptionHandler] -> a -> a
+ Foreign.Hoppy.Generator.Spec: hsImportForException :: HsImportSet
+ Foreign.Hoppy.Generator.Spec: hsImportForMap :: HsImportSet
+ Foreign.Hoppy.Generator.Spec: hsImportForTypeable :: HsImportSet
+ Foreign.Hoppy.Generator.Spec: interface' :: String -> [Module] -> InterfaceOptions -> Either ErrorMsg Interface
+ Foreign.Hoppy.Generator.Spec: interfaceAllExceptionClasses :: Interface -> [Class]
+ Foreign.Hoppy.Generator.Spec: interfaceCallbacksThrow :: Interface -> Bool
+ Foreign.Hoppy.Generator.Spec: interfaceExceptionClassId :: Interface -> Class -> Maybe ExceptionId
+ Foreign.Hoppy.Generator.Spec: interfaceExceptionHandlers :: Interface -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: interfaceExceptionSupportModule :: Interface -> Maybe Module
+ Foreign.Hoppy.Generator.Spec: interfaceHaskellModuleImportNames :: Interface -> Map Module String
+ Foreign.Hoppy.Generator.Spec: interfaceSetCallbacksThrow :: Bool -> Interface -> Interface
+ Foreign.Hoppy.Generator.Spec: interfaceSetExceptionSupportModule :: Module -> Interface -> Interface
+ Foreign.Hoppy.Generator.Spec: isValidExtName :: String -> Bool
+ Foreign.Hoppy.Generator.Spec: makeClassVariable :: String -> Maybe ExtName -> Type -> Staticness -> Bool -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: makeClassVariable_ :: String -> Maybe ExtName -> Type -> Staticness -> Bool -> ClassVariable
+ Foreign.Hoppy.Generator.Spec: makeCtor_ :: ExtName -> [Type] -> Ctor
+ Foreign.Hoppy.Generator.Spec: makeFnMethod_ :: IsFnName Identifier name => name -> String -> MethodApplicability -> Purity -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: makeMethod_ :: IsFnName String name => name -> ExtName -> MethodApplicability -> Purity -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: methodExceptionHandlers :: Method -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: mkBoolHasProp_ :: String -> Prop
+ Foreign.Hoppy.Generator.Spec: mkBoolIsProp_ :: String -> Prop
+ Foreign.Hoppy.Generator.Spec: mkClassVariable :: String -> Type -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: mkClassVariable_ :: String -> Type -> ClassVariable
+ Foreign.Hoppy.Generator.Spec: mkConstMethod'_ :: IsFnName String name => name -> String -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkConstMethod_ :: IsFnName String name => name -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkCtor_ :: String -> [Type] -> Ctor
+ Foreign.Hoppy.Generator.Spec: mkMethod'_ :: IsFnName String name => name -> String -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkMethod_ :: IsFnName String name => name -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkProp_ :: String -> Type -> Prop
+ Foreign.Hoppy.Generator.Spec: mkStaticClassVariable :: String -> Type -> ClassEntity
+ Foreign.Hoppy.Generator.Spec: mkStaticClassVariable_ :: String -> Type -> ClassVariable
+ Foreign.Hoppy.Generator.Spec: mkStaticMethod'_ :: IsFnName String name => name -> String -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkStaticMethod_ :: IsFnName String name => name -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkStaticProp_ :: String -> Type -> Prop
+ Foreign.Hoppy.Generator.Spec: modifyAddendum :: HasAddendum a => (Addendum -> Addendum) -> a -> a
+ Foreign.Hoppy.Generator.Spec: moduleAddendum :: Module -> Addendum
+ Foreign.Hoppy.Generator.Spec: moduleCallbacksThrow :: Module -> Maybe Bool
+ Foreign.Hoppy.Generator.Spec: moduleExceptionHandlers :: Module -> ExceptionHandlers
+ Foreign.Hoppy.Generator.Spec: moduleSetCallbacksThrow :: MonadState Module m => Maybe Bool -> m ()
+ Foreign.Hoppy.Generator.Spec: newtype ExceptionId
+ Foreign.Hoppy.Generator.Spec: setAddendum :: HasAddendum a => Addendum -> a -> a
- Foreign.Hoppy.Generator.Language.Haskell: Output :: [HsExport] -> HsImportSet -> [String] -> Output
+ Foreign.Hoppy.Generator.Language.Haskell: Output :: [HsExport] -> HsImportSet -> [String] -> Set String -> Output
- Foreign.Hoppy.Generator.Language.Haskell: evalGenerator :: Interface -> String -> Generator a -> Either ErrorMsg a
+ Foreign.Hoppy.Generator.Language.Haskell: evalGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg a
- Foreign.Hoppy.Generator.Language.Haskell: execGenerator :: Interface -> String -> Generator a -> Either ErrorMsg Partial
+ Foreign.Hoppy.Generator.Language.Haskell: execGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg Partial
- Foreign.Hoppy.Generator.Language.Haskell: getClassHaskellConversion :: Class -> Maybe ClassHaskellConversion
+ Foreign.Hoppy.Generator.Language.Haskell: getClassHaskellConversion :: Class -> ClassHaskellConversion
- Foreign.Hoppy.Generator.Language.Haskell: runGenerator :: Interface -> String -> Generator a -> Either ErrorMsg (Partial, a)
+ Foreign.Hoppy.Generator.Language.Haskell: runGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg (Partial, a)
- Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceClassName :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceClassName :: Bitspace -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceFromValueName :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceFromValueName :: Bitspace -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceToNumName :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceToNumName :: Bitspace -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceTypeName :: Bitspace -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceTypeName :: Bitspace -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceValueName :: Bitspace -> [String] -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsBitspaceValueName :: Bitspace -> [String] -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsCallbackCtorName :: Callback -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCallbackCtorName :: Callback -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsCastMethodName :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCastMethodName :: Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsCastPrimitiveName :: Class -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsCastPrimitiveName :: Class -> Class -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsConstCastFnName :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsConstCastFnName :: Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsDataCtorName :: Managed -> Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDataCtorName :: Managed -> Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsDataTypeName :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDataTypeName :: Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsDownCastClassName :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDownCastClassName :: Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsDownCastMethodName :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsDownCastMethodName :: Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsEnumCtorName :: CppEnum -> [String] -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsEnumCtorName :: CppEnum -> [String] -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsEnumTypeName :: CppEnum -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsEnumTypeName :: CppEnum -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsFnName :: ExtName -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsFnName :: ExtName -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsMethodName :: Class -> Method -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsMethodName :: Class -> Method -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsMethodName' :: IsFnName String name => Class -> name -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsMethodName' :: Class -> Method -> String
- Foreign.Hoppy.Generator.Language.Haskell: toHsPtrClassName :: Constness -> Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsPtrClassName :: Constness -> Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsValueClassName :: Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsValueClassName :: Class -> Generator String
- Foreign.Hoppy.Generator.Language.Haskell: toHsWithValuePtrName :: Class -> String
+ Foreign.Hoppy.Generator.Language.Haskell: toHsWithValuePtrName :: Class -> Generator String
- Foreign.Hoppy.Generator.Spec: ClassConversion :: ClassConversionMode ClassHaskellConversion -> ClassConversion
+ Foreign.Hoppy.Generator.Spec: ClassConversion :: ClassHaskellConversion -> ClassConversion
- Foreign.Hoppy.Generator.Spec: ClassHaskellConversion :: Generator HsType -> Generator () -> Generator () -> ClassHaskellConversion
+ Foreign.Hoppy.Generator.Spec: ClassHaskellConversion :: Maybe (Generator HsType) -> Maybe (Generator ()) -> Maybe (Generator ()) -> ClassHaskellConversion
- Foreign.Hoppy.Generator.Spec: [classHaskellConversionFromCppFn] :: ClassHaskellConversion -> Generator ()
+ Foreign.Hoppy.Generator.Spec: [classHaskellConversionFromCppFn] :: ClassHaskellConversion -> Maybe (Generator ())
- Foreign.Hoppy.Generator.Spec: [classHaskellConversionToCppFn] :: ClassHaskellConversion -> Generator ()
+ Foreign.Hoppy.Generator.Spec: [classHaskellConversionToCppFn] :: ClassHaskellConversion -> Maybe (Generator ())
- Foreign.Hoppy.Generator.Spec: [classHaskellConversionType] :: ClassHaskellConversion -> Generator HsType
+ Foreign.Hoppy.Generator.Spec: [classHaskellConversionType] :: ClassHaskellConversion -> Maybe (Generator HsType)
- Foreign.Hoppy.Generator.Spec: [classHaskellConversion] :: ClassConversion -> ClassConversionMode ClassHaskellConversion
+ Foreign.Hoppy.Generator.Spec: [classHaskellConversion] :: ClassConversion -> ClassHaskellConversion
- Foreign.Hoppy.Generator.Spec: makeClass :: Identifier -> Maybe ExtName -> [Class] -> [Ctor] -> [Method] -> Class
+ Foreign.Hoppy.Generator.Spec: makeClass :: Identifier -> Maybe ExtName -> [Class] -> [ClassEntity] -> Class
- Foreign.Hoppy.Generator.Spec: makeCtor :: ExtName -> [Type] -> Ctor
+ Foreign.Hoppy.Generator.Spec: makeCtor :: ExtName -> [Type] -> ClassEntity
- Foreign.Hoppy.Generator.Spec: makeFnMethod :: IsFnName Identifier name => name -> String -> MethodApplicability -> Purity -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: makeFnMethod :: IsFnName Identifier name => name -> String -> MethodApplicability -> Purity -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: makeMethod :: IsFnName String name => name -> ExtName -> MethodApplicability -> Purity -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: makeMethod :: IsFnName String name => name -> ExtName -> MethodApplicability -> Purity -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkBoolHasProp :: String -> [Method]
+ Foreign.Hoppy.Generator.Spec: mkBoolHasProp :: String -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkBoolIsProp :: String -> [Method]
+ Foreign.Hoppy.Generator.Spec: mkBoolIsProp :: String -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkConstMethod :: IsFnName String name => name -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkConstMethod :: IsFnName String name => name -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkConstMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkConstMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkCtor :: String -> [Type] -> Ctor
+ Foreign.Hoppy.Generator.Spec: mkCtor :: String -> [Type] -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkMethod :: IsFnName String name => name -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkMethod :: IsFnName String name => name -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkProp :: String -> Type -> [Method]
+ Foreign.Hoppy.Generator.Spec: mkProp :: String -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkStaticMethod :: IsFnName String name => name -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkStaticMethod :: IsFnName String name => name -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkStaticMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> Method
+ Foreign.Hoppy.Generator.Spec: mkStaticMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> ClassEntity
- Foreign.Hoppy.Generator.Spec: mkStaticProp :: String -> Type -> [Method]
+ Foreign.Hoppy.Generator.Spec: mkStaticProp :: String -> Type -> ClassEntity

Files

hoppy-generator.cabal view
@@ -1,5 +1,5 @@ name: hoppy-generator-version: 0.2.1+version: 0.3.0 synopsis: C++ FFI generator - Code generator homepage: http://khumba.net/projects/hoppy license: AGPL-3@@ -29,11 +29,16 @@     , Foreign.Hoppy.Generator.Common.Consume     , Foreign.Hoppy.Generator.Language.Cpp.Internal     , Foreign.Hoppy.Generator.Language.Haskell.Internal+    , Foreign.Hoppy.Generator.Spec.Base+    , Foreign.Hoppy.Generator.Spec.Conversion   default-extensions:       FlexibleContexts     , FlexibleInstances     , FunctionalDependencies+    , LambdaCase     , MultiParamTypeClasses+  other-extensions:+      GeneralizedNewtypeDeriving   build-depends:       base >=4.7 && <5     , containers >=0.5 && <0.6
src/Foreign/Hoppy/Generator/Common.hs view
@@ -22,6 +22,7 @@   fromMaybeM,   fromEitherM,   maybeFail,+  for,   listSubst,   zipWithM,   writeFileIfDifferent,@@ -51,6 +52,10 @@ -- | @maybeFail s x = maybe (fail s) x@ maybeFail :: Monad m => String -> Maybe a -> m a maybeFail = fromMaybeM . fail++-- | @for = flip map@+for :: [a] -> (a -> b) -> [b]+for = flip map  -- | @listSubst a b xs@ replaces all @x@ in @xs@ such that @x == a@ with @b@. listSubst :: Eq a => a -> a -> [a] -> [a]
src/Foreign/Hoppy/Generator/Language/Cpp.hs view
@@ -27,6 +27,10 @@   callbackFnName,   toArgName,   toArgNameAlt,+  exceptionIdArgName,+  exceptionPtrArgName,+  exceptionVarName,+  exceptionRethrowFnName,   Chunk (..),   runChunkWriter,   evalChunkWriter,@@ -45,6 +49,7 @@ import Control.Monad.Writer (MonadWriter, Writer, WriterT, runWriter, runWriterT, tell) import Data.Foldable (forM_) import Data.List (intercalate, intersperse)+import Foreign.Hoppy.Generator.Common import Foreign.Hoppy.Generator.Spec import Foreign.Hoppy.Generator.Types @@ -108,6 +113,25 @@ toArgNameAlt :: Int -> String toArgNameAlt n = "arg" ++ show n ++ "_" +-- | The C++ variable name to use for the exception ID argument in a gateway+-- function.+exceptionIdArgName :: String+exceptionIdArgName = "excId"++-- | The C++ variable name to use for the exception pointer argument in a+-- gateway function.+exceptionPtrArgName :: String+exceptionPtrArgName = "excPtr"++-- | The C++ variable name to use in a @catch@ statement in a gateway function.+exceptionVarName :: String+exceptionVarName = "exc_"++-- | The name of the C++ function that receives an exception from a foreign+-- language and throws it in C++.+exceptionRethrowFnName :: String+exceptionRethrowFnName = "genthrow"+ -- TODO Fixme, this is most likely backwards, it should be a finite set of -- non-identifier chars.  Also (maybe) share some logic with the toExtName -- requirements?@@ -155,7 +179,7 @@ combineChunks :: [Chunk] -> String combineChunks chunks =   let strs = map chunkContents chunks-  in concat $ flip map (zip ("":strs) strs) $ \(prev, cur) ->+  in concat $ for (zip ("":strs) strs) $ \(prev, cur) ->        let needsSpace =              not (null prev) && not (null cur) &&              (let a = last prev@@ -246,7 +270,7 @@       outer       say "("       sequence_ $ intersperse (say ", ") $-        flip map (zip paramTypes $ maybe (repeat Nothing) (map Just) maybeParamNames) $+        for (zip paramTypes $ maybe (repeat Nothing) (map Just) maybeParamNames) $         \(ptype, pname) ->         sayType' ptype Nothing topPrecedence $ forM_ pname say       say ")"
src/Foreign/Hoppy/Generator/Language/Cpp/Internal.hs view
@@ -32,9 +32,12 @@ import Control.Monad.Writer (WriterT, execWriterT, runWriterT, tell) import Control.Monad.Trans (lift) import Data.Foldable (forM_)+#if !MIN_VERSION_base(4,8,0)+import Data.Functor ((<$))+#endif import Data.List (intersperse) import qualified Data.Map as M-import Data.Maybe (fromMaybe, isJust)+import Data.Maybe (catMaybes, fromMaybe, isJust) #if !MIN_VERSION_base(4,8,0) import Data.Monoid (mappend, mconcat, mempty) #endif@@ -136,12 +139,20 @@   addReqsM $ moduleReqs m   mapM_ (sayExport False) $ M.elems $ moduleExports m +  iface <- askInterface+  when (interfaceExceptionSupportModule iface == Just m) $+    sayExceptionSupport False+ sayModuleSource :: Generator () sayModuleSource = do   m <- askModule   addInclude $ includeLocal $ moduleHppPath m   mapM_ (sayExport True) $ M.elems $ moduleExports m +  iface <- askInterface+  when (interfaceExceptionSupportModule iface == Just m) $+    sayExceptionSupport True+ sayExport :: Bool -> Export -> Generator () sayExport sayBody export = case export of   ExportVariable v -> when sayBody $ sayExportVariable v@@ -161,6 +172,7 @@                   Nothing                   (fnParams fn)                   (fnReturn fn)+                  (fnExceptionHandlers fn)                   sayBody    ExportClass cls -> when sayBody $ do@@ -171,11 +183,12 @@      -- Export each of the class's constructors.     forM_ (classCtors cls) $ \ctor ->-      sayExportFn (getClassyExtName cls ctor)+      sayExportFn (classEntityExtName cls ctor)                   (CallFn $ say "new" >> sayIdentifier (classIdentifier cls))                   Nothing                   (ctorParams ctor)                   clsPtr+                  (ctorExceptionHandlers ctor)                   sayBody      -- Export a delete function for the class.@@ -185,6 +198,9 @@                   (fnT [ptrT $ constT $ objT cls] voidT) $         Just $ say "delete self;\n" +    -- Export each of the class's variables.+    forM_ (classVariables cls) $ sayExportClassVariable cls+     -- Export each of the class's methods.     forM_ (classMethods cls) $ \method -> do       let nonMemberCall =@@ -193,7 +209,7 @@               RealMethod {} -> False               FnMethod {} -> True       let static = methodStatic method == Static-      sayExportFn (getClassyExtName cls method)+      sayExportFn (classEntityExtName cls method)                   (case methodImpl method of                      RealMethod name -> case name of                        FnName cName -> CallFn $ do@@ -208,6 +224,7 @@                   (if nonMemberCall then Nothing else justClsPtr)                   (methodParams method)                   (methodReturn method)+                  (methodExceptionHandlers method)                   sayBody      -- Export upcast functions for the class to its direct superclasses.@@ -243,43 +260,82 @@           forM_ (classSuperclasses ancestorCls) $ genDowncastFns cls  sayExportVariable :: Variable -> Generator ()-sayExportVariable v = do-  let (isConst, deconstType) = case varType v of+sayExportVariable v =+  sayExportVariable' (varType v)+                     Nothing+                     True+                     (varGetterExtName v)+                     (varSetterExtName v)+                     (sayIdentifier $ varIdentifier v)++sayExportClassVariable :: Class -> ClassVariable -> Generator ()+sayExportClassVariable cls v =+  sayExportVariable' (classVarType v)+                     (case classVarStatic v of+                        Nonstatic -> Just (ptrT $ constT $ objT cls, ptrT $ objT cls)+                        Static -> Nothing)+                     (classVarGettable v)+                     (classVarGetterExtName cls v)+                     (classVarSetterExtName cls v)+                     (case classVarStatic v of+                        Nonstatic -> say $ classVarCName v+                        Static -> do sayIdentifier $ classIdentifier cls+                                     says ["::", classVarCName v])++sayExportVariable' :: Type+                   -> Maybe (Type, Type)+                   -> Bool+                   -> ExtName+                   -> ExtName+                   -> Generator ()+                   -> Generator ()+sayExportVariable' t maybeThisTypes gettable getterName setterName sayVarName = do+  let (isConst, deconstType) = case t of         Internal_TConst t -> (True, t)         t -> (False, t)    -- Say a getter function.-  sayExportFn (varGetterExtName v)-              (VarRead $ varIdentifier v)-              Nothing-              []-              deconstType-              True+  when gettable $+    sayExportFn getterName+                (VarRead sayVarName)+                (fmap fst maybeThisTypes)+                []+                deconstType+                mempty+                True    -- Say a setter function.   unless isConst $-    sayExportFn (varSetterExtName v)-                (VarWrite $ varIdentifier v)-                Nothing+    sayExportFn setterName+                (VarWrite sayVarName)+                (fmap snd maybeThisTypes)                 [deconstType]                 voidT+                mempty                 True  data CallType =     CallOp Operator   | CallFn (Generator ())-  | VarRead Identifier-  | VarWrite Identifier+  | VarRead (Generator ())+  | VarWrite (Generator ())  sayExportFn :: ExtName             -> CallType             -> Maybe Type             -> [Type]             -> Type+            -> ExceptionHandlers             -> Bool             -> Generator ()-sayExportFn extName callType maybeThisType paramTypes retType sayBody = do-  let paramCount = length paramTypes+sayExportFn extName callType maybeThisType paramTypes retType exceptionHandlers sayBody = do+  handlerList <- exceptionHandlersList <$> getEffectiveExceptionHandlers exceptionHandlers+  let catches = not $ null handlerList+      addExceptionParamNames =+        if catches then (++ [exceptionIdArgName, exceptionPtrArgName]) else id+      addExceptionParamTypes = if catches then (++ [ptrT intT, ptrT $ ptrT voidT]) else id++      paramCount = length paramTypes       paramCTypeMaybes = map typeToCType paramTypes       paramCTypes = zipWith fromMaybe paramTypes paramCTypeMaybes       retCTypeMaybe = typeToCType retType@@ -289,14 +345,20 @@    sayFunction (externalNameToCpp extName)               (maybe id (const ("self":)) maybeThisType $+               addExceptionParamNames $                zipWith3 (\t ctm -> case t of                            Internal_TCallback {} -> toArgNameAlt                            _ -> if isJust ctm then toArgNameAlt else toArgName)                paramTypes paramCTypeMaybes [1..paramCount])-              (fnT (maybe id (:) maybeThisType paramCTypes) retCType) $+              (fnT (addExceptionParamTypes $ maybe id (:) maybeThisType paramCTypes)+                   retCType) $     if not sayBody     then Nothing     else Just $ do+      when catches $ do+        say "try {\n"+        says ["*", exceptionIdArgName, " = 0;\n"]+       -- Convert arguments that aren't passed in directly.       mapM_ (sayArgRead DoDecode) $ zip3 [1..] paramTypes paramCTypeMaybes @@ -326,8 +388,13 @@               say "("               sayArgNames paramCount               say ")"-            VarRead identifier -> sayIdentifier identifier-            VarWrite identifier -> sayIdentifier identifier >> says [" = ", toArgName 1]+            VarRead sayVarName -> do+              when (isJust maybeThisType) $ say "self->"+              sayVarName+            VarWrite sayVarName -> do+              when (isJust maybeThisType) $ say "self->"+              sayVarName+              says [" = ", toArgName 1]            -- Writes the call, transforming the return value if necessary.           -- These translations should be kept in sync with typeToCType.@@ -358,6 +425,39 @@        sayCallAndReturn retType retCTypeMaybe +      when catches $ do+        iface <- askInterface++        forM_ handlerList $ \handler -> do+          say "} catch ("+          case handler of+            CatchClass cls -> sayVar exceptionVarName Nothing $ refT $ constT $ objT cls+            CatchAll -> say "..."+          say ") {\n"++          exceptionId <- case handler of+            CatchClass cls -> case interfaceExceptionClassId iface cls of+              Just exceptionId -> return exceptionId+              Nothing -> abort $ concat+                         ["sayExportFn: Trying to catch non-exception class ", show cls,+                          " while generating binding for ", show extName, "."]+            CatchAll -> return exceptionCatchAllId+          says ["*", exceptionIdArgName, " = ", show $ getExceptionId exceptionId, ";\n"]++          case handler of+            CatchAll -> says ["*", exceptionPtrArgName, " = 0;\n"]+            CatchClass cls -> do+              -- Object pointers don't convert automatically to void*.+              says ["*", exceptionPtrArgName, " = reinterpret_cast<void*>(new "]+              sayType Nothing $ objT cls+              says ["(", exceptionVarName, "));\n"]++          -- For all of the types our gateway functions actually return, "return+          -- 0" is a valid statement.+          when (retType /= Internal_TVoid) $ say "return 0;\n"++        say "}\n"+   where sayReturnNew cls sayCall =           say "return new" >> sayIdentifier (classIdentifier cls) >> say "(" >>           sayCall >> say ");\n"@@ -396,6 +496,22 @@                    show cb, "."]     says [callbackClassName cb, " ", toArgName n, "(", toArgNameAlt n, ");\n"] +  t@(Internal_TPtr (Internal_TFn paramTypes retType)) -> do+    -- Assert that all types referred to in a function pointer type are all+    -- representable as C types.+    let check label t' = (label ++ " " ++ show t') <$ typeToCType t'+        mismatches = catMaybes $+                     check "return type" retType :+                     map (\paramType -> check "parameter" paramType)+                         paramTypes+    unless (null mismatches) $+      abort $ concat $+      "sayArgRead: Some types within a function pointer type use non-C types, " :+      "but only C types may be used.  The unsupported types are: " :+      intersperse "; " mismatches ++ [".  The whole function type is ", show t, "."]++    convertDefault+   Internal_TRef t -> convertObj t    Internal_TObj _ -> convertObj $ constT cppType@@ -418,17 +534,19 @@             _ -> t'       sayArgRead dir (n, cppType, typeToCType newCppType) -  -- Primitive types don't need to be encoded/decoded.  But if maybeCType is a-  -- Just, then we're expected to do some encoding/decoding, so something is-  -- wrong.-  ---  -- TODO Do we need to handle TConst?-  _ -> forM_ maybeCType $ \cType ->-    abort $ concat-    ["sayArgRead: Don't know how to ", show dir, " between C-type ", show cType,-     " and C++-type ", show cppType, "."]+  _ -> convertDefault -  where convertObj cppType' = case dir of+  where -- Primitive types don't need to be encoded/decoded.  But if maybeCType is a+        -- Just, then we're expected to do some encoding/decoding, so something is+        -- wrong.+        --+        -- TODO Do we need to handle TConst?+        convertDefault = forM_ maybeCType $ \cType ->+          abort $ concat+          ["sayArgRead: Don't know how to ", show dir, " between C-type ", show cType,+           " and C++-type ", show cppType, "."]++        convertObj cppType' = case dir of           DoDecode -> do             sayVar (toArgName n) Nothing $ refT cppType'             says [" = *", toArgNameAlt n, ";\n"]@@ -442,6 +560,8 @@  sayExportCallback :: Bool -> Callback -> Generator () sayExportCallback sayBody cb = do+  throws <- getEffectiveCallbackThrows cb+   let className = callbackClassName cb       implClassName = callbackImplClassName cb       fnName = callbackFnName cb@@ -458,7 +578,9 @@    addReqsM . mconcat =<< mapM typeReqs (retType:paramTypes) -  let fnCType = fnT paramCTypes retCType+  let fnCType = fnT ((if throws then ([ptrT intT, ptrT $ ptrT voidT] ++) else id)+                     paramCTypes)+                    retCType       fnPtrCType = ptrT fnCType    if not sayBody@@ -520,31 +642,74 @@                   fnType $ Just $ do         -- Convert arguments that aren't passed in directly.         mapM_ (sayArgRead DoEncode) $ zip3 [1..] paramTypes paramCTypeMaybes++        when throws $ do+          says ["int ", exceptionIdArgName, " = 0;\n"]+          says ["void *", exceptionPtrArgName, " = 0;\n"]++          -- Add an include for the exception support module to be able to call the+          -- C++ rethrow function.+          iface <- askInterface+          currentModule <- askModule+          case interfaceExceptionSupportModule iface of+            Just exceptionSupportModule ->+              when (exceptionSupportModule /= currentModule) $+                -- TODO Should this be includeStd?+                addReqsM $ reqInclude $ includeLocal $ moduleHppPath exceptionSupportModule+            Nothing -> abort $ "sayExportCallback: " ++ show iface +++                       " uses exceptions, so it needs an exception support " +++                       "module.  Please use interfaceSetExceptionSupportModule."+         -- Invoke the function pointer into foreign code.-        let sayCall = say "f_(" >> sayArgNames paramCount >> say ")"+        let sayCall = do+              say "f_("+              when throws $ do+                says ["&", exceptionIdArgName, ", &", exceptionPtrArgName]+                when (paramCount /= 0) $ say ", "+              sayArgNames paramCount+              say ")"++            sayExceptionCheck = when throws $ do+              says ["if (", exceptionIdArgName, " != 0) { ",+                    exceptionRethrowFnName, "(", exceptionIdArgName, ", ",+                    exceptionPtrArgName, "); }\n"]+         case (retType, retCTypeMaybe) of-          (Internal_TVoid, Nothing) -> sayCall >> say ";\n"-          (_, Nothing) -> say "return " >> sayCall >> say ";\n"+          (Internal_TVoid, Nothing) -> do+            sayCall >> say ";\n"+            sayExceptionCheck+          (_, Nothing) -> do+            sayVar "result" Nothing retType >> say " = " >> sayCall >> say ";\n"+            sayExceptionCheck+            say "return result;\n"           (Internal_TBitspace b, Just _) -> do             addReqsM $ bitspaceReqs b             let convFn = bitspaceToCppValueFn b-            say "return "+            sayVar "result" Nothing retType+            say " = "             forM_ convFn $ \f -> says [f, "("]             sayCall             when (isJust convFn) $ say ")"             say ";\n";+            sayExceptionCheck+            say "return result;\n"           (Internal_TObj cls1, Just retCType@(Internal_TPtr (Internal_TConst (Internal_TObj cls2))))             | cls1 == cls2 -> do-              sayVar "resultPtr" Nothing retCType >> say " = " >> sayCall >> say ";\n"-              sayVar "result" Nothing retType >> say " = *resultPtr;\n"-              say "delete resultPtr;\n"-              say "return result;\n"+            sayVar "resultPtr" Nothing retCType >> say " = " >> sayCall >> say ";\n"+            sayVar "result" Nothing retType >> say " = *resultPtr;\n"+            say "delete resultPtr;\n"+            sayExceptionCheck+            say "return result;\n"           (Internal_TRef (Internal_TConst (Internal_TObj cls1)),-           Just (Internal_TPtr (Internal_TConst (Internal_TObj cls2)))) | cls1 == cls2 ->-            say "return *(" >> sayCall >> say ");\n"+           Just (Internal_TPtr (Internal_TConst (Internal_TObj cls2)))) | cls1 == cls2 -> do+            sayVar "result" Nothing retType >> say " = *" >> sayCall >> say ";\n"+            sayExceptionCheck+            say "return result;\n"           (Internal_TRef (Internal_TObj cls1),-           Just (Internal_TPtr (Internal_TObj cls2))) | cls1 == cls2 ->-            say "return *(" >> sayCall >> say ");\n"+           Just (Internal_TPtr (Internal_TObj cls2))) | cls1 == cls2 -> do+            sayVar "result" Nothing retType >> say " = *" >> sayCall >> say ";\n"+            sayExceptionCheck+            say "return result;\n"           ts -> abort $ concat                 ["sayExportCallback: Unexpected return types ", show ts, "."] @@ -568,6 +733,39 @@       sayFunction fnName ["f", "release", "releaseRelease"] newCallbackFnType $ Just $         says ["return new ", implClassName, "(f, release, releaseRelease);\n"] +-- | Outputs interface-wide code needed to support exceptions.  Currently, this+-- comprises the function for rethrowing in C++ an exception transferred from+-- a foreign language.+sayExceptionSupport :: Bool -> Generator ()+sayExceptionSupport sayBody =+  sayFunction exceptionRethrowFnName+              ["excId", "voidPtr"]+              (fnT [intT, ptrT voidT] voidT) $+  if not sayBody+  then Nothing+  else Just $ do+    iface <- askInterface+    let excClasses = interfaceAllExceptionClasses iface++    says ["switch (excId) {\n"]++    forM_ excClasses $ \cls -> do+      excId <- fmap getExceptionId $+               fromMaybeM (abort $ "sayExceptionSupport: Internal error, " ++ show cls +++                           "should have an exception ID, but doesn't.") $+               interfaceExceptionClassId iface cls+      says ["case ", show excId, ": {\n"]+      sayVar "excPtr" Nothing (ptrT $ objT cls) >> say " = reinterpret_cast<" >>+        sayType Nothing (ptrT $ objT cls) >> says [">(voidPtr);\n"]+      sayVar "exc" Nothing (objT cls) >> say " = *excPtr;\n"+      say "delete excPtr;\n"+      say "throw exc;\n"+      say "}\n"++    say "}\n"+    says ["throw \"Internal Hoppy error, ", exceptionRethrowFnName,+          " got an unknown exception ID.\";\n"]+ -- | Returns a 'Type' iff there is a C type distinct from the given C++ type -- that should be used for conversion. typeToCType :: Type -> Maybe Type@@ -622,10 +820,11 @@     -- TODO Is the right 'ReqsType' being used recursively here?     mconcat <$> mapM typeReqs (retType:paramTypes)   Internal_TCallback cb -> do+    -- TODO Should this be includeStd?     cbClassReqs <- reqInclude . includeLocal . moduleHppPath <$>                    findExportModule (callbackExtName cb)     -- TODO Is the right 'ReqsType' being used recursively here?-    fnTypeReqs <- typeReqs $ callbackToTFn cb+    fnTypeReqs <- typeReqs =<< callbackToTFn cb     return $ cbClassReqs `mappend` fnTypeReqs   Internal_TObj cls -> return $ classReqs cls   Internal_TObjToHeap cls -> return $ classReqs cls@@ -643,3 +842,36 @@   fromMaybeM (abort $ concat               ["findExportModule: Can't find module exporting ", fromExtName extName, "."]) =<<   fmap (M.lookup extName . interfaceNamesToModules) askInterface++getEffectiveExceptionHandlers :: ExceptionHandlers -> Generator ExceptionHandlers+getEffectiveExceptionHandlers handlers = do+  ifaceHandlers <- interfaceExceptionHandlers <$> askInterface+  moduleHandlers <- getExceptionHandlers <$> askModule+  -- Exception handlers declared lower in the hierarchy take precedence over+  -- those in the hierarchy; ExceptionHandlers is a left-biased monoid.+  return $ mconcat [handlers, moduleHandlers, ifaceHandlers]++getEffectiveCallbackThrows :: Callback -> Generator Bool+getEffectiveCallbackThrows cb = case callbackThrows cb of+  Just b -> return b+  Nothing -> moduleCallbacksThrow <$> askModule >>= \case+    Just b -> return b+    Nothing -> interfaceCallbacksThrow <$> askInterface++-- | Constructs the function type for a callback.  A callback that throws has+-- additional parameters.+--+-- Keep this in sync with the Haskell generator's version.+callbackToTFn :: Callback -> Generator Type+callbackToTFn cb = do+  throws <- mayThrow+  return $ Internal_TFn ((if throws 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])
src/Foreign/Hoppy/Generator/Language/Haskell.hs view
@@ -31,6 +31,10 @@   evalGenerator,   execGenerator,   renderPartial,+  askInterface,+  askModule,+  askModuleName,+  getModuleForExtName,   withErrorContext,   inFunction,   -- * Exports@@ -40,40 +44,68 @@   addExports,   -- * Imports   addImports,-  importHsModuleForExtName,+  -- * Language extensions+  addExtension,   -- * Code generation   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,-  toHsClassDeleteFnName,-  toHsClassDeleteFnPtrName,+  toHsDataCtorName',+  toHsClassDeleteFnName',+  toHsClassDeleteFnPtrName',+  toHsCtorName,+  toHsCtorName',   toHsMethodName,   toHsMethodName',+  toHsClassEntityName,+  toHsClassEntityName',   toHsCallbackCtorName,+  toHsCallbackCtorName',+  toHsCallbackNewFunPtrFnName,+  toHsCallbackNewFunPtrFnName',   toHsFnName,+  toHsFnName',   toArgName,   HsTypeSide (..),   cppTypeToHsTypeAndUse,   getClassHaskellConversion,+  callbackToTFn,   prettyPrint,   ) where @@ -81,7 +113,6 @@ import Control.Applicative ((<$>)) #endif import Control.Arrow (first)-import Control.Monad (when) #if MIN_VERSION_mtl(2,2,1) import Control.Monad.Except (Except, catchError, runExcept, throwError) #else@@ -99,9 +130,10 @@ #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 (capitalize, lowerFirst)-import Foreign.Hoppy.Generator.Spec+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 (@@ -250,19 +282,35 @@ -- | Context information for generating Haskell code. data Env = Env   { envInterface :: Interface+  , envModule :: Module   , envModuleName :: String   } +-- | Returns the currently generating interface. askInterface :: Generator Interface askInterface = envInterface <$> ask +-- | Returns the currently generating module.+askModule :: Generator Module+askModule = envModule <$> ask++-- | Returns the currently generating module's Haskell module name. askModuleName :: Generator String askModuleName = envModuleName <$> ask +-- | Looks up the 'Module' containing a given external name, throwing an error+-- if it can't be found.+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+ -- | A partially-rendered 'Module'.  Contains all of the module's bindings, but -- may be subject to further processing. data Partial = Partial-  { partialModuleHsName :: String+  { partialModuleHsName :: String  -- ^ This is just the module name.   , partialOutput :: Output   } @@ -286,40 +334,43 @@     -- ^ Lines of Haskell code (possibly empty).  These lines may not contain     -- the newline character in them.  There is an implicit newline between each     -- string, as given by @intercalate \"\\n\" . outputBody@.+  , outputExtensions :: S.Set String+    -- ^ Language extensions to enable via the @{-# LANGUAGE #-}@ pragma for the+    -- whole module.   }  instance Monoid Output where-  mempty = Output mempty mempty mempty+  mempty = Output mempty mempty mempty mempty -  (Output e i b) `mappend` (Output e' i' b') =-    Output (e `mappend` e') (i `mappend` i') (b `mappend` b')+  (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)  -- | Runs a generator action for the given interface and module name string. -- Returns an error message if an error occurred, otherwise the action's output -- together with its value.-runGenerator :: Interface -> String -> Generator a -> Either ErrorMsg (Partial, a)-runGenerator iface modName generator =-  fmap (first (Partial modName) . swap) $+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 $+     runExcept $ #endif-  flip catchError (\msg -> throwError $ msg ++ ".") $-  runWriterT $ runReaderT generator $ Env iface modName+     flip catchError (\msg -> throwError $ msg ++ ".") $+     runWriterT $ runReaderT generator $ Env iface mod modName  -- | Runs a generator action and returns the its value.-evalGenerator :: Interface -> String -> Generator a -> Either ErrorMsg a-evalGenerator iface modName =-  fmap snd . runGenerator iface modName+evalGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg a+evalGenerator iface mod = fmap snd . runGenerator iface mod  -- | Runs a generator action and returns its output.-execGenerator :: Interface -> String -> Generator a -> Either ErrorMsg Partial-execGenerator iface modName =-  fmap fst . runGenerator iface modName+execGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg Partial+execGenerator iface mod = fmap fst . runGenerator iface mod  -- | Converts a 'Partial' into a complete Haskell module. renderPartial :: Partial -> String@@ -332,6 +383,11 @@         [ [ "---------- 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 ->@@ -376,24 +432,10 @@ addImports :: HsImportSet -> Generator () addImports imports = tell mempty { outputImports = imports } --- | Imports all of the objects for the given external name into the current--- module.  This is a no-op of the external name is defined in the current--- module.-importHsModuleForExtName :: ExtName -> Generator ()-importHsModuleForExtName extName = inFunction "importHsModuleForExtName" $ do-  iface <- askInterface-  case M.lookup extName $ interfaceNamesToModules iface of-    Just ownerModule -> do-      let ownerModuleName = getModuleName iface ownerModule-      currentModuleName <- askModuleName-      when (currentModuleName /= ownerModuleName) $-        -- Yes, this currently imports the whole dang module to keep things-        -- simple.-        addImports $ hsWholeModuleImport ownerModuleName-    Nothing ->-      throwError $ concat-      ["Couldn't find module for ", show extName,-       " (maybe you forgot to include it in an exports list?)"]+-- | Adds a Haskell language extension to the current module.+addExtension :: String -> Generator ()+addExtension extensionName =+  tell $ mempty { outputExtensions = S.singleton extensionName }  -- | Outputs a line of Haskell code.  A newline will be added on the end of the -- input.  Newline characters must not be given to this function.@@ -418,6 +460,11 @@ indent :: Generator a -> Generator a indent = censor $ \o -> o { outputBody = map (\x -> ' ':' ':x) $ outputBody o } +-- | Runs the given action, indenting all code output by the action N spaces.+indentSpaces :: Int -> Generator a -> Generator a+indentSpaces n = censor $ \o -> o { outputBody = map (\x -> indentation ++ x) $ outputBody o }+  where indentation = replicate n ' '+ -- | Takes a list of binding actions and a body action, and outputs a @let@ -- expression.  By passing in 'Nothing' for the body, it will be omitted, so -- @let@ statements in @do@ blocks can be created as well.  Output is of the@@ -442,11 +489,62 @@       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++-- | Returns a module's unique short name that should be used for a qualified+-- import of the module.+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++-- | Adds a qualified import of the given external name's module into the current+-- module, and returns the qualified name of the import.  If the external name+-- is defined in the current module, then this is a no-op and 'Nothing' is+-- returned.+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++-- | Used like @addExtNameModule extName hsEntity@.  @hsEntity@ is a name in+-- Haskell code that is generated from the definition of @extName@, and thus+-- lives in @extName@'s module.  This function adds imports and returns a+-- qualified name as necessary to refer to the given entity.+addExtNameModule :: ExtName -> String -> Generator String+addExtNameModule extName hsEntity = do+  maybeImportName <- importHsModuleForExtName extName+  return $ case maybeImportName of+    Nothing -> hsEntity  -- Same module.+    Just importName -> concat [importName, ".", hsEntity]  -- Different module.+ -- | Internal helper function for constructing Haskell names from external -- names.  Returns a name that is a suitable Haskell type name for the external -- name, and if given 'Const', then with @\"Const\"@ appended.-toHsTypeName :: Constness -> ExtName -> String+toHsTypeName :: Constness -> ExtName -> Generator String toHsTypeName cst extName =+  inFunction "toHsTypeName" $+  addExtNameModule extName $ toHsTypeName' cst extName++-- | Pure version of 'toHsTypeName' that doesn't create a qualified name.+toHsTypeName' :: Constness -> ExtName -> String+toHsTypeName' cst extName =   (case cst of       Const -> (++ "Const")       Nonconst -> id) $@@ -455,67 +553,141 @@     [] -> []  -- | Returns the Haskell name for an enum.-toHsEnumTypeName :: CppEnum -> String-toHsEnumTypeName = toHsTypeName Nonconst . enumExtName+toHsEnumTypeName :: CppEnum -> Generator String+toHsEnumTypeName enum =+  inFunction "toHsEnumTypeName" $+  addExtNameModule (enumExtName enum) $ toHsEnumTypeName' enum +-- | Pure version of 'toHsEnumTypeName' that doesn't create a qualified name.+toHsEnumTypeName' :: CppEnum -> String+toHsEnumTypeName' = toHsTypeName' Nonconst . enumExtName+ -- | Constructs the data constructor name for a value in an enum.  Like C++ and -- unlike say Java, Haskell enum values aren't in a separate enum-specific -- namespace, so we prepend the enum name to the value name to get the data -- constructor name.  The value name is a list of words; see 'enumValueNames'.-toHsEnumCtorName :: CppEnum -> [String] -> String+toHsEnumCtorName :: CppEnum -> [String] -> Generator String toHsEnumCtorName enum words =-  concat $ toHsEnumTypeName enum : "_" : map capitalize words+  inFunction "toHsEnumCtorName" $+  addExtNameModule (enumExtName enum) $ toHsEnumCtorName' enum words +-- | Pure version of 'toHsEnumCtorName' that doesn't create a qualified name.+toHsEnumCtorName' :: CppEnum -> [String] -> String+toHsEnumCtorName' enum words =+  concat $ enumValuePrefix enum : map capitalize words+ -- | Returns the Haskell name for a bitspace.  See 'toHsEnumTypeName'.-toHsBitspaceTypeName :: Bitspace -> String-toHsBitspaceTypeName = toHsTypeName Nonconst . bitspaceExtName+toHsBitspaceTypeName :: Bitspace -> Generator String+toHsBitspaceTypeName bitspace =+  inFunction "toHsBitspaceTypeName" $+  addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceTypeName' bitspace +-- | Pure version of 'toHsBitspaceTypeName' that doesn't create a qualified name.+toHsBitspaceTypeName' :: Bitspace -> String+toHsBitspaceTypeName' = toHsTypeName' Nonconst . bitspaceExtName+ -- | Constructs the data constructor name for a value in a bitspace.  See -- 'toHsEnumCtorName'.-toHsBitspaceValueName :: Bitspace -> [String] -> String+toHsBitspaceValueName :: Bitspace -> [String] -> Generator String toHsBitspaceValueName bitspace words =-  lowerFirst $ concat $ toHsBitspaceTypeName bitspace : "_" : map capitalize words+  inFunction "toHsBitspaceValueName" $+  addExtNameModule (bitspaceExtName bitspace) $+  toHsBitspaceValueName' bitspace words +-- | Pure version of 'toHsBitspaceValueName' that doesn't create a qualified name.+toHsBitspaceValueName' :: Bitspace -> [String] -> String+toHsBitspaceValueName' bitspace words =+  lowerFirst $ concat $ bitspaceValuePrefix bitspace : map capitalize words+ -- | Returns the name of the function that will convert a bitspace value into a -- raw numeric value.-toHsBitspaceToNumName :: Bitspace -> String-toHsBitspaceToNumName = ("from" ++) . toHsBitspaceTypeName+toHsBitspaceToNumName :: Bitspace -> Generator String+toHsBitspaceToNumName bitspace =+  inFunction "toHsBitspaceToNumName" $+  addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceToNumName' bitspace +-- | Pure version of 'toHsBitspaceToNumName' that doesn't create a qualified name.+toHsBitspaceToNumName' :: Bitspace -> String+toHsBitspaceToNumName' = ("from" ++) . toHsBitspaceTypeName'+ -- | The name of the Haskell typeclass that contains a method for converting to -- a bitspace value.-toHsBitspaceClassName :: Bitspace -> String-toHsBitspaceClassName bitspace = 'I':'s':toHsBitspaceTypeName bitspace+toHsBitspaceClassName :: Bitspace -> Generator String+toHsBitspaceClassName bitspace =+  inFunction "toHsBitspaceClassName" $+  addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceClassName' bitspace +-- | Pure version of 'toHsBitspaceClassName' that doesn't create a qualified name.+toHsBitspaceClassName' :: Bitspace -> String+toHsBitspaceClassName' bitspace = 'I':'s':toHsBitspaceTypeName' bitspace+ -- | The name of the method in the 'toHsBitspaceClassName' typeclass that -- constructs bitspace values.-toHsBitspaceFromValueName :: Bitspace -> String-toHsBitspaceFromValueName = ("to" ++) . toHsBitspaceTypeName+toHsBitspaceFromValueName :: Bitspace -> Generator String+toHsBitspaceFromValueName bitspace =+  inFunction "toHsBitspaceFromValueName" $+  addExtNameModule (bitspaceExtName bitspace) $ toHsBitspaceFromValueName' bitspace +-- | Pure version of 'toHsBitspaceFromValueName' that doesn't create a qualified name.+toHsBitspaceFromValueName' :: Bitspace -> String+toHsBitspaceFromValueName' = ("to" ++) . toHsBitspaceTypeName'+ -- | The name for the typeclass of types that can be represented as values of -- the given C++ class.-toHsValueClassName :: Class -> String-toHsValueClassName cls = toHsDataTypeName Nonconst cls ++ "Value"+toHsValueClassName :: Class -> Generator String+toHsValueClassName cls =+  inFunction "toHsValueClassName" $+  addExtNameModule (classExtName cls) $ toHsValueClassName' cls +-- | Pure version of 'toHsValueClassName' that doesn't create a qualified name.+toHsValueClassName' :: Class -> String+toHsValueClassName' cls = toHsDataTypeName' Nonconst cls ++ "Value"+ -- | The name of the method within the 'toHsValueClassName' typeclass for -- accessing an object of the type as a pointer.-toHsWithValuePtrName :: Class -> String-toHsWithValuePtrName cls = concat ["with", toHsDataTypeName Nonconst cls, "Ptr"]+toHsWithValuePtrName :: Class -> Generator String+toHsWithValuePtrName cls =+  inFunction "toHsWithValuePtrName" $+  addExtNameModule (classExtName cls) $ toHsWithValuePtrName' cls +-- | Pure version of 'toHsWithValuePtrName' that doesn't create a qualified name.+toHsWithValuePtrName' :: Class -> String+toHsWithValuePtrName' cls = concat ["with", toHsDataTypeName' Nonconst cls, "Ptr"]+ -- | The name for the typeclass of types that are (possibly const) pointers to -- objects of the given C++ class, or subclasses.-toHsPtrClassName :: Constness -> Class -> String-toHsPtrClassName cst cls = toHsDataTypeName cst cls ++ "Ptr"+toHsPtrClassName :: Constness -> Class -> Generator String+toHsPtrClassName cst cls =+  inFunction "toHsPtrClassName" $+  addExtNameModule (classExtName cls) $ toHsPtrClassName' cst cls +-- | Pure version of 'toHsPtrClassName' that doesn't create a qualified name.+toHsPtrClassName' :: Constness -> Class -> String+toHsPtrClassName' cst cls = toHsDataTypeName' cst cls ++ "Ptr"+ -- | The name of the function that upcasts pointers to the specific class type -- and constness.-toHsCastMethodName :: Constness -> Class -> String-toHsCastMethodName cst cls = "to" ++ toHsDataTypeName cst cls+toHsCastMethodName :: Constness -> Class -> Generator String+toHsCastMethodName cst cls =+  inFunction "toHsCastMethodName" $+  addExtNameModule (classExtName cls) $ toHsCastMethodName' cst cls +-- | Pure version of 'toHsCastMethodName' that doesn't create a qualified name.+toHsCastMethodName' :: Constness -> Class -> String+toHsCastMethodName' cst cls = "to" ++ toHsDataTypeName' cst cls+ -- | The name of the typeclass that provides a method to downcast to a specific -- class type.  See 'toHsDownCastMethodName'.-toHsDownCastClassName :: Constness -> Class -> String+toHsDownCastClassName :: Constness -> Class -> Generator String toHsDownCastClassName cst cls =-  concat [toHsDataTypeName Nonconst cls,+  inFunction "toHsDownCastClassName" $+  addExtNameModule (classExtName cls) $ toHsDownCastClassName' cst cls++-- | Pure version of 'toHsDownCastClassName' that doesn't create a qualified+-- name.+toHsDownCastClassName' :: Constness -> Class -> String+toHsDownCastClassName' cst cls =+  concat [toHsDataTypeName' Nonconst cls,           "Super",           case cst of             Const -> "Const"@@ -523,77 +695,167 @@  -- | The name of the function that downcasts pointers to the specific class type -- and constness.-toHsDownCastMethodName :: Constness -> Class -> String-toHsDownCastMethodName cst cls = "downTo" ++ toHsDataTypeName cst cls+toHsDownCastMethodName :: Constness -> Class -> Generator String+toHsDownCastMethodName cst cls =+  inFunction "toHsDownCastMethodName" $+  addExtNameModule (classExtName cls) $ toHsDownCastMethodName' cst cls +-- | Pure version of 'toHsDownCastMethodName' that doesn't create a qualified+-- name.+toHsDownCastMethodName' :: Constness -> Class -> String+toHsDownCastMethodName' cst cls = "downTo" ++ toHsDataTypeName' cst cls+ -- | The import name for the foreign function that casts between two specific -- pointer types.  Used for upcasting and downcasting.-toHsCastPrimitiveName :: Class -> Class -> String-toHsCastPrimitiveName from to =-  concat ["cast", toHsDataTypeName Nonconst from, "To", toHsDataTypeName Nonconst to]+--+-- We need to know which module the cast function resides in, and while we could+-- look this up, the caller always knows, so we just have them pass it in.+toHsCastPrimitiveName :: Class -> Class -> Class -> Generator String+toHsCastPrimitiveName descendentClass from to =+  inFunction "toHsCastPrimitiveName" $+  addExtNameModule (classExtName descendentClass) $ toHsCastPrimitiveName' from to +-- | Pure version of 'toHsCastPrimitiveName' that doesn't create a qualified+-- name.+toHsCastPrimitiveName' :: Class -> Class -> String+toHsCastPrimitiveName' from to =+  concat ["cast", toHsDataTypeName' Nonconst from, "To", toHsDataTypeName' Nonconst to]+ -- | The name of one of the functions that add/remove const to/from a class's -- pointer type.  Given 'Const', it will return the function that adds const, -- and given 'Nonconst', it will return the function that removes const.-toHsConstCastFnName :: Constness -> Class -> String+toHsConstCastFnName :: Constness -> Class -> Generator String toHsConstCastFnName cst cls =-  concat ["cast", toHsDataTypeName Nonconst cls,+  inFunction "toHsConstCastFnName" $+  addExtNameModule (classExtName cls) $ toHsConstCastFnName' cst cls++-- | Pure version of 'toHsConstCastFnName' that doesn't create a qualified name.+toHsConstCastFnName' :: Constness -> Class -> String+toHsConstCastFnName' cst cls =+  concat ["cast", toHsDataTypeName' Nonconst cls,           case cst of             Const -> "ToConst"             Nonconst -> "ToNonconst"]  -- | The name of the data type that represents a pointer to an object of the -- given class and constness.-toHsDataTypeName :: Constness -> Class -> String-toHsDataTypeName cst cls = toHsTypeName cst $ classExtName cls+toHsDataTypeName :: Constness -> Class -> Generator String+toHsDataTypeName cst cls =+  inFunction "toHsDataTypeName" $+  addExtNameModule (classExtName cls) $ toHsDataTypeName' cst cls +-- | Pure version of 'toHsDataTypeName' that doesn't create a qualified name.+toHsDataTypeName' :: Constness -> Class -> String+toHsDataTypeName' cst cls = toHsTypeName' cst $ classExtName cls+ -- | The name of a data constructor for one of the object pointer types.-toHsDataCtorName :: Managed -> Constness -> Class -> String-toHsDataCtorName m cst cls = case m of+toHsDataCtorName :: Managed -> Constness -> Class -> Generator String+toHsDataCtorName m cst cls =+  inFunction "toHsDataCtorName" $+  addExtNameModule (classExtName cls) $ toHsDataCtorName' m cst cls++-- | Pure version of 'toHsDataCtorName' that doesn't create a qualified name.+toHsDataCtorName' :: Managed -> Constness -> Class -> String+toHsDataCtorName' m cst cls = case m of   Unmanaged -> base   Managed -> base ++ "Gc"-  where base = toHsDataTypeName cst cls+  where base = toHsDataTypeName' cst cls  -- | The name of the foreign function import wrapping @delete@ for the given -- class type.  This is in internal to the binding; normal users should use -- 'Foreign.Hoppy.Runtime.delete'.-toHsClassDeleteFnName :: Class -> String-toHsClassDeleteFnName cls = 'd':'e':'l':'e':'t':'e':'\'':toHsDataTypeName Nonconst cls+--+-- This is internal to a generated Haskell module, so it does not have a public+-- (qualified) form.+toHsClassDeleteFnName' :: Class -> String+toHsClassDeleteFnName' cls = 'd':'e':'l':'e':'t':'e':'\'':toHsDataTypeName' Nonconst cls  -- | The name of the foreign import that imports the same function as -- 'toHsClassDeleteFnName', but as a 'Foreign.Ptr.FunPtr' rather than an actual -- function.-toHsClassDeleteFnPtrName :: Class -> String-toHsClassDeleteFnPtrName cls =-  'd':'e':'l':'e':'t':'e':'P':'t':'r':'\'':toHsDataTypeName Nonconst cls+--+-- This is internal to a generated Haskell module, so it does not have a public+-- (qualified) form.+toHsClassDeleteFnPtrName' :: Class -> String+toHsClassDeleteFnPtrName' cls =+  'd':'e':'l':'e':'t':'e':'P':'t':'r':'\'':toHsDataTypeName' Nonconst cls +-- | Returns the name of the Haskell function that invokes the given+-- constructor.+toHsCtorName :: Class -> Ctor -> Generator String+toHsCtorName cls ctor =+  inFunction "toHsCtorName" $+  toHsClassEntityName cls $ fromExtName $ ctorExtName ctor++-- | Pure version of 'toHsCtorName' that doesn't create a qualified name.+toHsCtorName' :: Class -> Ctor -> String+toHsCtorName' cls ctor =+  toHsClassEntityName' cls $ fromExtName $ ctorExtName ctor+ -- | Returns the name of the Haskell function that invokes the given method.------ See also 'getClassyExtName'.-toHsMethodName :: Class -> Method -> String-toHsMethodName cls method = toHsMethodName' cls $ fromExtName $ methodExtName method+toHsMethodName :: Class -> Method -> Generator String+toHsMethodName cls method =+  inFunction "toHsMethodName" $+  toHsClassEntityName cls $ fromExtName $ methodExtName method --- | Returns the name of the Haskell function that invokes a method with a--- specific name in a class.-toHsMethodName' :: IsFnName String name => Class -> name -> String-toHsMethodName' cls methodName =-  lowerFirst $-  concat [fromExtName $ classExtName cls, "_",-          case toFnName methodName of-            FnName name -> name-            FnOp op -> fromExtName $ operatorPreferredExtName op]+-- | Pure version of 'toHsMethodName' that doesn't create a qualified name.+toHsMethodName' :: Class -> Method -> String+toHsMethodName' cls method =+  toHsClassEntityName' cls $ fromExtName $ methodExtName method +-- | Returns the name of the Haskell function for an entity in a class.+toHsClassEntityName :: IsFnName String name => Class -> name -> Generator String+toHsClassEntityName cls name =+  addExtNameModule (classExtName cls) $ toHsClassEntityName' cls name++-- | Pure version of 'toHsClassEntityName' that doesn't create a qualified 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+ -- | The name of the function that takes a Haskell function and wraps it in a -- callback object.  This is internal to the binding; normal users can pass -- Haskell functions to be used as callbacks inplicitly.-toHsCallbackCtorName :: Callback -> String-toHsCallbackCtorName = toHsFnName . callbackExtName+toHsCallbackCtorName :: Callback -> Generator String+toHsCallbackCtorName callback =+  inFunction "toHsCallbackCtorName" $+  addExtNameModule (callbackExtName callback) $ toHsCallbackCtorName' callback +-- | Pure version of 'toHsCallbackCtorName' that doesn't create a qualified+-- name.+toHsCallbackCtorName' :: Callback -> String+toHsCallbackCtorName' callback =+  toHsFnName' $ toExtName $ fromExtName (callbackExtName callback) ++ "_new"++-- | The name of the function that takes a Haskell function with Haskell-side+-- types and wraps it in a 'Foreign.Ptr.FunPtr' that does appropriate+-- conversions to and from C-side types.+toHsCallbackNewFunPtrFnName :: Callback -> Generator String+toHsCallbackNewFunPtrFnName callback =+  inFunction "toHsCallbackNewFunPtrFnName" $+  addExtNameModule (callbackExtName callback) $ toHsCallbackNewFunPtrFnName' callback++-- | Pure version of 'toHsCallbackNewFunPtrFnName' that doesn't create a qualified+-- name.+toHsCallbackNewFunPtrFnName' :: Callback -> String+toHsCallbackNewFunPtrFnName' callback =+  toHsFnName' $ toExtName $ fromExtName (callbackExtName callback) ++ "_newFunPtr"+ -- | Converts an external name into a name suitable for a Haskell function or -- variable.-toHsFnName :: ExtName -> String-toHsFnName = lowerFirst . fromExtName+toHsFnName :: ExtName -> Generator String+toHsFnName extName =+  inFunction "toHsFnName" $+  addExtNameModule extName $ toHsFnName' extName +-- | Pure version of 'toHsFnName' that doesn't create a qualified name.+toHsFnName' :: ExtName -> String+toHsFnName' = lowerFirst . fromExtName+ -- | Returns a distinct argument variable name for each nonnegative number. toArgName :: Int -> String toArgName = ("arg'" ++) . show@@ -652,15 +914,16 @@       addImports hsImportForSystemPosixTypes $> HsTyCon (UnQual $ HsIdent "HoppySPT.CSsize")     Internal_TEnum e -> HsTyCon . UnQual . HsIdent <$> case side of       HsCSide -> addImports hsImportForForeignC $> "HoppyFC.CInt"-      HsHsSide -> importHsModuleForExtName (enumExtName e) $> toHsEnumTypeName e+      HsHsSide -> toHsEnumTypeName e     Internal_TBitspace b -> case side of       HsCSide -> cppTypeToHsTypeAndUse side $ bitspaceType b-      HsHsSide -> importHsModuleForExtName (bitspaceExtName b) $>-                  HsTyCon (UnQual $ HsIdent $ toHsBitspaceTypeName b)+      HsHsSide -> do+        typeName <- toHsBitspaceTypeName b+        return $ HsTyCon $ UnQual $ HsIdent typeName     Internal_TPtr (Internal_TObj cls) -> do       -- Same as TPtr (TConst (TObj cls)), but nonconst.-      importHsModuleForExtName (classExtName cls)-      let dataType = HsTyCon $ UnQual $ HsIdent $ toHsTypeName Nonconst $ classExtName cls+      typeName <- toHsTypeName Nonconst $ classExtName cls+      let dataType = HsTyCon $ UnQual $ HsIdent typeName       case side of         HsCSide -> do           addImports hsImportForForeign@@ -668,23 +931,16 @@         HsHsSide -> return dataType     Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> do       -- Same as TPtr (TObj cls), but const.-      importHsModuleForExtName (classExtName cls)-      let dataType = HsTyCon $ UnQual $ HsIdent $ toHsTypeName Const $ classExtName cls+      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 (Internal_TFn paramTypes retType) -> do-      paramHsTypes <- mapM (cppTypeToHsTypeAndUse side) paramTypes-      retHsType <- cppTypeToHsTypeAndUse side retType-      sideFn <- case side of-        HsCSide -> do addImports hsImportForForeign-                      return $ HsTyApp $ HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr"-        HsHsSide -> return id-      addImports hsImportForPrelude-      return $ sideFn $-        foldr HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") retHsType) paramHsTypes+    Internal_TPtr fn@(Internal_TFn {}) -> do+      addImports hsImportForForeign+      HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") <$> cppTypeToHsTypeAndUse HsCSide fn     Internal_TPtr t' -> do       addImports hsImportForForeign       -- Pointers to types not covered above point to raw C++ values, so we need@@ -698,7 +954,7 @@       return $         foldr HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") retHsType) paramHsTypes     Internal_TCallback cb -> do-      hsType <- cppTypeToHsTypeAndUse side $ callbackToTFn cb+      hsType <- cppTypeToHsTypeAndUse side =<< callbackToTFn side cb       case side of         HsHsSide -> return hsType         HsCSide -> do@@ -706,11 +962,11 @@           return $ HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyFHR.CCallback") hsType     Internal_TObj cls -> case side of       HsCSide -> cppTypeToHsTypeAndUse side $ ptrT $ constT t-      HsHsSide -> case getClassHaskellConversion cls of+      HsHsSide -> case classHaskellConversionType $ getClassHaskellConversion cls of+        Just typeGen -> typeGen         Nothing ->           throwError $ concat           ["Expected a Haskell type for ", show cls, " but there isn't one"]-        Just c -> classHaskellConversionType c     Internal_TObjToHeap cls -> cppTypeToHsTypeAndUse side $ ptrT $ objT cls     Internal_TToGc t' -> case t' of       Internal_TRef _ -> cppTypeToHsTypeAndUse side t'  -- References behave the same as pointers.@@ -719,17 +975,36 @@       _ -> throwError $ tToGcInvalidFormErrorMessage Nothing t'     Internal_TConst t' -> cppTypeToHsTypeAndUse side t' --- | Returns the 'ClassHaskellConversion' of a class, if it has one.-getClassHaskellConversion :: Class -> Maybe ClassHaskellConversion-getClassHaskellConversion cls = case classHaskellConversion $ classConversion cls of-  ClassConversionNone -> Nothing-  ClassConversionManual c -> Just c-  ClassConversionToHeap -> Nothing-  ClassConversionToGc -> Nothing+-- | Returns the 'ClassHaskellConversion' of a class.+getClassHaskellConversion :: Class -> ClassHaskellConversion+getClassHaskellConversion = classHaskellConversion . classConversion +-- | Constructs the function type for a callback.  For Haskell, the type depends+-- on the side; the C++ side has additional parameters.+--+-- Keep this in sync with the C++ generator's version.+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])+ -- | Prints a value like 'P.prettyPrint', but removes newlines so that they -- don't cause problems with this module's textual generation.  Should be mainly -- used for printing types; stripping newlines from definitions for example -- could go badly. prettyPrint :: P.Pretty a => a -> String-prettyPrint = filter (/= '\n') . P.prettyPrint+prettyPrint = collapseSpaces . filter (/= '\n') . P.prettyPrint+  where collapseSpaces (' ':xs) = ' ' : collapseSpaces (dropWhile (== ' ') xs)+        collapseSpaces (x:xs) = x : collapseSpaces xs+        collapseSpaces [] = []
src/Foreign/Hoppy/Generator/Language/Haskell/Internal.hs view
@@ -27,1336 +27,1659 @@ #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>), (<*>), pure) #endif-import Control.Arrow ((&&&), second)-import Control.Monad (forM, unless, when)-#if MIN_VERSION_mtl(2,2,1)-import Control.Monad.Except (throwError)-#else-import Control.Monad.Error (throwError)-#endif-import Control.Monad.Trans (lift)-import Control.Monad.Writer (execWriterT, tell)-import Data.Foldable (forM_)-import Data.Graph (SCC (AcyclicSCC, CyclicSCC), stronglyConnComp)-import Data.List (intersperse)-import qualified Data.Map as M-import Data.Maybe (isJust, mapMaybe)-#if !MIN_VERSION_base(4,8,0)-import Data.Monoid (mconcat)-#endif-import qualified Data.Set as S-import Foreign.Hoppy.Generator.Common-import Foreign.Hoppy.Generator.Spec-import Foreign.Hoppy.Generator.Types-import Foreign.Hoppy.Generator.Language.Cpp (-  classCastFnCppName,-  classDeleteFnCppName,-  externalNameToCpp,-  )-import Foreign.Hoppy.Generator.Language.Haskell-import Language.Haskell.Syntax (-  HsAsst,-  HsContext,-  HsName (HsIdent),-  HsQName (Special, UnQual),-  HsQualType (HsQualType),-  HsSpecialCon (HsUnitCon),-  HsType (HsTyApp, HsTyCon, HsTyFun, HsTyVar),-  )-import System.FilePath ((<.>), pathSeparator)---- | The in-memory result of generating Haskell code for an interface.-data Generation = Generation-  { generatedFiles :: M.Map FilePath String-    -- ^ A map from paths of generated files to the contents of those files.-    -- The file paths are relative paths below the Haskell generation root.-  }---- | Runs the C++ code generator against an interface.-generate :: Interface -> Either ErrorMsg Generation-generate iface = do-  -- Build the partial generation of each module.-  modPartials <- forM (M.elems $ interfaceModules iface) $ \m ->-    (,) m <$> execGenerator iface (getModuleName iface m) (generateSource m)--  -- Compute the strongly connected components.  If there is a nontrivial SCC,-  -- then there is a module import cycle that we'll have to break with hs-boot-  -- files.-  let partialsByHsName :: M.Map HsModuleName Partial-      partialsByHsName = M.fromList $ map ((partialModuleHsName &&& id) . snd) modPartials--      sccInput :: [((Module, Partial), Partial, [Partial])]-      sccInput = flip map modPartials $ \x@(_, p) ->-        (x, p,-         mapMaybe (flip M.lookup partialsByHsName . hsImportModule) $-         M.keys $ getHsImportSet $ outputImports $ partialOutput p)--      sccs :: [SCC (Module, Partial)]-      sccs = stronglyConnComp sccInput--  fileContents <- execWriterT $ forM_ sccs $ \scc -> case scc of-    AcyclicSCC (_, p) -> tell [finishPartial p "hs"]-    CyclicSCC mps -> do-      let cycleModNames = S.fromList $ map (partialModuleHsName . snd) mps-      forM_ mps $ \(m, p) -> do-        -- Create a boot partial.-        pBoot <- lift $ execGenerator iface (partialModuleHsName p) (generateBootSource m)--        -- Change the source and boot partials so that all imports of modules in-        -- this cycle are {-# SOURCE #-} imports.-        let p' = setSourceImports cycleModNames p-            pBoot' = setSourceImports cycleModNames pBoot--        -- Emit the completed partials.-        tell [finishPartial p' "hs", finishPartial pBoot' "hs-boot"]--  return $ Generation $ M.fromList fileContents--  where finishPartial :: Partial -> String -> (FilePath, String)-        finishPartial p fileExt =-          (listSubst '.' pathSeparator (partialModuleHsName p) <.> fileExt,-           prependExtensions $ renderPartial p)--        setSourceImports :: S.Set HsModuleName -> Partial -> Partial-        setSourceImports modulesToSourceImport p =-          let output = partialOutput p-              imports = outputImports output-              imports' = makeHsImportSet $-                         M.mapWithKey (setSourceImportIfIn modulesToSourceImport) $-                         getHsImportSet imports-              output' = output { outputImports = imports' }-          in p { partialOutput = output' }--        setSourceImportIfIn :: S.Set HsModuleName -> HsImportKey -> HsImportSpecs -> HsImportSpecs-        setSourceImportIfIn modulesToSourceImport key specs =-          if hsImportModule key `S.member` modulesToSourceImport-          then specs { hsImportSource = True }-          else specs--prependExtensions :: String -> String-prependExtensions = (prependExtensionsPrefix ++)--prependExtensionsPrefix :: String-prependExtensionsPrefix =-  -- MultiParamTypeClasses is necessary for instances of Decodable and-  -- Encodable.  FlexibleContexts is needed for the type signature of the-  -- function that wraps the actual callback function in callback creation-  -- functions.-  ---  -- FlexibleInstances and TypeSynonymInstances are enabled to allow conversions-  -- to and from String, which is really [Char].-  ---  -- UndecidableInstances is needed for instances of the form "SomeClassConstPtr-  -- a => SomeClassValue a", and overlapping instances are used for the overlap-  -- between these instances and instances of SomeClassValue for the class's-  -- native Haskell type, when it's convertible.  CPP is used for warning-free-  -- compatibility using overlapping instances with both GHC 7.8 and 7.10.-  ---  -- GeneralizedNewtypeDeriving is to enable automatic deriving of-  -- Data.Bits.Bits instances for bitspace newtypes.-  concat-  [ "{-# LANGUAGE CPP, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving"-  , ", MultiParamTypeClasses, TypeSynonymInstances, UndecidableInstances #-}\n"-  , "#if !MIN_VERSION_base(4,8,0)\n"-  , "{-# LANGUAGE OverlappingInstances #-}\n"-  , "#endif\n\n"-  ]--generateSource :: Module -> Generator ()-generateSource m = do-  forM_ (moduleExports m) $ sayExport SayExportForeignImports-  forM_ (moduleExports m) $ sayExport SayExportDecls--generateBootSource :: Module -> Generator ()-generateBootSource m =-  forM_ (moduleExports m) $ sayExport SayExportBoot--data SayExportMode = SayExportForeignImports | SayExportDecls | SayExportBoot-                   deriving (Eq, Show)--sayExport :: SayExportMode -> Export -> Generator ()-sayExport mode export = do-  case export of-    ExportVariable v -> sayExportVar mode v-    ExportEnum enum -> sayExportEnum mode enum-    ExportBitspace bitspace -> sayExportBitspace mode bitspace-    ExportFn fn ->-      (sayExportFn mode <$> fnExtName <*> pure Nothing <*> fnPurity <*> fnParams <*> fnReturn) fn-    ExportClass cls -> sayExportClass mode cls-    ExportCallback cb -> sayExportCallback mode cb--  when (mode == SayExportDecls) $-    addendumHaskell $ exportAddendum export--sayExportVar :: SayExportMode -> Variable -> Generator ()-sayExportVar mode v = do-  withErrorContext ("generating variable " ++ show (varExtName v)) $ do-    let (isConst, deconstType) = case varType v of-          Internal_TConst t -> (True, t)-          t -> (False, t)-    sayExportFn mode (varGetterExtName v) Nothing Nonpure [] deconstType-    unless isConst $-      sayExportFn mode (varSetterExtName v) Nothing Nonpure [deconstType] voidT--sayExportEnum :: SayExportMode -> CppEnum -> Generator ()-sayExportEnum mode enum =-  withErrorContext ("generating enum " ++ show (enumExtName enum)) $-  case mode of-    -- Nothing to import from the C++ side of an enum.-    SayExportForeignImports -> return ()--    SayExportDecls -> do-      let hsTypeName = toHsEnumTypeName enum-          values :: [(Int, String)]-          values = map (second $ toHsEnumCtorName enum) $ enumValueNames enum-      addImports $ mconcat [hsImports "Prelude" ["($)", "(++)"], hsImportForPrelude]--      -- Print out the data declaration.-      ln-      addExport' hsTypeName-      saysLn ["data ", hsTypeName, " ="]-      indent $ do-        forM_ (zip (False:repeat True) values) $ \(cont, (_, hsCtorName)) ->-          saysLn [if cont then "| " else "", hsCtorName]-        sayLn "deriving (HoppyP.Bounded, HoppyP.Eq, HoppyP.Ord, HoppyP.Show)"--      -- Print out the Enum instance.-      ln-      saysLn ["instance HoppyP.Enum ", hsTypeName, " where"]-      indent $ do-        forM_ values $ \(num, hsCtorName) ->-          saysLn ["fromEnum ", hsCtorName, " = ", show num]-        ln-        forM_ values $ \(num, hsCtorName) ->-          saysLn ["toEnum (", show num, ") = ", hsCtorName]-        saysLn ["toEnum n' = HoppyP.error $ ",-                show (concat ["Unknown ", hsTypeName, " numeric value: "]),-                " ++ HoppyP.show n'"]--    SayExportBoot -> do-      let hsTypeName = toHsEnumTypeName enum-      addImports hsImportForPrelude-      addExport hsTypeName-      ln-      saysLn ["data ", hsTypeName]-      saysLn ["instance HoppyP.Bounded ", hsTypeName]-      saysLn ["instance HoppyP.Enum ", hsTypeName]-      saysLn ["instance HoppyP.Eq ", hsTypeName]-      saysLn ["instance HoppyP.Ord ", hsTypeName]-      saysLn ["instance HoppyP.Show ", hsTypeName]--sayExportBitspace :: SayExportMode -> Bitspace -> Generator ()-sayExportBitspace mode bitspace =-  withErrorContext ("generating bitspace " ++ show (bitspaceExtName bitspace)) $-  let hsTypeName = toHsBitspaceTypeName bitspace-      fromFnName = toHsBitspaceToNumName bitspace-      className = toHsBitspaceClassName bitspace-      toFnName = toHsBitspaceFromValueName bitspace-      hsType = HsTyCon $ UnQual $ HsIdent hsTypeName-  in case mode of-    -- Nothing to import from the C++ side of a bitspace.-    SayExportForeignImports -> return ()--    SayExportDecls -> do-      let values :: [(Int, String)]-          values = map (second $ toHsBitspaceValueName bitspace) $ bitspaceValueNames bitspace--      hsCNumType <- cppTypeToHsTypeAndUse HsCSide $ bitspaceType bitspace-      hsHsNumType <- cppTypeToHsTypeAndUse HsHsSide $ bitspaceType bitspace--      -- Print out the data declaration and conversion functions.-      addImports $ mconcat [hsImportForBits, hsImportForPrelude, hsImportForRuntime]-      addExport' hsTypeName-      addExport' className-      ln-      saysLn ["newtype ", hsTypeName, " = ", hsTypeName, " { ",-              fromFnName, " :: ", prettyPrint hsCNumType, " }"]-      indent $ sayLn "deriving (HoppyDB.Bits, HoppyP.Bounded, HoppyP.Eq, HoppyP.Ord, HoppyP.Show)"-      ln-      saysLn ["class ", className, " a where"]-      indent $ do-        let tyVar = HsTyVar $ HsIdent "a"-        saysLn [toFnName, " :: ", prettyPrint $ HsTyFun tyVar hsType]-      ln-      saysLn ["instance ", className, " (", prettyPrint hsCNumType, ") where"]-      indent $ saysLn [toFnName, " = ", hsTypeName]-      saysLn ["instance ", className, " (", prettyPrint hsHsNumType, ") where"]-      indent $ saysLn [toFnName, " = ", hsTypeName, " . HoppyFHR.coerceIntegral"]-      saysLn ["instance ", className, " ", hsTypeName, " where"]-      indent $ saysLn [toFnName, " = HoppyP.id"]--      -- If the bitspace has an associated enum, then print out a conversion-      -- instance for it as well.-      forM_ (bitspaceEnum bitspace) $ \enum -> do-        let enumTypeName = toHsEnumTypeName enum-        importHsModuleForExtName $ enumExtName enum-        addImports $ mconcat [hsImport1 "Prelude" "(.)", hsImportForPrelude, hsImportForRuntime]-        ln-        saysLn ["instance ", className, " ", enumTypeName, " where"]-        indent $-          saysLn [toFnName, " = ", hsTypeName, " . HoppyFHR.coerceIntegral . HoppyP.fromEnum"]--      -- Print out the constants.-      ln-      forM_ values $ \(num, valueName) -> do-        addExport valueName-        saysLn [valueName, " = ", hsTypeName, " ", show num]--    SayExportBoot -> do-      hsCNumType <- cppTypeToHsTypeAndUse HsCSide $ bitspaceType bitspace-      hsHsNumType <- cppTypeToHsTypeAndUse HsHsSide $ bitspaceType bitspace--      addImports $ mconcat [hsImportForBits, hsImportForPrelude]-      addExport' hsTypeName-      addExport' className-      ln-      saysLn ["newtype ", hsTypeName, " = ", hsTypeName, " { ",-              fromFnName, " :: ", prettyPrint hsCNumType, " }"]-      ln-      saysLn ["instance HoppyDB.Bits ", hsTypeName]-      saysLn ["instance HoppyP.Bounded ", hsTypeName]-      saysLn ["instance HoppyP.Eq ", hsTypeName]-      saysLn ["instance HoppyP.Ord ", hsTypeName]-      saysLn ["instance HoppyP.Show ", hsTypeName]-      ln-      saysLn ["class ", className, " a where"]-      indent $ do-        let tyVar = HsTyVar $ HsIdent "a"-        saysLn [toFnName, " :: ", prettyPrint $ HsTyFun tyVar hsType]-      ln-      saysLn ["instance ", className, " (", prettyPrint hsCNumType, ")"]-      saysLn ["instance ", className, " (", prettyPrint hsHsNumType, ")"]-      saysLn ["instance ", className, " ", hsTypeName]-      forM_ (bitspaceEnum bitspace) $ \enum -> do-        let enumTypeName = toHsEnumTypeName enum-        importHsModuleForExtName $ enumExtName enum-        saysLn ["instance ", className, " ", enumTypeName]--sayExportFn :: SayExportMode-            -> ExtName-            -> Maybe (Constness, Class)-            -> Purity-            -> [Type]-            -> Type-            -> Generator ()-sayExportFn mode name methodInfo purity paramTypes retType =-  let hsFnName = toHsFnName name-      hsFnImportedName = hsFnName ++ "'"-  in case mode of-    SayExportForeignImports ->-      withErrorContext ("generating imports for function " ++ show name) $ do-        -- Print a "foreign import" statement.-        hsCType <- fnToHsTypeAndUse HsCSide methodInfo purity paramTypes retType-        saysLn ["foreign import ccall \"", externalNameToCpp name, "\" ", hsFnImportedName, " :: ",-                prettyPrint hsCType]--    SayExportDecls -> withErrorContext ("generating function " ++ show name) $ do-      -- Print the type signature.-      ln-      addExport hsFnName-      hsHsType <- fnToHsTypeAndUse HsHsSide methodInfo purity paramTypes retType-      saysLn [hsFnName, " :: ", prettyPrint hsHsType]--      case purity of-        Nonpure -> return ()-        Pure -> saysLn ["{-# NOINLINE ", hsFnName, " #-}"]--      -- Print the function body.-      let argNames = map toArgName [1..length paramTypes]-          argNamesWithThis = (if isJust methodInfo then ("this":) else id) argNames-          convertedArgNames = map (++ "'") argNames-      -- Operators on this line must bind more weakly than operators used below,-      -- namely ($) and (>>=).  (So finish the line with ($).)-      lineEnd <- case purity of-        Nonpure -> return [" ="]-        Pure -> do addImports $ mconcat [hsImport1 "Prelude" "($)", hsImportForUnsafeIO]-                   return [" = HoppySIU.unsafePerformIO $"]-      saysLn $ hsFnName : map (' ':) argNamesWithThis ++ lineEnd-      indent $ do-        forM_ (zip3 paramTypes argNames convertedArgNames) $ \(t, argName, argName') ->-          sayArgProcessing ToCpp t argName argName'--        sayCallAndProcessReturn ToCpp retType $-          hsFnImportedName :-          (case methodInfo of-             Just (cst, cls) -> " (" ++ toHsCastMethodName cst cls ++ " this)"-             Nothing -> "") :-          map (' ':) convertedArgNames--    SayExportBoot ->-      -- Functions (methods included) cannot be referenced from other exports,-      -- so we don't need to emit anything.-      return ()---- | Prints \"foreign import\" statements and an internal callback construction--- function for a given 'Callback' specification.  For example, for a callback--- of 'HsHsSide' type @Int -> String -> IO Int@, we will generate the following--- bindings:------ > foreign import ccall "wrapper" name'newFunPtr--- >   :: (CInt -> Ptr CChar -> IO CInt)--- >   -> IO (FunPtr (CInt -> Ptr CChar -> IO CInt))--- >--- > -- (This is an ad-hoc generated binding for C++ callback impl class constructor.)--- > foreign import ccall "genpop__name_impl" name'newCallback--- >   :: FunPtr (CInt -> Ptr CChar -> IO CInt)--- >   -> FunPtr (FunPtr (IO ()) -> IO ())--- >   -> Bool--- >   -> IO (CCallback (CInt -> Ptr CChar -> IO CInt))--- >--- > name :: (CInt -> String -> IO CInt) -> IO (CCallback (CInt -> Ptr CChar -> IO CInt))--- > name f = do--- >   let cf arg1' arg2' = do--- >         arg1 <- return arg1'--- >         arg2 <- ...decode the string...--- >         f arg1 arg2 >>= return--- >   cfp <- name'newFunPtr cf--- >   name'newCallback cfp freeHaskellFunPtrFunPtr False------ Only the implementation of bindings that take a callback of this type will--- make use of this @name@ binding; @name@ is not useful to users of bindings.-sayExportCallback :: SayExportMode -> Callback -> Generator ()-sayExportCallback mode cb =-  withErrorContext ("generating callback " ++ show (callbackExtName cb)) $ do-    let name = callbackExtName cb-        paramTypes = callbackParams cb-        retType = callbackReturn cb-        fnType = callbackToTFn cb-        hsFnName = toHsCallbackCtorName cb-        hsFnName'newCallback = hsFnName ++ "'newCallback"-        hsFnName'newFunPtr = hsFnName ++ "'newFunPtr"--    hsFnCType <- cppTypeToHsTypeAndUse HsCSide fnType-    hsFnHsType <- cppTypeToHsTypeAndUse HsHsSide fnType--    let getWholeFnType = do-          addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]-          return $-            HsTyFun hsFnHsType $-            HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $-            HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyFHR.CCallback") hsFnCType--    case mode of-      SayExportForeignImports -> do-        addImports $ mconcat [hsImportForForeign, hsImportForPrelude, hsImportForRuntime]-        let hsFunPtrType = HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") hsFnCType-            hsFunPtrImportType =-              HsTyFun hsFnCType $-              HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") hsFunPtrType-            hsCallbackCtorImportType =-              HsTyFun hsFunPtrType $-              HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") $-                       HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") $-                                HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $-                                HsTyCon $ Special HsUnitCon) $-                       HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $-                       HsTyCon $ Special HsUnitCon) $-              HsTyFun (HsTyCon $ UnQual $ HsIdent "HoppyP.Bool") $-              HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $-              HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyFHR.CCallback") hsFnCType--        saysLn ["foreign import ccall \"wrapper\" ", hsFnName'newFunPtr, " :: ",-                prettyPrint hsFunPtrImportType]-        saysLn ["foreign import ccall \"", externalNameToCpp name, "\" ",-                hsFnName'newCallback, " :: ", prettyPrint hsCallbackCtorImportType]--      SayExportDecls -> do-        addExport hsFnName-        wholeFnType <- getWholeFnType-        let paramCount = length paramTypes-            argNames = map toArgName [1..paramCount]-            argNames' = map (++ "'") argNames-        ln-        saysLn [hsFnName, " :: ", prettyPrint wholeFnType]-        saysLn [hsFnName, " f'hs = do"]-        indent $ do-          sayLet-            [do saysLn ["f'c ", unwords argNames, " ="]-                indent $ do-                  forM_ (zip3 paramTypes argNames argNames') $ \(t, argName, argName') ->-                    sayArgProcessing FromCpp t argName argName'-                  sayCallAndProcessReturn FromCpp retType $-                    "f'hs" : map (' ':) argNames']-            Nothing-          saysLn ["f'p <- ", hsFnName'newFunPtr, " f'c"]-          saysLn [hsFnName'newCallback, " f'p HoppyFHR.freeHaskellFunPtrFunPtr HoppyP.False"]--      SayExportBoot -> do-        addExport hsFnName-        wholeFnType <- getWholeFnType-        ln-        saysLn [hsFnName, " :: ", prettyPrint wholeFnType]--data CallDirection =-  ToCpp  -- ^ Haskell code is calling out to C++.-  | FromCpp  -- ^ C++ is invoking a callback.--sayArgProcessing :: CallDirection -> Type -> String -> String -> Generator ()-sayArgProcessing dir t fromVar toVar =-  withErrorContext ("processing argument of type " ++ show t) $-  case t of-    Internal_TVoid -> throwError $ "TVoid is not a valid argument type"-    Internal_TBool -> case dir of-      ToCpp -> saysLn ["let ", toVar, " = if ", fromVar, " then 1 else 0 in"]-      FromCpp -> do addImports $ hsImport1 "Prelude" "(/=)"-                    saysLn ["let ", toVar, " = ", fromVar, " /= 0 in"]-    Internal_TChar -> noConversion-    Internal_TUChar -> noConversion-    Internal_TShort -> noConversion-    Internal_TUShort -> noConversion-    Internal_TInt -> sayCoerceIntegral-    Internal_TUInt -> noConversion-    Internal_TLong -> noConversion-    Internal_TULong -> noConversion-    Internal_TLLong -> noConversion-    Internal_TULLong -> noConversion-    Internal_TFloat -> sayCoerceFloating-    Internal_TDouble -> sayCoerceFloating-    Internal_TInt8 -> noConversion-    Internal_TInt16 -> noConversion-    Internal_TInt32 -> noConversion-    Internal_TInt64 -> noConversion-    Internal_TWord8 -> noConversion-    Internal_TWord16 -> noConversion-    Internal_TWord32 -> noConversion-    Internal_TWord64 -> noConversion-    Internal_TPtrdiff -> noConversion-    Internal_TSize -> noConversion-    Internal_TSSize -> noConversion-    Internal_TEnum _ -> do-      addImports $ mconcat [hsImport1 "Prelude" "($)", hsImportForPrelude, hsImportForRuntime]-      saysLn ["let ", toVar,-              -- TODO The coersion here is unnecssary if we replace the C numeric-              -- types with their Haskell ones across the board (e.g. CInt ->-              -- Int).-              case dir of-                ToCpp -> " = HoppyFHR.coerceIntegral $ HoppyP.fromEnum "-                FromCpp -> " = HoppyP.toEnum $ HoppyFHR.coerceIntegral ",-              fromVar, " in"]-    Internal_TBitspace b -> do-      importHsModuleForExtName $ bitspaceExtName b-      saysLn $ concat [ ["let ", toVar, " = "]-                      , case dir of-                          ToCpp -> [toHsBitspaceToNumName b, " $ ", toHsBitspaceFromValueName b]-                          FromCpp -> [toHsBitspaceTypeName b],-                        [" ", fromVar, " in"]-                      ]-    -- References and pointers are handled equivalently.-    Internal_TPtr (Internal_TObj cls) -> do-      addImportForClass cls-      case dir of-        ToCpp -> do-          addImports $ mconcat [hsImport1 "Prelude" "($)",-                                hsImportForRuntime]-          saysLn ["HoppyFHR.withCppPtr (", toHsCastMethodName Nonconst cls, " ", fromVar,-                  ") $ \\", toVar, " ->"]-        FromCpp ->-          saysLn ["let ", toVar, " = ", toHsDataCtorName Unmanaged Nonconst cls,-                  " ", fromVar, " in"]-    Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> do-      addImportForClass cls-      case dir of-        ToCpp -> do-          -- Same as the (TObj _), ToCpp case.-          addImports $ mconcat [hsImport1 "Prelude" "($)",-                                hsImportForPrelude,-                                hsImportForRuntime]-          saysLn [toHsWithValuePtrName cls, " ", fromVar,-                  " $ HoppyP.flip HoppyFHR.withCppPtr $ \\", toVar, " ->"]-        FromCpp ->-          saysLn ["let ", toVar, " = ", toHsDataCtorName Unmanaged Const cls,-                  " ", fromVar, " in"]-    Internal_TPtr _ -> noConversion-    Internal_TRef t' -> sayArgProcessing dir (ptrT t') fromVar toVar-    Internal_TFn {} -> throwError "TFn unimplemented"-    Internal_TCallback cb -> case dir of-      ToCpp -> do-        addImports $ hsImport1 "Prelude" "(>>=)"-        importHsModuleForExtName $ callbackExtName cb-        saysLn [toHsCallbackCtorName cb, " ", fromVar, " >>= \\", toVar, " ->"]-      FromCpp -> throwError "Can't receive a callback from C++"-    Internal_TObj cls -> case dir of-      ToCpp -> do-        -- Same as the (TPtr (TConst (TObj _))), ToPtr case.-        addImportForClass cls-        addImports $ mconcat [hsImport1 "Prelude" "($)",-                              hsImportForPrelude,-                              hsImportForRuntime]-        saysLn [toHsWithValuePtrName cls, " ", fromVar,-                " $ HoppyP.flip HoppyFHR.withCppPtr $ \\", toVar, " ->"]-      FromCpp -> case classHaskellConversion $ classConversion cls of-        ClassConversionNone ->-          throwError $ concat-          ["Can't pass a TObj of ", show cls,-           " from C++ to Haskell because no class conversion is defined"]-        ClassConversionManual _ -> do-          addImportForClass cls-          addImports $ mconcat [hsImport1 "Prelude" "(>>=)",-                                hsImportForRuntime]-          saysLn ["HoppyFHR.decode (", toHsDataCtorName Unmanaged Const cls, " ",-                  fromVar, ") >>= \\", toVar, " ->"]-        ClassConversionToHeap -> sayArgProcessing dir (objToHeapT cls) fromVar toVar-        ClassConversionToGc -> sayArgProcessing dir (toGcT t) fromVar toVar-    Internal_TObjToHeap cls -> case dir of-      ToCpp -> throwError $ objToHeapTWrongDirectionErrorMsg Nothing cls-      FromCpp -> sayArgProcessing dir (ptrT $ objT cls) fromVar toVar-    Internal_TToGc t' -> case dir of-      ToCpp -> throwError $ toGcTWrongDirectionErrorMsg Nothing t'-      FromCpp -> do-        addImports $ mconcat [hsImport1 "Prelude" "(>>=)",-                              hsImportForRuntime]-        saysLn ["HoppyFHR.toGc ", fromVar, " >>= \\", toVar, " ->"]-    Internal_TConst t' -> sayArgProcessing dir t' fromVar toVar-  where noConversion = saysLn ["let ", toVar, " = ", fromVar, " in"]-        sayCoerceIntegral = do-          addImports hsImportForRuntime-          saysLn ["let ", toVar, " = HoppyFHR.coerceIntegral ", fromVar, " in"]-        sayCoerceFloating = do-          addImports hsImportForPrelude-          saysLn ["let ", toVar, " = HoppyP.realToFrac ", fromVar, " in"]---- | Note that the 'CallDirection' is the direction of the call, not the--- direction of the return.  'ToCpp' means we're returning to the foreign--- language, 'FromCpp' means we're returning from it.-sayCallAndProcessReturn :: CallDirection -> Type -> [String] -> Generator ()-sayCallAndProcessReturn dir t callWords =-  withErrorContext ("processing return value of type " ++ show t) $-  case t of-    Internal_TVoid -> sayCall-    Internal_TBool -> do-      case dir of-        ToCpp -> do addImports $ mconcat [hsImport1 "Prelude" "(/=)", hsImportForPrelude]-                    sayLn "HoppyP.fmap (/= 0)"-        FromCpp -> sayLn "HoppyP.fmap (\\x -> if x then 1 else 0)"-      sayCall-    Internal_TChar -> sayCall-    Internal_TUChar -> sayCall-    Internal_TShort -> sayCall-    Internal_TUShort -> sayCall-    Internal_TInt -> sayCoerceIntegral >> sayCall-    Internal_TUInt -> sayCall-    Internal_TLong -> sayCall-    Internal_TULong -> sayCall-    Internal_TLLong -> sayCall-    Internal_TULLong -> sayCall-    Internal_TFloat -> sayCoerceFloating >> sayCall-    Internal_TDouble -> sayCoerceFloating >> sayCall-    Internal_TInt8 -> sayCall-    Internal_TInt16 -> sayCall-    Internal_TInt32 -> sayCall-    Internal_TInt64 -> sayCall-    Internal_TWord8 -> sayCall-    Internal_TWord16 -> sayCall-    Internal_TWord32 -> sayCall-    Internal_TWord64 -> sayCall-    Internal_TPtrdiff -> sayCall-    Internal_TSize -> sayCall-    Internal_TSSize -> sayCall-    Internal_TEnum _ -> do-      addImports $ mconcat [hsImport1 "Prelude" "(.)", hsImportForPrelude, hsImportForRuntime]-      case dir of-        -- TODO The coersion here is unnecssary if we replace the C numeric types-        -- with their Haskell ones across the board (e.g. CInt -> Int).-        ToCpp -> saysLn ["HoppyP.fmap (HoppyP.toEnum . HoppyFHR.coerceIntegral)"]-        FromCpp -> saysLn ["HoppyP.fmap (HoppyFHR.coerceIntegral . HoppyP.fromEnum)"]-      sayCall-    Internal_TBitspace b -> do-      addImports hsImportForPrelude-      importHsModuleForExtName $ bitspaceExtName b-      saysLn ["HoppyP.fmap ", bitspaceConvFn dir b]-      sayCall-    -- The same as TPtr (TConst (TObj _)), but nonconst.-    Internal_TPtr (Internal_TObj cls) -> do-      addImportForClass cls-      case dir of-        ToCpp -> do-          addImports hsImportForPrelude-          saysLn ["HoppyP.fmap ", toHsDataCtorName Unmanaged Nonconst cls]-          sayCall-        FromCpp -> do-          addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]-          sayLn "HoppyP.fmap HoppyFHR.toPtr"-          sayCall-    -- The same as TPtr (TConst (TObj _)), but nonconst.-    Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> do-      addImportForClass cls-      case dir of-        ToCpp -> do-          addImports hsImportForPrelude-          saysLn ["HoppyP.fmap ", toHsDataCtorName Unmanaged Const cls]-          sayCall-        FromCpp -> do-          addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]-          sayLn "HoppyP.fmap HoppyFHR.toPtr"-          sayCall-    Internal_TPtr _ -> sayCall-    Internal_TRef t' -> sayCallAndProcessReturn dir (ptrT t') callWords-    Internal_TFn {} -> throwError "TFn unimplemented"-    Internal_TCallback cb -> case dir of-      ToCpp -> throwError "Can't receive a callback from C++"-      FromCpp -> do-        addImports $ hsImport1 "Prelude" "(=<<)"-        importHsModuleForExtName $ callbackExtName cb-        saysLn [toHsCallbackCtorName cb, "=<<"]-        sayCall-    Internal_TObj cls -> case dir of-      ToCpp -> case classHaskellConversion $ classConversion cls of-        ClassConversionNone ->-          throwError $ concat-          ["Can't return a TObj of ", show cls,-           " from C++ to Haskell because no class conversion is defined"]-        ClassConversionManual _ -> do-          addImportForClass cls-          addImports $ mconcat [hsImports "Prelude" ["(.)", "(=<<)"],-                                hsImportForRuntime]-          saysLn ["(HoppyFHR.decodeAndDelete . ", toHsDataCtorName Unmanaged Const cls, ") =<<"]-          sayCall-        ClassConversionToHeap -> sayCallAndProcessReturn dir (objToHeapT cls) callWords-        ClassConversionToGc -> sayCallAndProcessReturn dir (toGcT t) callWords-      FromCpp -> do-        addImportForClass cls-        addImports $ mconcat [hsImports "Prelude" ["(.)", "(=<<)"],-                              hsImportForPrelude,-                              hsImportForRuntime]-        sayLn "(HoppyP.fmap (HoppyFHR.toPtr) . HoppyFHR.encode) =<<"-        sayCall-    Internal_TObjToHeap cls -> case dir of-      ToCpp -> sayCallAndProcessReturn dir (ptrT $ objT cls) callWords-      FromCpp -> throwError $ objToHeapTWrongDirectionErrorMsg Nothing cls-    Internal_TToGc t' -> case dir of-      ToCpp -> do-        addImports $ mconcat [hsImport1 "Prelude" "(=<<)",-                              hsImportForRuntime]-        sayLn "HoppyFHR.toGc =<<"-        -- TToGc (TObj _) should create a pointer rather than decoding, so we-        -- change the TObj _ into a TPtr (TObj _).-        case t' of-          Internal_TObj _ -> sayCallAndProcessReturn dir (ptrT t') callWords-          _ -> sayCallAndProcessReturn dir t' callWords-      FromCpp -> throwError $ toGcTWrongDirectionErrorMsg Nothing t'-    Internal_TConst t' -> sayCallAndProcessReturn dir t' callWords-  where sayCall = saysLn $ "(" : callWords ++ [")"]-        sayCoerceIntegral = do addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]-                               sayLn "HoppyP.fmap HoppyFHR.coerceIntegral"-        sayCoerceFloating = do addImports hsImportForPrelude-                               sayLn "HoppyP.fmap HoppyP.realToFrac"-        bitspaceConvFn dir = case dir of-          ToCpp -> toHsBitspaceTypeName-          FromCpp -> toHsBitspaceToNumName--sayExportClass :: SayExportMode -> Class -> Generator ()-sayExportClass mode cls = do-  case mode of-    SayExportForeignImports -> do-      sayExportClassHsCtors mode cls--      forM_ (classMethods cls) $ \method ->-        (sayExportFn mode <$> getClassyExtName cls <*> pure Nothing <*> methodPurity <*>-         pure (getMethodEffectiveParams cls method) <*> methodReturn) method--    SayExportDecls -> do-      sayExportClassHsClass True cls Const-      sayExportClassHsClass True cls Nonconst--      sayExportClassHsStaticMethods cls--      -- Create a newtype for referencing foreign objects with pointers.  The-      -- newtype is not used with encodings of value objects.-      sayExportClassHsType True cls Const-      sayExportClassHsType True cls Nonconst--      sayExportClassHsCtors mode cls--    SayExportBoot -> do-      sayExportClassHsClass False cls Const-      sayExportClassHsClass False cls Nonconst--      sayExportClassHsType False cls Const-      sayExportClassHsType False cls Nonconst--  sayExportClassCastPrimitives mode cls-  sayExportClassHsSpecialFns mode cls--sayExportClassHsClass :: Bool -> Class -> Constness -> Generator ()-sayExportClassHsClass doDecls cls cst = do-  let hsTypeName = toHsDataTypeName cst cls-      hsValueClassName = toHsValueClassName cls-      hsWithValuePtrName = toHsWithValuePtrName cls-      hsPtrClassName = toHsPtrClassName cst cls-      hsCastMethodName = toHsCastMethodName cst cls-      supers = classSuperclasses cls--  forM_ supers $ importHsModuleForExtName . classExtName-  hsSupers <--    (\x -> if null x-           then do addImports hsImportForRuntime-                   return ["HoppyFHR.CppPtr"]-           else return x) $-    case cst of-      Const -> map (toHsPtrClassName Const) supers-      Nonconst -> toHsPtrClassName Const cls : map (toHsPtrClassName Nonconst) supers--  -- Print the value class definition.  There is only one of these, and it is-  -- spiritually closer to the const version of the pointers for this class, so-  -- we emit for the const case only.-  when (cst == Const) $ do-    addImports hsImportForPrelude-    addExport' hsValueClassName-    ln-    saysLn ["class ", hsValueClassName, " a where"]-    indent $-      saysLn [hsWithValuePtrName, " :: a -> (", hsTypeName, " -> HoppyP.IO b) -> HoppyP.IO b"]--    -- Generate instances for all pointer subtypes.-    ln-    saysLn ["#if MIN_VERSION_base(4,8,0)"]-    saysLn ["instance {-# OVERLAPPABLE #-} ", hsPtrClassName, " a => ", hsValueClassName, " a",-            if doDecls then " where" else ""]-    saysLn ["#else"]-    saysLn ["instance ", hsPtrClassName, " a => ", hsValueClassName, " a",-            if doDecls then " where" else ""]-    saysLn ["#endif"]-    when doDecls $ do-      addImports $ mconcat [hsImports "Prelude" ["($)", "(.)"],-                            hsImportForPrelude]-      indent $ saysLn [hsWithValuePtrName, " = HoppyP.flip ($) . ", hsCastMethodName]--    -- When the class has a native Haskell type, also print an instance for it.-    forM_ (getClassHaskellConversion cls) $ \conv -> do-      hsType <- classHaskellConversionType conv-      ln-      saysLn ["#if MIN_VERSION_base(4,8,0)"]-      saysLn ["instance {-# OVERLAPPING #-} ", hsValueClassName, " (", prettyPrint hsType, ")",-              if doDecls then " where" else ""]-      saysLn ["#else"]-      saysLn ["instance ", hsValueClassName, " (", prettyPrint hsType, ")",-              if doDecls then " where" else ""]-      saysLn ["#endif"]-      when doDecls $ do-        addImports hsImportForRuntime-        indent $ saysLn [hsWithValuePtrName, " = HoppyFHR.withCppObj"]--  -- Print the pointer class definition.-  addExport' hsPtrClassName-  ln-  saysLn $-    "class (" :-    intersperse ", " (map (++ " this") hsSupers) ++-    [") => ", hsPtrClassName, " this where"]-  indent $ saysLn [hsCastMethodName, " :: this -> ", hsTypeName]--  -- Print the non-static methods.-  when doDecls $ do-    let methods = filter ((cst ==) . methodConst) $ classMethods cls-    forM_ methods $ \method ->-      when (methodStatic method == Nonstatic) $-      (sayExportFn SayExportDecls <$> getClassyExtName cls <*> pure Nothing <*>-       methodPurity <*> pure (getMethodEffectiveParams cls method) <*>-       methodReturn) method--sayExportClassHsStaticMethods :: Class -> Generator ()-sayExportClassHsStaticMethods cls =-  forM_ (classMethods cls) $ \method ->-    when (methodStatic method == Static) $-    (sayExportFn SayExportDecls <$> getClassyExtName cls <*> pure Nothing <*> methodPurity <*>-     methodParams <*> methodReturn) method--sayExportClassHsType :: Bool -> Class -> Constness -> Generator ()-sayExportClassHsType doDecls cls cst = do-  addImports $ mconcat [hsImportForForeign, hsImportForPrelude, hsImportForRuntime]-  -- Unfortunately, we must export the data constructor, so that GHC can marshal-  -- it in foreign calls in other modules.-  addExport' hsTypeName-  ln-  saysLn ["data ", hsTypeName, " ="]-  indent $ do-    saysLn ["  ", hsCtor, " (HoppyF.Ptr ", hsTypeName, ")"]-    saysLn ["| ", hsCtorGc, " (HoppyF.ForeignPtr ()) (HoppyF.Ptr ", hsTypeName, ")"]-  when doDecls $ do-    addImports $ hsImport1 "Prelude" "(==)"-    indent $ sayLn "deriving (HoppyP.Show)"-    ln-    saysLn ["instance HoppyP.Eq ", hsTypeName, " where"]-    indent $ saysLn ["x == y = HoppyFHR.toPtr x == HoppyFHR.toPtr y"]-    ln-    saysLn ["instance HoppyP.Ord ", hsTypeName, " where"]-    indent $ saysLn ["compare x y = HoppyP.compare (HoppyFHR.toPtr x) (HoppyFHR.toPtr y)"]--  -- Generate const_cast functions:-  --   castFooToConst :: Foo -> FooConst-  --   castFooToNonconst :: FooConst -> Foo-  ln-  let constCastFnName = toHsConstCastFnName cst cls-  addExport constCastFnName-  saysLn [constCastFnName, " :: ", toHsDataTypeName (constNegate cst) cls, " -> ", hsTypeName]-  when doDecls $ do-    addImports $ hsImport1 "Prelude" "($)"-    saysLn [constCastFnName, " (", toHsDataCtorName Unmanaged (constNegate cst) cls,-            " ptr') = ", hsCtor, " $ HoppyF.castPtr ptr'"]-    saysLn [constCastFnName, " (", toHsDataCtorName Managed (constNegate cst) cls,-            " fptr' ptr') = ", hsCtorGc, " fptr' $ HoppyF.castPtr ptr'"]--  -- Generate an instance of CppPtr.-  ln-  if doDecls-    then do addImports $ hsImport1 "Prelude" "($)"-            saysLn ["instance HoppyFHR.CppPtr ", hsTypeName, " where"]-            indent $ do-              saysLn ["nullptr = ", toHsDataCtorName Unmanaged cst cls, " HoppyF.nullPtr"]-              ln-              saysLn ["withCppPtr (", hsCtor, " ptr') f' = f' ptr'"]-              saysLn ["withCppPtr (", hsCtorGc,-                      " fptr' ptr') f' = HoppyF.withForeignPtr fptr' $ \\_ -> f' ptr'"]-              ln-              saysLn ["toPtr (", hsCtor, " ptr') = ptr'"]-              saysLn ["toPtr (", hsCtorGc, " _ ptr') = ptr'"]-              ln-              saysLn ["touchCppPtr (", hsCtor, " _) = HoppyP.return ()"]-              saysLn ["touchCppPtr (", hsCtorGc, " fptr' _) = HoppyF.touchForeignPtr fptr'"]-            when (classDtorIsPublic cls) $ do-              addImports $ hsImport1 "Prelude" "(==)"-              ln-              saysLn ["instance HoppyFHR.Deletable ", hsTypeName, " where"]-              indent $ do-                saysLn $-                  "delete (" : toHsDataCtorName Unmanaged cst cls : " ptr') = " :-                  toHsClassDeleteFnName cls :-                  case cst of-                    Const -> [" ptr'"]-                    Nonconst -> [" $ (HoppyF.castPtr ptr' :: HoppyF.Ptr ",-                                 toHsDataTypeName Const cls, ")"]-                saysLn ["delete (", toHsDataCtorName Managed cst cls,-                        " _ _) = HoppyP.fail $ HoppyP.concat ",-                        "[\"Deletable.delete: Asked to delete a GC-managed \", ",-                        show hsTypeName, ", \" object.\"]"]-                ln-                saysLn ["toGc this'@(", hsCtor, " ptr') = ",-                        -- No sense in creating a ForeignPtr for a null pointer.-                        "if ptr' == HoppyF.nullPtr then HoppyP.return this' else HoppyP.fmap ",-                        "(HoppyP.flip ", hsCtorGc, " ptr') $ ",-                        "HoppyF.newForeignPtr ",-                        -- The foreign delete function takes a const pointer; we cast it to-                        -- take a Ptr () to match up with the ForeignPtr () we're creating,-                        -- assuming that data pointers have the same representation.-                        "(HoppyF.castFunPtr ", toHsClassDeleteFnPtrName cls,-                        " :: HoppyF.FunPtr (HoppyF.Ptr () -> HoppyP.IO ())) ",-                        "(HoppyF.castPtr ptr' :: HoppyF.Ptr ())"]-                saysLn ["toGc this'@(", hsCtorGc, " {}) = HoppyP.return this'"]-    else do saysLn ["instance HoppyFHR.CppPtr ", hsTypeName]-            saysLn ["instance HoppyFHR.Deletable ", hsTypeName]--  -- Generate instances for all superclasses' typeclasses.-  genInstances [] cls--  where hsTypeName :: String-        hsTypeName = toHsDataTypeName cst cls--        hsCtor :: String-        hsCtor = toHsDataCtorName Unmanaged cst cls--        hsCtorGc :: String-        hsCtorGc = toHsDataCtorName Managed cst cls--        genInstances :: [Class] -> Class -> Generator ()-        genInstances path ancestorCls = do-          -- In this example Bar inherits from Foo.  We are generating instances-          -- either for BarConst or Bar, depending on 'cst'.-          ---          -- BarConst's instances:-          --   instance FooConstPtr BarConst where-          --     toFooConst (BarConst ptr') = FooConst $ castBarToFoo ptr'-          --     toFooConst (BarConstGc fptr' ptr') = FooConstGc fptr' $ castBarToFoo ptr'-          ---          --   instance BarConstPtr BarConst where-          --     toFooConst = id-          ---          -- Bar's instances:-          --   instance FooConstPtr Bar-          --     toFooConst (Bar ptr') =-          --       FooConst $ castBarToFoo $ castBarToConst ptr'-          --     toFooConst (BarGc fptr' ptr') =-          --       FooConstGc fptr' $ castBarToFoo $ castBarToConst ptr'-          ---          --   instance FooPtr Bar-          --     toFoo (Bar ptr') =-          --       Foo $ castFooToNonconst $ castBarToFoo $ castBarToConst ptr'-          --     toFoo (BarGc fptr' ptr') =-          --       FooGc fptr' $ castFooToNonconst $ castBarToFoo $ castBarToConst ptr'-          ---          --   instance BarConstPtr Bar-          --     toBarConst (Bar ptr') = Bar $ castBarToConst ptr'-          --     toBarConst (BarGc fptr' ptr') = BarGc fptr' $ castBarToConst ptr'-          ---          --   instance BarPtr Bar-          --     toBar = id-          ---          -- In all cases, we unwrap the pointer, maybe add const, maybe do an-          -- upcast, maybe remove const, then rewrap the pointer.  The identity-          -- cases are where we just unwrap and wrap again.--          addImportForClass ancestorCls-          forM_ (case cst of-                   Const -> [Const]-                   Nonconst -> [Const, Nonconst]) $ \typeclassCst -> do-            saysLn ["instance ", toHsPtrClassName typeclassCst ancestorCls, " ", hsTypeName,-                    if doDecls then " where" else ""]-            when doDecls $ indent $ do-              let castMethodName = toHsCastMethodName typeclassCst ancestorCls-              if null path && cst == typeclassCst-                then do addImports hsImportForPrelude-                        saysLn [castMethodName, " = HoppyP.id"]-                else do let addConst = cst == Nonconst-                            removeConst = typeclassCst == Nonconst-                        when (addConst || removeConst) $-                          addImports hsImportForForeign-                        forM_ ([minBound..] :: [Managed]) $ \managed -> do-                          let ancestorCtor = case managed of-                                Unmanaged -> [toHsDataCtorName Unmanaged typeclassCst ancestorCls]-                                Managed -> [toHsDataCtorName Managed typeclassCst ancestorCls,-                                            " fptr'"]-                              ptrPattern = case managed of-                                Unmanaged -> [toHsDataCtorName Unmanaged cst cls, " ptr'"]-                                Managed -> [toHsDataCtorName Managed cst cls, " fptr' ptr'"]-                          saysLn $ concat-                            [ [castMethodName, " ("], ptrPattern, [") = "], ancestorCtor-                            , if removeConst-                              then [" $ (HoppyF.castPtr :: HoppyF.Ptr ",-                                    toHsDataTypeName Const ancestorCls, " -> HoppyF.Ptr ",-                                    toHsDataTypeName Nonconst ancestorCls, ")"]-                              else []-                            , if not $ null path-                              then [" $ ", toHsCastPrimitiveName cls ancestorCls]-                              else []-                            , if addConst-                              then [" $ (HoppyF.castPtr :: HoppyF.Ptr ",-                                    toHsDataTypeName Nonconst cls, " -> HoppyF.Ptr ",-                                    toHsDataTypeName Const cls, ")"]-                              else []-                            , [" ptr'"]-                            ]--          forM_ (classSuperclasses ancestorCls) $ genInstances $ ancestorCls : path--sayExportClassHsCtors :: SayExportMode -> Class -> Generator ()-sayExportClassHsCtors mode cls =-  forM_ (classCtors cls) $ \ctor ->-  (sayExportFn mode <$> getClassyExtName cls <*> pure Nothing <*>-   pure Nonpure <*> ctorParams <*> pure (ptrT $ objT cls)) ctor--sayExportClassHsSpecialFns :: SayExportMode -> Class -> Generator ()-sayExportClassHsSpecialFns mode cls = do-  let typeName = toHsDataTypeName Nonconst cls-      typeNameConst = toHsDataTypeName Const cls--  -- Say the delete function.-  case mode of-    SayExportForeignImports -> when (classDtorIsPublic cls) $ do-      addImports $ mconcat [hsImportForForeign, hsImportForPrelude]-      saysLn ["foreign import ccall \"", classDeleteFnCppName cls, "\" ",-              toHsClassDeleteFnName cls, " :: HoppyF.Ptr ",-              toHsDataTypeName Const cls, " -> HoppyP.IO ()"]-      saysLn ["foreign import ccall \"&", classDeleteFnCppName cls, "\" ",-              toHsClassDeleteFnPtrName cls, " :: HoppyF.FunPtr (HoppyF.Ptr ",-              toHsDataTypeName Const cls, " -> HoppyP.IO ())"]-    -- The user interface to this is the generic 'delete' function, rendered-    -- elsewhere.-    SayExportDecls -> return ()-    SayExportBoot -> return ()--  case mode of-    SayExportForeignImports -> return ()-    SayExportDecls -> do-      addImports $ mconcat [hsImport1 "Prelude" "($)",-                            hsImportForForeign,-                            hsImportForRuntime]-      ln-      saysLn ["instance HoppyFHR.Assignable (HoppyF.Ptr (HoppyF.Ptr ", typeName, ")) ",-              typeName, " where"]-      indent $ sayLn "assign ptr' value' = HoppyF.poke ptr' $ HoppyFHR.toPtr value'"-    SayExportBoot -> return ()--  -- If the class has an assignment operator that takes its own type, then-  -- generate an instance of Assignable.-  let assignmentMethods = flip filter (classMethods cls) $ \m ->-        methodApplicability m == MNormal &&-        (methodParams m == [objT cls] || methodParams m == [refT $ constT $ objT cls]) &&-        (case methodImpl m of-          RealMethod name -> name == FnOp OpAssign-          FnMethod name -> name == FnOp OpAssign)-      withAssignmentMethod f = case assignmentMethods of-        [] -> return ()-        [m] -> f m-        _ ->-          throwError $ concat-          ["Can't determine an Assignable instance to generator for ", show cls,-          " because it has multiple assignment operators ", show assignmentMethods]-  when (mode == SayExportDecls) $ withAssignmentMethod $ \m -> do-    addImports $ mconcat [hsImport1 "Prelude" "(>>)", hsImportForPrelude]-    ln-    saysLn ["instance ", toHsValueClassName cls, " a => HoppyFHR.Assignable ", typeName,-            " a where"]-    indent $-      saysLn ["assign x' y' = ", toHsFnName $ getClassyExtName cls m,-                " x' y' >> HoppyP.return ()"]--  -- A pointer to an object pointer is decodable to an object pointer by peeking-  -- at the value, so generate a Decodable instance.  You are now a two-star-  -- programmer.  There is a generic @Ptr (Ptr a)@ to @Ptr a@ instance which-  -- handles deeper levels.-  case mode of-    SayExportForeignImports -> return ()--    SayExportDecls -> do-      addImports $ mconcat [hsImport1 "Prelude" "(.)",-                            hsImportForForeign,-                            hsImportForPrelude,-                            hsImportForRuntime]-      ln-      saysLn ["instance HoppyFHR.Decodable (HoppyF.Ptr (HoppyF.Ptr ",-              typeName, ")) ", typeName, " where"]-      indent $-        saysLn ["decode = HoppyP.fmap ",-                toHsDataCtorName Unmanaged Nonconst cls, " . HoppyF.peek"]--    SayExportBoot -> do-      addImports $ mconcat [hsImportForForeign, hsImportForRuntime]-      ln-      -- TODO Encodable.-      saysLn ["instance HoppyFHR.Decodable (HoppyF.Ptr (HoppyF.Ptr ", typeName, ")) ", typeName]--  -- Say Encodable and Decodable instances, if the class is encodable and-  -- decodable.-  forM_ (getClassHaskellConversion cls) $ \conv -> do-    hsType <- classHaskellConversionType conv-    let hsTypeStr = concat ["(", prettyPrint hsType, ")"]-    case mode of-      SayExportForeignImports -> return ()--      SayExportDecls -> do-        addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]--        -- Say the Encodable instances.-        ln-        saysLn ["instance HoppyFHR.Encodable ", typeName, " ", hsTypeStr, " where"]-        indent $ do-          sayLn "encode ="-          indent $ classHaskellConversionToCppFn conv-        ln-        saysLn ["instance HoppyFHR.Encodable ", typeNameConst, " ", hsTypeStr, " where"]-        indent $-          saysLn ["encode = HoppyP.fmap (", toHsCastMethodName Const cls,-                  ") . HoppyFHR.encodeAs (HoppyP.undefined :: ", typeName, ")"]--        -- Say the Decodable instances.-        ln-        saysLn ["instance HoppyFHR.Decodable ", typeName, " ", hsTypeStr, " where"]-        indent $-          saysLn ["decode = HoppyFHR.decode . ", toHsCastMethodName Const cls]-        ln-        saysLn ["instance HoppyFHR.Decodable ", typeNameConst, " ", hsTypeStr, " where"]-        indent $ do-          sayLn "decode ="-          indent $ classHaskellConversionFromCppFn conv--      SayExportBoot -> do-        addImports hsImportForRuntime-        ln-        saysLn ["instance HoppyFHR.Encodable ", typeName, " (", hsTypeStr, ")"]-        saysLn ["instance HoppyFHR.Encodable ", typeNameConst, " (", hsTypeStr, ")"]-        saysLn ["instance HoppyFHR.Decodable ", typeName, " (", hsTypeStr, ")"]-        saysLn ["instance HoppyFHR.Decodable ", typeNameConst, " (", hsTypeStr, ")"]--sayExportClassCastPrimitives :: SayExportMode -> Class -> Generator ()-sayExportClassCastPrimitives mode cls = do-  let clsType = toHsDataTypeName Const cls-  case mode of-    SayExportForeignImports ->-      forAncestors cls $ \super -> do-        let hsCastFnName = toHsCastPrimitiveName cls super-            hsDownCastFnName = toHsCastPrimitiveName super cls-            superType = toHsDataTypeName Const super-        addImports hsImportForForeign-        addExport hsCastFnName-        saysLn [ "foreign import ccall \"", classCastFnCppName cls super-               , "\" ", hsCastFnName, " :: HoppyF.Ptr ", clsType, " -> HoppyF.Ptr ", superType-               ]-        unless (classIsSubclassOfMonomorphic cls || classIsMonomorphicSuperclass super) $ do-          addExport hsDownCastFnName-          saysLn [ "foreign import ccall \"", classCastFnCppName super cls-                 , "\" ", hsDownCastFnName, " :: HoppyF.Ptr ", superType, " -> HoppyF.Ptr ", clsType-                 ]-        return True--    SayExportDecls ->-      -- Generate a downcast typeclass and instances for all ancestor classes-      -- for the current constness.  These don't need to be in the boot file,-      -- since they're not used by other generated bindings.-      unless (classIsSubclassOfMonomorphic cls) $-      forM_ [minBound..] $ \cst -> do-        let downCastClassName = toHsDownCastClassName cst cls-            downCastMethodName = toHsDownCastMethodName cst cls-        addExport' downCastClassName-        ln-        saysLn ["class ", downCastClassName, " a where"]-        indent $ saysLn [downCastMethodName, " :: ",-                         prettyPrint $ HsTyFun (HsTyVar $ HsIdent "a") $-                         HsTyCon $ UnQual $ HsIdent $ toHsDataTypeName cst cls]-        ln-        forAncestors cls $ \super -> case classIsMonomorphicSuperclass super of-          True -> return False-          False -> do-            let superTypeName = toHsDataTypeName cst super-                primitiveCastFn = toHsCastPrimitiveName super cls-            addImportForClass super-            saysLn ["instance ", downCastClassName, " ", superTypeName, " where"]--            -- If Foo is a superclass of Bar:-            ---            -- instance BarSuper Foo where-            --   downToBar castFooToNonconst . downcast' . castFooToConst-            --     where downcast' (FooConst ptr') = BarConst $ castFooToBar ptr'-            --           downcast' (FooConstGc fptr' ptr') = BarConstGc fptr' $ castFooToBar ptr'-            ---            -- instance BarSuperConst FooConst where-            --   downToBarConst = downcast'-            --     where downcast' (FooConst ptr') = BarConst $ castFooToBar ptr'-            --           downcast' (FooConstGc fptr' ptr') = BarConstGc fptr' $ castFooToBar ptr'--            indent $ do-              saysLn $-                downCastMethodName : " = " :-                case cst of-                  Const -> ["cast'"]-                  Nonconst -> [toHsConstCastFnName Nonconst cls,-                               " . cast' . ",-                               toHsConstCastFnName Const super]-              indent $ do-                sayLn "where"-                indent $ do-                  saysLn ["cast' (", toHsDataCtorName Unmanaged Const super, " ptr') = ",-                          toHsDataCtorName Unmanaged Const cls, " $ ",-                          primitiveCastFn, " ptr'"]-                  saysLn ["cast' (", toHsDataCtorName Managed Const super, " fptr' ptr') = ",-                          toHsDataCtorName Managed Const cls, " fptr' $ ",-                          primitiveCastFn, " ptr'"]-            return True--    SayExportBoot -> do-      forAncestors cls $ \super -> do-        let hsCastFnName = toHsCastPrimitiveName cls super-            superType = toHsDataTypeName Const super-        addImports $ hsImportForForeign-        addExport hsCastFnName-        saysLn [hsCastFnName, " :: HoppyF.Ptr ", clsType, " -> HoppyF.Ptr ", superType]-        return True--  where forAncestors :: Class -> (Class -> Generator Bool) -> Generator ()-        forAncestors cls' f = forM_ (classSuperclasses cls') $ \super -> do-          recur <- f super-          when recur $ forAncestors super f---- | Implements special logic on top of 'cppTypeToHsTypeAndUse', that computes--- the Haskell __qualified__ type for a function, including typeclass--- constraints.-fnToHsTypeAndUse :: HsTypeSide-                 -> Maybe (Constness, Class)-                 -> Purity-                 -> [Type]-                 -> Type-                 -> Generator HsQualType-fnToHsTypeAndUse side methodInfo purity paramTypes returnType = do-  params <- mapM contextForParam $-            (case methodInfo of-                Just (cst, cls) -> [("this", case cst of-                                        Nonconst -> ptrT $ objT cls-                                        Const -> ptrT $ constT $ objT cls)]-                Nothing -> []) ++-            zip (map toArgName [1..]) paramTypes-  let context = mapMaybe fst params :: HsContext-      hsParams = map snd params--  -- Determine the 'HsHsSide' return type for the function.  If the function is-  -- returning a 'TObj' of a class that uses 'ClassConversionToHeap' or-  -- 'ClassConversionToGc', then first we wrap the return type.  Then we do the-  -- conversion to a Haskell type, and wrap the result in 'IO' if the function-  -- is impure.  (HsCSide types always get wrapped in IO.)-  returnForGc <- case returnType of-    Internal_TObj cls -> case classHaskellConversion $ classConversion cls of-      ClassConversionNone ->-        throwError $ concat ["Expected ", show cls, " to be returnable from a C++ function"]-      ClassConversionManual _ -> return returnType-      ClassConversionToHeap -> return $ objToHeapT cls-      ClassConversionToGc -> return $ toGcT returnType-    _ -> return returnType-  hsReturnForGc <- cppTypeToHsTypeAndUse side returnForGc-  hsReturnForPurity <- case (purity, side) of-    (Pure, HsHsSide) -> return hsReturnForGc-    _ -> do-      addImports hsImportForPrelude-      return $ HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") hsReturnForGc--  return $ HsQualType context $ foldr HsTyFun hsReturnForPurity hsParams--  where contextForParam :: (String, Type) -> Generator (Maybe HsAsst, HsType)-        contextForParam (s, t) = case t of-          Internal_TBitspace b -> receiveBitspace s t b-          Internal_TPtr (Internal_TObj cls) -> receivePtr s cls Nonconst-          Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> receiveValue s t cls-          Internal_TRef (Internal_TObj cls) -> receivePtr s cls Nonconst-          Internal_TRef (Internal_TConst (Internal_TObj cls)) -> receiveValue s t cls-          Internal_TObj cls -> receiveValue s t cls-          Internal_TConst t' -> contextForParam (s, t')-          _ -> handoff side t--        -- Use whatever type 'cppTypeToHsTypeAndUse' suggests, with no typeclass-        -- constraints.-        handoff :: HsTypeSide -> Type -> Generator (Maybe HsAsst, HsType)-        handoff side t = (,) Nothing <$> cppTypeToHsTypeAndUse side t--        -- Receives a @IsFooBitspace a => a@.-        receiveBitspace s t b = case side of-          HsCSide -> handoff side t-          HsHsSide -> do-            importHsModuleForExtName $ bitspaceExtName b-            let t' = HsTyVar $ HsIdent s-            return (Just (UnQual $ HsIdent $ toHsBitspaceClassName b, [t']),-                    t')--        -- Receives a @FooPtr this => this@.-        receivePtr :: String -> Class -> Constness -> Generator (Maybe HsAsst, HsType)-        receivePtr s cls cst = do-          addImportForClass cls-          case side of-            HsHsSide -> do-              let t' = HsTyVar $ HsIdent s-              return (Just (UnQual $ HsIdent $ toHsPtrClassName cst cls, [t']),-                      t')-            HsCSide -> do-              addImports $ hsImportForForeign-              return (Nothing, HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.Ptr") $-                               HsTyVar $ HsIdent $ toHsDataTypeName cst cls)--        -- Receives a @FooValue a => a@.-        receiveValue :: String -> Type -> Class -> Generator (Maybe HsAsst, HsType)-        receiveValue s t cls = case side of-          HsCSide -> handoff side t-          HsHsSide -> do-            addImports hsImportForRuntime-            addImportForClass cls-            let t' = HsTyVar $ HsIdent s-            return (Just (UnQual $ HsIdent $ toHsValueClassName cls, [t']),-                    t')--getMethodEffectiveParams :: Class -> Method -> [Type]-getMethodEffectiveParams cls method =-  (case methodImpl method of-     RealMethod {} -> case methodApplicability method of-       MNormal -> (ptrT (objT cls):)-       MConst -> (ptrT (constT $ objT cls):)-       MStatic -> id-     FnMethod {} -> id) $-  methodParams method---- | Imports bindings for the given class into the Haskell module.-addImportForClass :: Class -> Generator ()-addImportForClass = importHsModuleForExtName . classExtName+import Control.Arrow ((&&&))+import Control.Monad (forM, unless, when)+#if MIN_VERSION_mtl(2,2,1)+import Control.Monad.Except (throwError)+#else+import Control.Monad.Error (throwError)+#endif+import Control.Monad.Trans (lift)+import Control.Monad.Writer (execWriterT, tell)+import Data.Foldable (forM_)+import Data.Graph (SCC (AcyclicSCC, CyclicSCC), stronglyConnComp)+import Data.List (intersperse)+import qualified Data.Map as M+import Data.Maybe (mapMaybe)+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (mconcat, mempty)+#endif+import qualified Data.Set as S+import Foreign.Hoppy.Generator.Common+import Foreign.Hoppy.Generator.Spec+import Foreign.Hoppy.Generator.Types+import Foreign.Hoppy.Generator.Language.Cpp (+  classCastFnCppName,+  classDeleteFnCppName,+  externalNameToCpp,+  )+import Foreign.Hoppy.Generator.Language.Haskell+import Language.Haskell.Syntax (+  HsAsst,+  HsContext,+  HsName (HsIdent),+  HsQName (Special, UnQual),+  HsQualType (HsQualType),+  HsSpecialCon (HsUnitCon),+  HsType (HsTyApp, HsTyCon, HsTyFun, HsTyVar),+  )+import System.FilePath ((<.>), pathSeparator)++-- | The in-memory result of generating Haskell code for an interface.+data Generation = Generation+  { generatedFiles :: M.Map FilePath String+    -- ^ A map from paths of generated files to the contents of those files.+    -- The file paths are relative paths below the Haskell generation root.+  }++-- | Runs the C++ code generator against an interface.+generate :: Interface -> Either ErrorMsg Generation+generate iface = do+  -- Build the partial generation of each module.+  modPartials <- forM (M.elems $ interfaceModules iface) $ \m ->+    (,) m <$> execGenerator iface m (generateSource m)++  -- Compute the strongly connected components.  If there is a nontrivial SCC,+  -- then there is a module import cycle that we'll have to break with hs-boot+  -- files.+  let partialsByHsName :: M.Map HsModuleName Partial+      partialsByHsName = M.fromList $ map ((partialModuleHsName &&& id) . snd) modPartials++      sccInput :: [((Module, Partial), Partial, [Partial])]+      sccInput = for modPartials $ \x@(_, p) ->+        (x, p,+         mapMaybe (flip M.lookup partialsByHsName . hsImportModule) $+         M.keys $ getHsImportSet $ outputImports $ partialOutput p)++      sccs :: [SCC (Module, Partial)]+      sccs = stronglyConnComp sccInput++  fileContents <- execWriterT $ forM_ sccs $ \scc -> case scc of+    AcyclicSCC (_, p) -> tell [finishPartial p "hs"]+    CyclicSCC mps -> do+      let cycleModNames = S.fromList $ map (partialModuleHsName . snd) mps+      forM_ mps $ \(m, p) -> do+        -- Create a boot partial.+        pBoot <- lift $ execGenerator iface m (generateBootSource m)++        -- Change the source and boot partials so that all imports of modules in+        -- this cycle are {-# SOURCE #-} imports.+        let p' = setSourceImports cycleModNames p+            pBoot' = setSourceImports cycleModNames pBoot++        -- Emit the completed partials.+        tell [finishPartial p' "hs", finishPartial pBoot' "hs-boot"]++  return $ Generation $ M.fromList fileContents++  where finishPartial :: Partial -> String -> (FilePath, String)+        finishPartial p fileExt =+          (listSubst '.' pathSeparator (partialModuleHsName p) <.> fileExt,+           prependExtensions $ renderPartial p)++        setSourceImports :: S.Set HsModuleName -> Partial -> Partial+        setSourceImports modulesToSourceImport p =+          let output = partialOutput p+              imports = outputImports output+              imports' = makeHsImportSet $+                         M.mapWithKey (setSourceImportIfIn modulesToSourceImport) $+                         getHsImportSet imports+              output' = output { outputImports = imports' }+          in p { partialOutput = output' }++        setSourceImportIfIn :: S.Set HsModuleName -> HsImportKey -> HsImportSpecs -> HsImportSpecs+        setSourceImportIfIn modulesToSourceImport key specs =+          if hsImportModule key `S.member` modulesToSourceImport+          then specs { hsImportSource = True }+          else specs++prependExtensions :: String -> String+prependExtensions = (prependExtensionsPrefix ++)++prependExtensionsPrefix :: String+prependExtensionsPrefix =+  -- MultiParamTypeClasses is necessary for instances of Decodable and+  -- Encodable.  FlexibleContexts is needed for the type signature of the+  -- function that wraps the actual callback function in callback creation+  -- functions.+  --+  -- FlexibleInstances and TypeSynonymInstances are enabled to allow conversions+  -- to and from String, which is really [Char].+  --+  -- UndecidableInstances is needed for instances of the form "SomeClassConstPtr+  -- a => SomeClassValue a", and overlapping instances are used for the overlap+  -- between these instances and instances of SomeClassValue for the class's+  -- native Haskell type, when it's convertible.  CPP is used for warning-free+  -- compatibility using overlapping instances with both GHC 7.8 and 7.10.+  --+  -- GeneralizedNewtypeDeriving is to enable automatic deriving of+  -- Data.Bits.Bits instances for bitspace newtypes.+  concat+  [ "{-# LANGUAGE CPP, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving"+  , ", MultiParamTypeClasses, ScopedTypeVariables, TypeSynonymInstances, UndecidableInstances #-}\n"+  , "#if !MIN_VERSION_base(4,8,0)\n"+  , "{-# LANGUAGE OverlappingInstances #-}\n"+  , "#endif\n\n"+  ]++generateSource :: Module -> Generator ()+generateSource m = do+  forM_ (moduleExports m) $ sayExport SayExportForeignImports+  forM_ (moduleExports m) $ sayExport SayExportDecls++  iface <- askInterface+  when (interfaceExceptionSupportModule iface == Just m) $+    sayExceptionSupport True++  addendumHaskell $ getAddendum m++generateBootSource :: Module -> Generator ()+generateBootSource m = do+  forM_ (moduleExports m) $ sayExport SayExportBoot++  iface <- askInterface+  when (interfaceExceptionSupportModule iface == Just m) $+    sayExceptionSupport False++data SayExportMode = SayExportForeignImports | SayExportDecls | SayExportBoot+                   deriving (Eq, Show)++sayExport :: SayExportMode -> Export -> Generator ()+sayExport mode export = do+  case export of+    ExportVariable v -> sayExportVar mode v+    ExportEnum enum -> sayExportEnum mode enum+    ExportBitspace bitspace -> sayExportBitspace mode bitspace+    ExportFn fn ->+      (sayExportFn mode <$> fnExtName <*> fnExtName <*> fnPurity <*>+       fnParams <*> fnReturn <*> fnExceptionHandlers) fn+    ExportClass cls -> sayExportClass mode cls+    ExportCallback cb -> sayExportCallback mode cb++  when (mode == SayExportDecls) $+    addendumHaskell $ exportAddendum export++sayExportVar :: SayExportMode -> Variable -> Generator ()+sayExportVar mode v = withErrorContext ("generating variable " ++ show (varExtName v)) $ do+  let getterName = varGetterExtName v+      setterName = varSetterExtName v+  sayExportVar' mode (varType v) Nothing True getterName getterName setterName setterName++sayExportClassVar :: SayExportMode -> Class -> ClassVariable -> Generator ()+sayExportClassVar mode cls v =+  withErrorContext ("generating variable " ++ show (classVarExtName v)) $+  sayExportVar' mode+                (classVarType v)+                (case classVarStatic v of+                   Nonstatic -> Just cls+                   Static -> Nothing)+                (classVarGettable v)+                (classVarGetterExtName cls v)+                (classVarGetterForeignName cls v)+                (classVarSetterExtName cls v)+                (classVarSetterForeignName cls v)++sayExportVar' :: SayExportMode+              -> Type+              -> Maybe Class+              -> Bool+              -> ExtName+              -> ExtName+              -> ExtName+              -> ExtName+              -> Generator ()+sayExportVar' mode+              t+              classIfNonstatic+              gettable+              getterExtName+              getterForeignName+              setterExtName+              setterForeignName = do+  let (isConst, deconstType) = case t of+        Internal_TConst t -> (True, t)+        t -> (False, t)++  when gettable $+    sayExportFn mode+                getterExtName+                getterForeignName+                Nonpure+                (maybe [] (\cls -> [ptrT $ constT $ objT cls]) classIfNonstatic)+                deconstType+                mempty++  unless isConst $+    sayExportFn mode+                setterExtName+                setterForeignName+                Nonpure+                (maybe [deconstType] (\cls -> [ptrT $ objT cls, deconstType])+                       classIfNonstatic)+                voidT+                mempty++sayExportEnum :: SayExportMode -> CppEnum -> Generator ()+sayExportEnum mode enum =+  withErrorContext ("generating enum " ++ show (enumExtName enum)) $+  case mode of+    -- Nothing to import from the C++ side of an enum.+    SayExportForeignImports -> return ()++    SayExportDecls -> do+      hsTypeName <- toHsEnumTypeName enum+      values <- forM (enumValueNames enum) $ \(value, name) -> do+        ctorName <- toHsEnumCtorName enum name+        return (value, ctorName)+      addImports $ mconcat [hsImports "Prelude" ["($)", "(++)"], hsImportForPrelude]++      -- Print out the data declaration.+      ln+      addExport' hsTypeName+      saysLn ["data ", hsTypeName, " ="]+      indent $ do+        forM_ (zip (False:repeat True) values) $ \(cont, (_, hsCtorName)) ->+          saysLn [if cont then "| " else "", hsCtorName]+        sayLn "deriving (HoppyP.Bounded, HoppyP.Eq, HoppyP.Ord, HoppyP.Show)"++      -- Print out the Enum instance.+      ln+      saysLn ["instance HoppyP.Enum ", hsTypeName, " where"]+      indent $ do+        forM_ values $ \(num, hsCtorName) ->+          saysLn ["fromEnum ", hsCtorName, " = ", show num]+        ln+        forM_ values $ \(num, hsCtorName) ->+          saysLn ["toEnum (", show num, ") = ", hsCtorName]+        saysLn ["toEnum n' = HoppyP.error $ ",+                show (concat ["Unknown ", hsTypeName, " numeric value: "]),+                " ++ HoppyP.show n'"]++    SayExportBoot -> do+      hsTypeName <- toHsEnumTypeName enum+      addImports hsImportForPrelude+      addExport hsTypeName+      ln+      saysLn ["data ", hsTypeName]+      saysLn ["instance HoppyP.Bounded ", hsTypeName]+      saysLn ["instance HoppyP.Enum ", hsTypeName]+      saysLn ["instance HoppyP.Eq ", hsTypeName]+      saysLn ["instance HoppyP.Ord ", hsTypeName]+      saysLn ["instance HoppyP.Show ", hsTypeName]++sayExportBitspace :: SayExportMode -> Bitspace -> Generator ()+sayExportBitspace mode bitspace =+  withErrorContext ("generating bitspace " ++ show (bitspaceExtName bitspace)) $ do+  hsTypeName <- toHsBitspaceTypeName bitspace+  fromFnName <- toHsBitspaceToNumName bitspace+  className <- toHsBitspaceClassName bitspace+  toFnName <- toHsBitspaceFromValueName bitspace+  let hsType = HsTyCon $ UnQual $ HsIdent hsTypeName+  case mode of+    -- Nothing to import from the C++ side of a bitspace.+    SayExportForeignImports -> return ()++    SayExportDecls -> do+      values <- forM (bitspaceValueNames bitspace) $ \(value, name) -> do+        bindingName <- toHsBitspaceValueName bitspace name+        return (value, bindingName)++      hsCNumType <- cppTypeToHsTypeAndUse HsCSide $ bitspaceType bitspace+      hsHsNumType <- cppTypeToHsTypeAndUse HsHsSide $ bitspaceType bitspace++      -- Print out the data declaration and conversion functions.+      addImports $ mconcat [hsImportForBits, hsImportForPrelude, hsImportForRuntime]+      addExport' hsTypeName+      addExport' className+      ln+      saysLn ["newtype ", hsTypeName, " = ", hsTypeName, " { ",+              fromFnName, " :: ", prettyPrint hsCNumType, " }"]+      indent $ sayLn "deriving (HoppyDB.Bits, HoppyP.Bounded, HoppyP.Eq, HoppyP.Ord, HoppyP.Show)"+      ln+      saysLn ["class ", className, " a where"]+      indent $ do+        let tyVar = HsTyVar $ HsIdent "a"+        saysLn [toFnName, " :: ", prettyPrint $ HsTyFun tyVar hsType]+      ln+      saysLn ["instance ", className, " (", prettyPrint hsCNumType, ") where"]+      indent $ saysLn [toFnName, " = ", hsTypeName]+      saysLn ["instance ", className, " (", prettyPrint hsHsNumType, ") where"]+      indent $ saysLn [toFnName, " = ", hsTypeName, " . HoppyFHR.coerceIntegral"]+      saysLn ["instance ", className, " ", hsTypeName, " where"]+      indent $ saysLn [toFnName, " = HoppyP.id"]++      -- If the bitspace has an associated enum, then print out a conversion+      -- instance for it as well.+      forM_ (bitspaceEnum bitspace) $ \enum -> do+        enumTypeName <- toHsEnumTypeName enum+        addImports $ mconcat [hsImport1 "Prelude" "(.)", hsImportForPrelude, hsImportForRuntime]+        ln+        saysLn ["instance ", className, " ", enumTypeName, " where"]+        indent $+          saysLn [toFnName, " = ", hsTypeName, " . HoppyFHR.coerceIntegral . HoppyP.fromEnum"]++      -- Print out the constants.+      ln+      forM_ values $ \(num, valueName) -> do+        addExport valueName+        saysLn [valueName, " = ", hsTypeName, " ", show num]++    SayExportBoot -> do+      hsCNumType <- cppTypeToHsTypeAndUse HsCSide $ bitspaceType bitspace+      hsHsNumType <- cppTypeToHsTypeAndUse HsHsSide $ bitspaceType bitspace++      addImports $ mconcat [hsImportForBits, hsImportForPrelude]+      addExport' hsTypeName+      addExport' className+      ln+      saysLn ["newtype ", hsTypeName, " = ", hsTypeName, " { ",+              fromFnName, " :: ", prettyPrint hsCNumType, " }"]+      ln+      saysLn ["instance HoppyDB.Bits ", hsTypeName]+      saysLn ["instance HoppyP.Bounded ", hsTypeName]+      saysLn ["instance HoppyP.Eq ", hsTypeName]+      saysLn ["instance HoppyP.Ord ", hsTypeName]+      saysLn ["instance HoppyP.Show ", hsTypeName]+      ln+      saysLn ["class ", className, " a where"]+      indent $ do+        let tyVar = HsTyVar $ HsIdent "a"+        saysLn [toFnName, " :: ", prettyPrint $ HsTyFun tyVar hsType]+      ln+      saysLn ["instance ", className, " (", prettyPrint hsCNumType, ")"]+      saysLn ["instance ", className, " (", prettyPrint hsHsNumType, ")"]+      saysLn ["instance ", className, " ", hsTypeName]+      forM_ (bitspaceEnum bitspace) $ \enum -> do+        enumTypeName <- toHsEnumTypeName enum+        saysLn ["instance ", className, " ", enumTypeName]++sayExportFn :: SayExportMode+            -> ExtName+            -> ExtName+            -> Purity+            -> [Type]+            -> Type+            -> ExceptionHandlers+            -> Generator ()+sayExportFn mode extName foreignName purity paramTypes retType exceptionHandlers = do+  effectiveHandlers <- getEffectiveExceptionHandlers exceptionHandlers+  let handlerList = exceptionHandlersList effectiveHandlers+      catches = not $ null handlerList++  -- We use the pure version of toHsFnName here; because foreignName isn't an+  -- ExtName present in the interface's lookup table, toHsFnName would bail on+  -- it.  Since functions don't reference each other (e.g. we don't put anything+  -- in .hs-boot files for them in circular modules cases), this isn't a problem.+  let hsFnName = toHsFnName' foreignName+      hsFnImportedName = hsFnName ++ "'"++  case mode of+    SayExportForeignImports ->+      withErrorContext ("generating imports for function " ++ show extName) $ do+        -- Print a "foreign import" statement.+        hsCType <- fnToHsTypeAndUse HsCSide purity paramTypes retType effectiveHandlers+        saysLn ["foreign import ccall \"", externalNameToCpp extName, "\" ", hsFnImportedName,+                " :: ", prettyPrint hsCType]++    SayExportDecls -> withErrorContext ("generating function " ++ show extName) $ do+      -- Print the type signature.+      ln+      addExport hsFnName+      hsHsType <- fnToHsTypeAndUse HsHsSide purity paramTypes retType effectiveHandlers+      saysLn [hsFnName, " :: ", prettyPrint hsHsType]++      case purity of+        Nonpure -> return ()+        Pure -> saysLn ["{-# NOINLINE ", hsFnName, " #-}"]++      -- Print the function body.+      let argNames = map toArgName [1..length paramTypes]+          convertedArgNames = map (++ "'") argNames+      -- Operators on this line must bind more weakly than operators used below,+      -- namely ($) and (>>=).  (So finish the line with ($).)+      lineEnd <- case purity of+        Nonpure -> return [" ="]+        Pure -> do addImports $ mconcat [hsImport1 "Prelude" "($)", hsImportForUnsafeIO]+                   return [" = HoppySIU.unsafePerformIO $"]+      saysLn $ hsFnName : map (' ':) argNames ++ lineEnd+      indent $ do+        forM_ (zip3 paramTypes argNames convertedArgNames) $ \(t, argName, argName') ->+          sayArgProcessing ToCpp t argName argName'++        when catches $ do+          iface <- askInterface+          currentModule <- askModule+          let exceptionSupportModule = interfaceExceptionSupportModule iface+          when (exceptionSupportModule /= Just currentModule) $+            addImports . hsWholeModuleImport . getModuleName iface =<<+            fromMaybeM (throwError "Internal error, an exception support module is not available")+            exceptionSupportModule+          addImports $ mconcat [hsImport1 "Prelude" "($)", hsImportForRuntime]+          sayLn "HoppyFHR.internalHandleExceptions exceptionDb' $"++        let callWords = hsFnImportedName : map (' ':) convertedArgNames+        sayCallAndProcessReturn ToCpp retType callWords++    SayExportBoot ->+      -- Functions (methods included) cannot be referenced from other exports,+      -- so we don't need to emit anything.+      --+      -- If this changes, revisit the comment on hsFnName above.+      return ()++-- | Prints \"foreign import\" statements and an internal callback construction+-- function for a given 'Callback' specification.  For example, for a callback+-- of 'HsHsSide' type @Int -> String -> IO Int@, we will generate the following+-- bindings:+--+-- > foreign import ccall "wrapper" name'newFunPtr+-- >   :: (CInt -> Ptr CChar -> IO CInt)+-- >   -> IO (FunPtr (CInt -> Ptr CChar -> IO CInt))+-- >+-- > -- (This is an ad-hoc generated binding for C++ callback impl class constructor.)+-- > foreign import ccall "genpop__name_impl" name'newCallback+-- >   :: FunPtr (CInt -> Ptr CChar -> IO CInt)+-- >   -> FunPtr (FunPtr (IO ()) -> IO ())+-- >   -> Bool+-- >   -> IO (CCallback (CInt -> Ptr CChar -> IO CInt))+-- >+-- > name_newFunPtr :: (Int -> String -> IO Int) -> IO (FunPtr (CInt -> Ptr CChar -> IO CInt))+-- > name_newFunPtr f'hs = name'newFunPtr $ \excIdPtr excPtrPtr arg1 arg2 ->+-- >   internalHandleCallbackExceptions excIdPtr excPtrPtr $+-- >   coerceIntegral arg1 >>= \arg1' ->+-- >   (...decode the C string) >>= \arg2' ->+-- >   fmap coerceIntegral+-- >   (f'hs arg1' arg2')+-- >+-- > name_new :: (Int -> String -> IO Int) -> IO (CCallback (CInt -> Ptr CChar -> IO CInt))+-- > name_new f = do+-- >   f'p <- name_newFunPtr f+-- >   name'newCallback f'p freeHaskellFunPtrFunPtr False+sayExportCallback :: SayExportMode -> Callback -> Generator ()+sayExportCallback mode cb =+  withErrorContext ("generating callback " ++ show (callbackExtName cb)) $ do+    let name = callbackExtName cb+        paramTypes = callbackParams cb+        retType = callbackReturn cb+    hsNewFunPtrFnName <- toHsCallbackNewFunPtrFnName cb+    hsCtorName <- toHsCallbackCtorName cb+    let hsCtorName'newCallback = hsCtorName ++ "'newCallback"+        hsCtorName'newFunPtr = hsCtorName ++ "'newFunPtr"++    hsFnCType <- cppTypeToHsTypeAndUse HsCSide =<< callbackToTFn HsCSide cb+    hsFnHsType <- cppTypeToHsTypeAndUse HsHsSide =<< callbackToTFn HsHsSide cb++    let getWholeNewFunPtrFnType = do+          addImports $ mconcat [hsImportForForeign, hsImportForPrelude]+          return $+            HsTyFun hsFnHsType $+            HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $+            HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") hsFnCType+        getWholeCtorType = do+          addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]+          return $+            HsTyFun hsFnHsType $+            HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $+            HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyFHR.CCallback") hsFnCType++    case mode of+      SayExportForeignImports -> do+        addImports $ mconcat [hsImportForForeign, hsImportForPrelude, hsImportForRuntime]+        let hsFunPtrType = HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") hsFnCType+            hsFunPtrImportType =+              HsTyFun hsFnCType $+              HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") hsFunPtrType+            hsCallbackCtorImportType =+              HsTyFun hsFunPtrType $+              HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") $+                       HsTyFun (HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.FunPtr") $+                                HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $+                                HsTyCon $ Special HsUnitCon) $+                       HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $+                       HsTyCon $ Special HsUnitCon) $+              HsTyFun (HsTyCon $ UnQual $ HsIdent "HoppyP.Bool") $+              HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") $+              HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyFHR.CCallback") hsFnCType++        saysLn ["foreign import ccall \"wrapper\" ", hsCtorName'newFunPtr, " :: ",+                prettyPrint hsFunPtrImportType]+        saysLn ["foreign import ccall \"", externalNameToCpp name, "\" ",+                hsCtorName'newCallback, " :: ", prettyPrint hsCallbackCtorImportType]++      SayExportDecls -> do+        addExports [hsNewFunPtrFnName, hsCtorName]++        wholeNewFunPtrFnType <- getWholeNewFunPtrFnType+        let paramCount = length paramTypes+            argNames = map toArgName [1..paramCount]+            argNames' = map (++ "'") argNames+        throws <- getEffectiveCallbackThrows cb+        addImports $ mconcat [hsImport1 "Prelude" "($)",+                              hsImportForRuntime]+        ln+        saysLn [hsNewFunPtrFnName, " :: ", prettyPrint wholeNewFunPtrFnType]+        saysLn $ hsNewFunPtrFnName : " f'hs = " : hsCtorName'newFunPtr : " $" :+          case (if throws then (["excIdPtr", "excPtrPtr"] ++) else id) argNames of+            [] -> []+            argNames' -> [" \\", unwords argNames', " ->"]+        indent $ do+          when throws $ sayLn "HoppyFHR.internalHandleCallbackExceptions excIdPtr excPtrPtr $"+          forM_ (zip3 paramTypes argNames argNames') $ \(t, argName, argName') ->+            sayArgProcessing FromCpp t argName argName'+          sayCallAndProcessReturn FromCpp retType $+            "f'hs" : map (' ':) argNames'++        wholeCtorType <- getWholeCtorType+        ln+        saysLn [hsCtorName, " :: ", prettyPrint wholeCtorType]+        saysLn [hsCtorName, " f'hs = do"]+        indent $ do+          saysLn ["f'p <- ", hsNewFunPtrFnName, " f'hs"]+          saysLn [hsCtorName'newCallback, " f'p HoppyFHR.freeHaskellFunPtrFunPtr HoppyP.False"]++      SayExportBoot -> do+        addExports [hsNewFunPtrFnName, hsCtorName]+        wholeNewFunPtrFnType <- getWholeNewFunPtrFnType+        wholeCtorType <- getWholeCtorType+        ln+        saysLn [hsNewFunPtrFnName, " :: ", prettyPrint wholeNewFunPtrFnType]+        ln+        saysLn [hsCtorName, " :: ", prettyPrint wholeCtorType]++data CallDirection =+  ToCpp  -- ^ Haskell code is calling out to C++.+  | FromCpp  -- ^ C++ is invoking a callback.++sayArgProcessing :: CallDirection -> Type -> String -> String -> Generator ()+sayArgProcessing dir t fromVar toVar =+  withErrorContext ("processing argument of type " ++ show t) $+  case t of+    Internal_TVoid -> throwError $ "TVoid is not a valid argument type"+    Internal_TBool -> case dir of+      ToCpp -> saysLn ["let ", toVar, " = if ", fromVar, " then 1 else 0 in"]+      FromCpp -> do addImports $ hsImport1 "Prelude" "(/=)"+                    saysLn ["let ", toVar, " = ", fromVar, " /= 0 in"]+    Internal_TChar -> noConversion+    Internal_TUChar -> noConversion+    Internal_TShort -> noConversion+    Internal_TUShort -> noConversion+    Internal_TInt -> sayCoerceIntegral+    Internal_TUInt -> noConversion+    Internal_TLong -> noConversion+    Internal_TULong -> noConversion+    Internal_TLLong -> noConversion+    Internal_TULLong -> noConversion+    Internal_TFloat -> sayCoerceFloating+    Internal_TDouble -> sayCoerceFloating+    Internal_TInt8 -> noConversion+    Internal_TInt16 -> noConversion+    Internal_TInt32 -> noConversion+    Internal_TInt64 -> noConversion+    Internal_TWord8 -> noConversion+    Internal_TWord16 -> noConversion+    Internal_TWord32 -> noConversion+    Internal_TWord64 -> noConversion+    Internal_TPtrdiff -> noConversion+    Internal_TSize -> noConversion+    Internal_TSSize -> noConversion+    Internal_TEnum _ -> do+      addImports $ mconcat [hsImport1 "Prelude" "($)", hsImportForPrelude, hsImportForRuntime]+      saysLn ["let ", toVar,+              -- TODO The coersion here is unnecssary if we replace the C numeric+              -- types with their Haskell ones across the board (e.g. CInt ->+              -- Int).+              case dir of+                ToCpp -> " = HoppyFHR.coerceIntegral $ HoppyP.fromEnum "+                FromCpp -> " = HoppyP.toEnum $ HoppyFHR.coerceIntegral ",+              fromVar, " in"]+    Internal_TBitspace b -> case dir of+      ToCpp -> do+        toNumName <- toHsBitspaceToNumName b+        fromValueName <- toHsBitspaceFromValueName b+        saysLn ["let ", toVar, " = ", toNumName, " $ ", fromValueName, " ", fromVar, " in"]+      FromCpp -> do+        typeName <- toHsBitspaceTypeName b+        saysLn ["let ", toVar, " = " , typeName, " ", fromVar, " in"]+    -- References and pointers are handled equivalently.+    Internal_TPtr (Internal_TObj cls) -> case dir of+      ToCpp -> do+        addImports $ mconcat [hsImport1 "Prelude" "($)",+                              hsImportForRuntime]+        castMethodName <- toHsCastMethodName Nonconst cls+        saysLn ["HoppyFHR.withCppPtr (", castMethodName, " ", fromVar,+                ") $ \\", toVar, " ->"]+      FromCpp -> do+        ctorName <- toHsDataCtorName Unmanaged Nonconst cls+        saysLn ["let ", toVar, " = ", ctorName, " ", fromVar, " in"]+    Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> case dir of+      ToCpp -> do+        -- Same as the (TObj _), ToCpp case.+        addImports $ mconcat [hsImport1 "Prelude" "($)",+                              hsImportForPrelude,+                              hsImportForRuntime]+        withValuePtrName <- toHsWithValuePtrName cls+        saysLn [withValuePtrName, " ", fromVar,+                " $ HoppyP.flip HoppyFHR.withCppPtr $ \\", toVar, " ->"]+      FromCpp -> do+        ctorName <- toHsDataCtorName Unmanaged Const cls+        saysLn ["let ", toVar, " = ", ctorName, " ", fromVar, " in"]+    Internal_TPtr _ -> noConversion+    Internal_TRef t' -> sayArgProcessing dir (ptrT t') fromVar toVar+    Internal_TFn {} -> throwError "TFn unimplemented"+    Internal_TCallback cb -> case dir of+      ToCpp -> do+        addImports $ hsImport1 "Prelude" "(>>=)"+        callbackCtorName <- toHsCallbackCtorName cb+        saysLn [callbackCtorName, " ", fromVar, " >>= \\", toVar, " ->"]+      FromCpp -> throwError "Can't receive a callback from C++"+    Internal_TObj cls -> case dir of+      ToCpp -> do+        -- Same as the (TPtr (TConst (TObj _))), ToPtr case.+        addImports $ mconcat [hsImport1 "Prelude" "($)",+                              hsImportForPrelude,+                              hsImportForRuntime]+        withValuePtrName <- toHsWithValuePtrName cls+        saysLn [withValuePtrName, " ", fromVar,+                " $ HoppyP.flip HoppyFHR.withCppPtr $ \\", toVar, " ->"]+      FromCpp -> case classHaskellConversionFromCppFn $ getClassHaskellConversion cls of+        Just _ -> do+          addImports $ mconcat [hsImport1 "Prelude" "(>>=)",+                                hsImportForRuntime]+          ctorName <- toHsDataCtorName Unmanaged Const cls+          saysLn ["HoppyFHR.decode (", ctorName, " ", fromVar, ") >>= \\", toVar, " ->"]+        Nothing ->+          throwError $ concat+          ["Can't pass a TObj of ", show cls,+           " from C++ to Haskell because no class decode conversion is defined"]+    Internal_TObjToHeap cls -> case dir of+      ToCpp -> throwError $ objToHeapTWrongDirectionErrorMsg Nothing cls+      FromCpp -> sayArgProcessing dir (ptrT $ objT cls) fromVar toVar+    Internal_TToGc t' -> case dir of+      ToCpp -> throwError $ toGcTWrongDirectionErrorMsg Nothing t'+      FromCpp -> do+        addImports $ mconcat [hsImport1 "Prelude" "(>>=)",+                              hsImportForRuntime]+        saysLn ["HoppyFHR.toGc ", fromVar, " >>= \\", toVar, " ->"]+    Internal_TConst t' -> sayArgProcessing dir t' fromVar toVar+  where noConversion = saysLn ["let ", toVar, " = ", fromVar, " in"]+        sayCoerceIntegral = do+          addImports hsImportForRuntime+          saysLn ["let ", toVar, " = HoppyFHR.coerceIntegral ", fromVar, " in"]+        sayCoerceFloating = do+          addImports hsImportForPrelude+          saysLn ["let ", toVar, " = HoppyP.realToFrac ", fromVar, " in"]++-- | Note that the 'CallDirection' is the direction of the call, not the+-- direction of the return.  'ToCpp' means we're returning to the foreign+-- language, 'FromCpp' means we're returning from it.+sayCallAndProcessReturn :: CallDirection -> Type -> [String] -> Generator ()+sayCallAndProcessReturn dir t callWords =+  withErrorContext ("processing return value of type " ++ show t) $+  case t of+    Internal_TVoid -> sayCall+    Internal_TBool -> do+      case dir of+        ToCpp -> do addImports $ mconcat [hsImport1 "Prelude" "(/=)", hsImportForPrelude]+                    sayLn "HoppyP.fmap (/= 0)"+        FromCpp -> sayLn "HoppyP.fmap (\\x -> if x then 1 else 0)"+      sayCall+    Internal_TChar -> sayCall+    Internal_TUChar -> sayCall+    Internal_TShort -> sayCall+    Internal_TUShort -> sayCall+    Internal_TInt -> sayCoerceIntegral >> sayCall+    Internal_TUInt -> sayCall+    Internal_TLong -> sayCall+    Internal_TULong -> sayCall+    Internal_TLLong -> sayCall+    Internal_TULLong -> sayCall+    Internal_TFloat -> sayCoerceFloating >> sayCall+    Internal_TDouble -> sayCoerceFloating >> sayCall+    Internal_TInt8 -> sayCall+    Internal_TInt16 -> sayCall+    Internal_TInt32 -> sayCall+    Internal_TInt64 -> sayCall+    Internal_TWord8 -> sayCall+    Internal_TWord16 -> sayCall+    Internal_TWord32 -> sayCall+    Internal_TWord64 -> sayCall+    Internal_TPtrdiff -> sayCall+    Internal_TSize -> sayCall+    Internal_TSSize -> sayCall+    Internal_TEnum _ -> do+      addImports $ mconcat [hsImport1 "Prelude" "(.)", hsImportForPrelude, hsImportForRuntime]+      case dir of+        -- TODO The coersion here is unnecssary if we replace the C numeric types+        -- with their Haskell ones across the board (e.g. CInt -> Int).+        ToCpp -> saysLn ["HoppyP.fmap (HoppyP.toEnum . HoppyFHR.coerceIntegral)"]+        FromCpp -> saysLn ["HoppyP.fmap (HoppyFHR.coerceIntegral . HoppyP.fromEnum)"]+      sayCall+    Internal_TBitspace b -> do+      addImports hsImportForPrelude+      convFn <- bitspaceConvFn dir b+      saysLn ["HoppyP.fmap ", convFn]+      sayCall+    -- The same as TPtr (TConst (TObj _)), but nonconst.+    Internal_TPtr (Internal_TObj cls) -> do+      case dir of+        ToCpp -> do+          addImports hsImportForPrelude+          ctorName <- toHsDataCtorName Unmanaged Nonconst cls+          saysLn ["HoppyP.fmap ", ctorName]+          sayCall+        FromCpp -> do+          addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]+          sayLn "HoppyP.fmap HoppyFHR.toPtr"+          sayCall+    -- The same as TPtr (TConst (TObj _)), but nonconst.+    Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> case dir of+      ToCpp -> do+        addImports hsImportForPrelude+        ctorName <- toHsDataCtorName Unmanaged Const cls+        saysLn ["HoppyP.fmap ", ctorName]+        sayCall+      FromCpp -> do+        addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]+        sayLn "HoppyP.fmap HoppyFHR.toPtr"+        sayCall+    Internal_TPtr _ -> sayCall+    Internal_TRef t' -> sayCallAndProcessReturn dir (ptrT t') callWords+    Internal_TFn {} -> throwError "TFn unimplemented"+    Internal_TCallback cb -> case dir of+      ToCpp -> throwError "Can't receive a callback from C++"+      FromCpp -> do+        addImports $ hsImport1 "Prelude" "(=<<)"+        ctorName <- toHsCallbackCtorName cb+        saysLn [ctorName, "=<<"]+        sayCall+    Internal_TObj cls -> case dir of+      ToCpp -> case classHaskellConversionFromCppFn $ getClassHaskellConversion cls of+        Just _ -> do+          addImports $ mconcat [hsImports "Prelude" ["(.)", "(=<<)"],+                                hsImportForRuntime]+          ctorName <- toHsDataCtorName Unmanaged Const cls+          saysLn ["(HoppyFHR.decodeAndDelete . ", ctorName, ") =<<"]+          sayCall+        Nothing ->+          throwError $ concat+          ["Can't return a TObj of ", show cls,+           " from C++ to Haskell because no class decode conversion is defined"]+      FromCpp -> do+        addImports $ mconcat [hsImports "Prelude" ["(.)", "(=<<)"],+                              hsImportForPrelude,+                              hsImportForRuntime]+        sayLn "(HoppyP.fmap (HoppyFHR.toPtr) . HoppyFHR.encode) =<<"+        sayCall+    Internal_TObjToHeap cls -> case dir of+      ToCpp -> sayCallAndProcessReturn dir (ptrT $ objT cls) callWords+      FromCpp -> throwError $ objToHeapTWrongDirectionErrorMsg Nothing cls+    Internal_TToGc t' -> case dir of+      ToCpp -> do+        addImports $ mconcat [hsImport1 "Prelude" "(=<<)",+                              hsImportForRuntime]+        sayLn "HoppyFHR.toGc =<<"+        -- TToGc (TObj _) should create a pointer rather than decoding, so we+        -- change the TObj _ into a TPtr (TObj _).+        case t' of+          Internal_TObj _ -> sayCallAndProcessReturn dir (ptrT t') callWords+          _ -> sayCallAndProcessReturn dir t' callWords+      FromCpp -> throwError $ toGcTWrongDirectionErrorMsg Nothing t'+    Internal_TConst t' -> sayCallAndProcessReturn dir t' callWords+  where sayCall = saysLn $ "(" : callWords ++ [")"]+        sayCoerceIntegral = do addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]+                               sayLn "HoppyP.fmap HoppyFHR.coerceIntegral"+        sayCoerceFloating = do addImports hsImportForPrelude+                               sayLn "HoppyP.fmap HoppyP.realToFrac"+        bitspaceConvFn dir = case dir of+          ToCpp -> toHsBitspaceTypeName+          FromCpp -> toHsBitspaceToNumName++sayExportClass :: SayExportMode -> Class -> Generator ()+sayExportClass mode cls = withErrorContext ("generating class " ++ show (classExtName cls)) $ do+  case mode of+    SayExportForeignImports -> do+      sayExportClassHsVars mode cls+      sayExportClassHsCtors mode cls++      forM_ (classMethods cls) $ \method ->+        (sayExportFn mode <$> classEntityExtName cls <*> classEntityForeignName cls <*>+         methodPurity <*> pure (getMethodEffectiveParams cls method) <*>+         methodReturn <*> methodExceptionHandlers)+        method++    SayExportDecls -> do+      sayExportClassHsClass True cls Const+      sayExportClassHsClass True cls Nonconst++      sayExportClassHsStaticMethods cls++      -- Create a newtype for referencing foreign objects with pointers.  The+      -- newtype is not used with encodings of value objects.+      sayExportClassHsType True cls Const+      sayExportClassHsType True cls Nonconst++      sayExportClassExceptionSupport True cls++      sayExportClassHsVars mode cls+      sayExportClassHsCtors mode cls++    SayExportBoot -> do+      sayExportClassHsClass False cls Const+      sayExportClassHsClass False cls Nonconst++      sayExportClassHsType False cls Const+      sayExportClassHsType False cls Nonconst++      sayExportClassExceptionSupport False cls++      sayExportClassHsVars mode cls++  sayExportClassCastPrimitives mode cls+  sayExportClassHsSpecialFns mode cls++sayExportClassHsClass :: Bool -> Class -> Constness -> Generator ()+sayExportClassHsClass doDecls cls cst = withErrorContext "generating Haskell typeclass" $ do+  hsTypeName <- toHsDataTypeName cst cls+  hsValueClassName <- toHsValueClassName cls+  hsWithValuePtrName <- toHsWithValuePtrName cls+  hsPtrClassName <- toHsPtrClassName cst cls+  hsCastMethodName <- toHsCastMethodName cst cls+  let supers = classSuperclasses cls++  hsSupers <-+    (\x -> if null x+           then do addImports hsImportForRuntime+                   return ["HoppyFHR.CppPtr"]+           else return x) =<<+    case cst of+      Const -> mapM (toHsPtrClassName Const) supers+      Nonconst ->+        (:) <$> toHsPtrClassName Const cls <*> mapM (toHsPtrClassName Nonconst) supers++  -- Print the value class definition.  There is only one of these, and it is+  -- spiritually closer to the const version of the pointers for this class, so+  -- we emit for the const case only.+  when (cst == Const) $ do+    addImports hsImportForPrelude+    addExport' hsValueClassName+    ln+    saysLn ["class ", hsValueClassName, " a where"]+    indent $+      saysLn [hsWithValuePtrName, " :: a -> (", hsTypeName, " -> HoppyP.IO b) -> HoppyP.IO b"]++    -- Generate instances for all pointer subtypes.+    ln+    saysLn ["#if MIN_VERSION_base(4,8,0)"]+    saysLn ["instance {-# OVERLAPPABLE #-} ", hsPtrClassName, " a => ", hsValueClassName, " a",+            if doDecls then " where" else ""]+    saysLn ["#else"]+    saysLn ["instance ", hsPtrClassName, " a => ", hsValueClassName, " a",+            if doDecls then " where" else ""]+    saysLn ["#endif"]+    when doDecls $ do+      addImports $ mconcat [hsImports "Prelude" ["($)", "(.)"],+                            hsImportForPrelude]+      indent $ saysLn [hsWithValuePtrName, " = HoppyP.flip ($) . ", hsCastMethodName]++    -- When the class is encodable to a native Haskell type, also print an+    -- instance for it.+    let conv = getClassHaskellConversion cls+    case (classHaskellConversionType conv,+          classHaskellConversionToCppFn conv) of+      (Just hsTypeGen, Just _) -> do+        hsType <- hsTypeGen+        ln+        saysLn ["#if MIN_VERSION_base(4,8,0)"]+        saysLn ["instance {-# OVERLAPPING #-} ", hsValueClassName, " (", prettyPrint hsType, ")",+                if doDecls then " where" else ""]+        saysLn ["#else"]+        saysLn ["instance ", hsValueClassName, " (", prettyPrint hsType, ")",+                if doDecls then " where" else ""]+        saysLn ["#endif"]+        when doDecls $ do+          addImports hsImportForRuntime+          indent $ saysLn [hsWithValuePtrName, " = HoppyFHR.withCppObj"]+      _ -> return ()++  -- Print the pointer class definition.+  addExport' hsPtrClassName+  ln+  saysLn $+    "class (" :+    intersperse ", " (map (++ " this") hsSupers) +++    [") => ", hsPtrClassName, " this where"]+  indent $ saysLn [hsCastMethodName, " :: this -> ", hsTypeName]++  -- Print the non-static methods.+  when doDecls $ do+    let methods = filter ((cst ==) . methodConst) $ classMethods cls+    forM_ methods $ \method ->+      when (methodStatic method == Nonstatic) $+      (sayExportFn SayExportDecls <$> classEntityExtName cls <*> classEntityForeignName cls <*>+       methodPurity <*> pure (getMethodEffectiveParams cls method) <*>+       methodReturn <*> methodExceptionHandlers) method++sayExportClassHsStaticMethods :: Class -> Generator ()+sayExportClassHsStaticMethods cls =+  forM_ (classMethods cls) $ \method ->+    when (methodStatic method == Static) $+    (sayExportFn SayExportDecls <$> classEntityExtName cls <*> classEntityForeignName cls <*>+     methodPurity <*> methodParams <*> methodReturn <*> methodExceptionHandlers) method++sayExportClassHsType :: Bool -> Class -> Constness -> Generator ()+sayExportClassHsType doDecls cls cst = withErrorContext "generating Haskell data types" $ do+  hsTypeName <- toHsDataTypeName cst cls+  hsCtor <- toHsDataCtorName Unmanaged cst cls+  hsCtorGc <- toHsDataCtorName Managed cst cls+  constCastFnName <- toHsConstCastFnName cst cls++  addImports $ mconcat [hsImportForForeign, hsImportForPrelude, hsImportForRuntime]+  -- Unfortunately, we must export the data constructor, so that GHC can marshal+  -- it in foreign calls in other modules.+  addExport' hsTypeName+  ln+  saysLn ["data ", hsTypeName, " ="]+  indent $ do+    saysLn ["  ", hsCtor, " (HoppyF.Ptr ", hsTypeName, ")"]+    saysLn ["| ", hsCtorGc, " (HoppyF.ForeignPtr ()) (HoppyF.Ptr ", hsTypeName, ")"]+  when doDecls $ do+    addImports $ hsImport1 "Prelude" "(==)"+    indent $ sayLn "deriving (HoppyP.Show)"+    ln+    saysLn ["instance HoppyP.Eq ", hsTypeName, " where"]+    indent $ saysLn ["x == y = HoppyFHR.toPtr x == HoppyFHR.toPtr y"]+    ln+    saysLn ["instance HoppyP.Ord ", hsTypeName, " where"]+    indent $ saysLn ["compare x y = HoppyP.compare (HoppyFHR.toPtr x) (HoppyFHR.toPtr y)"]++  -- Generate const_cast functions:+  --   castFooToConst :: Foo -> FooConst+  --   castFooToNonconst :: FooConst -> Foo+  hsTypeNameOppConst <- toHsDataTypeName (constNegate cst) cls+  ln+  addExport constCastFnName+  saysLn [constCastFnName, " :: ", hsTypeNameOppConst, " -> ", hsTypeName]+  when doDecls $ do+    addImports $ hsImport1 "Prelude" "($)"+    hsCtorOppConst <- toHsDataCtorName Unmanaged (constNegate cst) cls+    hsCtorGcOppConst <- toHsDataCtorName Managed (constNegate cst) cls+    saysLn [constCastFnName, " (", hsCtorOppConst,+            " ptr') = ", hsCtor, " $ HoppyF.castPtr ptr'"]+    saysLn [constCastFnName, " (", hsCtorGcOppConst,+            " fptr' ptr') = ", hsCtorGc, " fptr' $ HoppyF.castPtr ptr'"]++  -- Generate an instance of CppPtr.+  ln+  if doDecls+    then do addImports $ hsImport1 "Prelude" "($)"+            saysLn ["instance HoppyFHR.CppPtr ", hsTypeName, " where"]+            indent $ do+              saysLn ["nullptr = ", hsCtor, " HoppyF.nullPtr"]+              ln+              saysLn ["withCppPtr (", hsCtor, " ptr') f' = f' ptr'"]+              saysLn ["withCppPtr (", hsCtorGc,+                      " fptr' ptr') f' = HoppyF.withForeignPtr fptr' $ \\_ -> f' ptr'"]+              ln+              saysLn ["toPtr (", hsCtor, " ptr') = ptr'"]+              saysLn ["toPtr (", hsCtorGc, " _ ptr') = ptr'"]+              ln+              saysLn ["touchCppPtr (", hsCtor, " _) = HoppyP.return ()"]+              saysLn ["touchCppPtr (", hsCtorGc, " fptr' _) = HoppyF.touchForeignPtr fptr'"]++            when (classDtorIsPublic cls) $ do+              addImports $ hsImport1 "Prelude" "(==)"+              ln+              saysLn ["instance HoppyFHR.Deletable ", hsTypeName, " where"]+              indent $ do+                -- Note, similar "delete" and "toGc" functions are generated for exception+                -- classes' ExceptionClassInfo structures.+                case cst of+                  Const ->+                    saysLn ["delete (", hsCtor, " ptr') = ", toHsClassDeleteFnName' cls, " ptr'"]+                  Nonconst -> do+                    constTypeName <- toHsDataTypeName Const cls+                    saysLn ["delete (",hsCtor, " ptr') = ", toHsClassDeleteFnName' cls,+                            " $ (HoppyF.castPtr ptr' :: HoppyF.Ptr ", constTypeName, ")"]+                saysLn ["delete (", hsCtorGc,+                        " _ _) = HoppyP.fail $ HoppyP.concat ",+                        "[\"Deletable.delete: Asked to delete a GC-managed \", ",+                        show hsTypeName, ", \" object.\"]"]+                ln+                saysLn ["toGc this'@(", hsCtor, " ptr') = ",+                        -- No sense in creating a ForeignPtr for a null pointer.+                        "if ptr' == HoppyF.nullPtr then HoppyP.return this' else HoppyP.fmap ",+                        "(HoppyP.flip ", hsCtorGc, " ptr') $ ",+                        "HoppyF.newForeignPtr ",+                        -- The foreign delete function takes a const pointer; we cast it to+                        -- take a Ptr () to match up with the ForeignPtr () we're creating,+                        -- assuming that data pointers have the same representation.+                        "(HoppyF.castFunPtr ", toHsClassDeleteFnPtrName' cls,+                        " :: HoppyF.FunPtr (HoppyF.Ptr () -> HoppyP.IO ())) ",+                        "(HoppyF.castPtr ptr' :: HoppyF.Ptr ())"]+                saysLn ["toGc this'@(", hsCtorGc, " {}) = HoppyP.return this'"]++            forM_ (classFindCopyCtor cls) $ \copyCtor -> do+              copyCtorName <- toHsCtorName cls copyCtor+              ln+              saysLn ["instance HoppyFHR.Copyable ", hsTypeName, " ",+                      case cst of+                        Nonconst -> hsTypeName+                        Const -> hsTypeNameOppConst,+                      " where copy = ", copyCtorName]++    else do saysLn ["instance HoppyFHR.CppPtr ", hsTypeName]++            when (classDtorIsPublic cls) $+              saysLn ["instance HoppyFHR.Deletable ", hsTypeName]++            forM_ (classFindCopyCtor cls) $ \_ ->+              saysLn ["instance HoppyFHR.Copyable ", hsTypeName, " ",+                      case cst of+                        Nonconst -> hsTypeName+                        Const -> hsTypeNameOppConst]++  -- Generate instances for all superclasses' typeclasses.+  genInstances hsTypeName [] cls++  where genInstances :: String -> [Class] -> Class -> Generator ()+        genInstances hsTypeName path ancestorCls = do+          -- In this example Bar inherits from Foo.  We are generating instances+          -- either for BarConst or Bar, depending on 'cst'.+          --+          -- BarConst's instances:+          --   instance FooConstPtr BarConst where+          --     toFooConst (BarConst ptr') = FooConst $ castBarToFoo ptr'+          --     toFooConst (BarConstGc fptr' ptr') = FooConstGc fptr' $ castBarToFoo ptr'+          --+          --   instance BarConstPtr BarConst where+          --     toFooConst = id+          --+          -- Bar's instances:+          --   instance FooConstPtr Bar+          --     toFooConst (Bar ptr') =+          --       FooConst $ castBarToFoo $ castBarToConst ptr'+          --     toFooConst (BarGc fptr' ptr') =+          --       FooConstGc fptr' $ castBarToFoo $ castBarToConst ptr'+          --+          --   instance FooPtr Bar+          --     toFoo (Bar ptr') =+          --       Foo $ castFooToNonconst $ castBarToFoo $ castBarToConst ptr'+          --     toFoo (BarGc fptr' ptr') =+          --       FooGc fptr' $ castFooToNonconst $ castBarToFoo $ castBarToConst ptr'+          --+          --   instance BarConstPtr Bar+          --     toBarConst (Bar ptr') = Bar $ castBarToConst ptr'+          --     toBarConst (BarGc fptr' ptr') = BarGc fptr' $ castBarToConst ptr'+          --+          --   instance BarPtr Bar+          --     toBar = id+          --+          -- In all cases, we unwrap the pointer, maybe add const, maybe do an+          -- upcast, maybe remove const, then rewrap the pointer.  The identity+          -- cases are where we just unwrap and wrap again.++          forM_ (case cst of+                   Const -> [Const]+                   Nonconst -> [Const, Nonconst]) $ \ancestorCst -> do+            ln+            ancestorPtrClassName <- toHsPtrClassName ancestorCst ancestorCls+            saysLn ["instance ", ancestorPtrClassName, " ", hsTypeName,+                    if doDecls then " where" else ""]+            when doDecls $ indent $ do+              -- Unqualified, for Haskell instance methods.+              let castMethodName = toHsCastMethodName' ancestorCst ancestorCls+              if null path && cst == ancestorCst+                then do addImports hsImportForPrelude+                        saysLn [castMethodName, " = HoppyP.id"]+                else do let addConst = cst == Nonconst+                            removeConst = ancestorCst == Nonconst+                        when (addConst || removeConst) $+                          addImports hsImportForForeign+                        forM_ ([minBound..] :: [Managed]) $ \managed -> do+                          ancestorCtor <- case managed of+                            Unmanaged -> (\x -> [x]) <$>+                                         toHsDataCtorName Unmanaged ancestorCst ancestorCls+                            Managed -> (\x -> [x, " fptr'"]) <$>+                                       toHsDataCtorName Managed ancestorCst ancestorCls+                          ptrPattern <- case managed of+                            Unmanaged -> (\x -> [x, " ptr'"]) <$>+                                         toHsDataCtorName Unmanaged cst cls+                            Managed -> (\x -> [x, " fptr' ptr'"]) <$>+                                       toHsDataCtorName Managed cst cls+                          saysLn . concat =<< sequence+                            [ return $+                              [castMethodName, " ("] ++ ptrPattern ++ [") = "] ++ ancestorCtor+                            , if removeConst+                              then do ancestorConstType <- toHsDataTypeName Const ancestorCls+                                      ancestorNonconstType <- toHsDataTypeName Nonconst ancestorCls+                                      return [" $ (HoppyF.castPtr :: HoppyF.Ptr ",+                                              ancestorConstType, " -> HoppyF.Ptr ",+                                              ancestorNonconstType, ")"]+                              else return []+                            , if not $ null path+                              then do addImports $ hsImport1 "Prelude" "($)"+                                      castPrimitiveName <- toHsCastPrimitiveName cls cls ancestorCls+                                      return [" $ ", castPrimitiveName]+                              else return []+                            , if addConst+                              then do addImports $ hsImport1 "Prelude" "($)"+                                      nonconstTypeName <- toHsDataTypeName Nonconst cls+                                      constTypeName <- toHsDataTypeName Const cls+                                      return [" $ (HoppyF.castPtr :: HoppyF.Ptr ",+                                              nonconstTypeName, " -> HoppyF.Ptr ",+                                              constTypeName, ")"]+                              else return []+                            , return [" ptr'"]+                            ]++          forM_ (classSuperclasses ancestorCls) $+            genInstances hsTypeName $+            ancestorCls : path++sayExportClassHsVars :: SayExportMode -> Class -> Generator ()+sayExportClassHsVars mode cls =+  forM_ (classVariables cls) $ sayExportClassVar mode cls++sayExportClassHsCtors :: SayExportMode -> Class -> Generator ()+sayExportClassHsCtors mode cls =+  withErrorContext "generating constructors" $+  forM_ (classCtors cls) $ \ctor ->+  (sayExportFn mode <$> classEntityExtName cls <*> classEntityForeignName cls <*>+   pure Nonpure <*> ctorParams <*> pure (ptrT $ objT cls) <*>+   ctorExceptionHandlers) ctor++sayExportClassHsSpecialFns :: SayExportMode -> Class -> Generator ()+sayExportClassHsSpecialFns mode cls = do+  typeName <- toHsDataTypeName Nonconst cls+  typeNameConst <- toHsDataTypeName Const cls++  -- Say the delete function.+  withErrorContext "generating delete bindings" $+    case mode of+      SayExportForeignImports -> when (classDtorIsPublic cls) $ do+        addImports $ mconcat [hsImportForForeign, hsImportForPrelude]+        saysLn ["foreign import ccall \"", classDeleteFnCppName cls, "\" ",+                toHsClassDeleteFnName' cls, " :: HoppyF.Ptr ",+                typeNameConst, " -> HoppyP.IO ()"]+        saysLn ["foreign import ccall \"&", classDeleteFnCppName cls, "\" ",+                toHsClassDeleteFnPtrName' cls, " :: HoppyF.FunPtr (HoppyF.Ptr ",+                typeNameConst, " -> HoppyP.IO ())"]+      -- The user interface to this is the generic 'delete' function, rendered+      -- elsewhere.+      SayExportDecls -> return ()+      SayExportBoot -> return ()++  withErrorContext "generating pointer Assignable instance" $+    case mode of+      SayExportForeignImports -> return ()+      SayExportDecls -> do+        addImports $ mconcat [hsImport1 "Prelude" "($)",+                              hsImportForForeign,+                              hsImportForRuntime]+        ln+        saysLn ["instance HoppyFHR.Assignable (HoppyF.Ptr (HoppyF.Ptr ", typeName, ")) ",+                typeName, " where"]+        indent $ sayLn "assign ptr' value' = HoppyF.poke ptr' $ HoppyFHR.toPtr value'"+      SayExportBoot -> return ()++  -- If the class has an assignment operator that takes its own type, then+  -- generate an instance of Assignable.+  withErrorContext "generating Assignable instance" $ do+    let assignmentMethods = flip filter (classMethods cls) $ \m ->+          methodApplicability m == MNormal &&+          (methodParams m == [objT cls] || methodParams m == [refT $ constT $ objT cls]) &&+          (case methodImpl m of+            RealMethod name -> name == FnOp OpAssign+            FnMethod name -> name == FnOp OpAssign)+        withAssignmentMethod f = case assignmentMethods of+          [] -> return ()+          [m] -> f m+          _ ->+            throwError $ concat+            ["Can't determine an Assignable instance to generator for ", show cls,+            " because it has multiple assignment operators ", show assignmentMethods]+    when (mode == SayExportDecls) $ withAssignmentMethod $ \m -> do+      addImports $ mconcat [hsImport1 "Prelude" "(>>)", hsImportForPrelude]+      valueClassName <- toHsValueClassName cls+      assignmentMethodName <- toHsMethodName cls m+      ln+      saysLn ["instance ", valueClassName, " a => HoppyFHR.Assignable ", typeName, " a where"]+      indent $+        saysLn ["assign x' y' = ", assignmentMethodName, " x' y' >> HoppyP.return ()"]++  -- A pointer to an object pointer is decodable to an object pointer by peeking+  -- at the value, so generate a Decodable instance.  You are now a two-star+  -- programmer.  There is a generic @Ptr (Ptr a)@ to @Ptr a@ instance which+  -- handles deeper levels.+  withErrorContext "generating pointer Decodable instance" $ do+    case mode of+      SayExportForeignImports -> return ()++      SayExportDecls -> do+        addImports $ mconcat [hsImport1 "Prelude" "(.)",+                              hsImportForForeign,+                              hsImportForPrelude,+                              hsImportForRuntime]+        ln+        saysLn ["instance HoppyFHR.Decodable (HoppyF.Ptr (HoppyF.Ptr ",+                typeName, ")) ", typeName, " where"]+        indent $ do+          ctorName <- toHsDataCtorName Unmanaged Nonconst cls+          saysLn ["decode = HoppyP.fmap ", ctorName, " . HoppyF.peek"]++      SayExportBoot -> do+        addImports $ mconcat [hsImportForForeign, hsImportForRuntime]+        ln+        -- TODO Encodable.+        saysLn ["instance HoppyFHR.Decodable (HoppyF.Ptr (HoppyF.Ptr ", typeName, ")) ", typeName]++  -- Say Encodable and Decodable instances, if the class is encodable and+  -- decodable.+  withErrorContext "generating Encodable/Decodable instances" $ do+    let conv = getClassHaskellConversion cls+    forM_ (classHaskellConversionType conv) $ \hsTypeGen -> do+      let hsTypeStrGen = hsTypeGen >>= \hsType -> return $ "(" ++ prettyPrint hsType ++ ")"++      case mode of+        SayExportForeignImports -> return ()++        SayExportDecls -> do+          -- Say the Encodable instances.+          forM_ (classHaskellConversionToCppFn conv) $ \toCppFnGen -> do+            hsTypeStr <- hsTypeStrGen+            addImports $ mconcat [hsImportForPrelude, hsImportForRuntime]+            castMethodName <- toHsCastMethodName Const cls++            ln+            saysLn ["instance HoppyFHR.Encodable ", typeName, " ", hsTypeStr, " where"]+            indent $ do+              sayLn "encode ="+              indent toCppFnGen+            ln+            saysLn ["instance HoppyFHR.Encodable ", typeNameConst, " ", hsTypeStr, " where"]+            indent $+              saysLn ["encode = HoppyP.fmap (", castMethodName,+                      ") . HoppyFHR.encodeAs (HoppyP.undefined :: ", typeName, ")"]++          -- Say the Decodable instances.+          forM_ (classHaskellConversionFromCppFn conv) $ \fromCppFnGen -> do+            hsTypeStr <- hsTypeStrGen+            addImports hsImportForRuntime+            castMethodName <- toHsCastMethodName Const cls++            ln+            saysLn ["instance HoppyFHR.Decodable ", typeName, " ", hsTypeStr, " where"]+            indent $+              saysLn ["decode = HoppyFHR.decode . ", castMethodName]+            ln+            saysLn ["instance HoppyFHR.Decodable ", typeNameConst, " ", hsTypeStr, " where"]+            indent $ do+              sayLn "decode ="+              indent fromCppFnGen++        SayExportBoot -> do+          -- Say the Encodable instances.+          forM_ (classHaskellConversionToCppFn conv) $ \_ -> do+            hsTypeStr <- hsTypeStrGen+            addImports hsImportForRuntime+            ln+            saysLn ["instance HoppyFHR.Encodable ", typeName, " (", hsTypeStr, ")"]+            saysLn ["instance HoppyFHR.Encodable ", typeNameConst, " (", hsTypeStr, ")"]++          -- Say the Decodable instances.+          forM_ (classHaskellConversionFromCppFn conv) $ \_ -> do+            hsTypeStr <- hsTypeStrGen+            addImports hsImportForRuntime+            ln+            saysLn ["instance HoppyFHR.Decodable ", typeName, " (", hsTypeStr, ")"]+            saysLn ["instance HoppyFHR.Decodable ", typeNameConst, " (", hsTypeStr, ")"]++-- | Generates a non-const @CppException@ instance if the class is an exception+-- class.+sayExportClassExceptionSupport :: Bool -> Class -> Generator ()+sayExportClassExceptionSupport doDecls cls =+  when (classIsException cls) $+  withErrorContext "generating exception support" $ do+  typeName <- toHsDataTypeName Nonconst cls+  typeNameConst <- toHsDataTypeName Const cls++  -- Generate a non-const CppException instance.+  exceptionId <- getClassExceptionId cls+  addImports hsImportForRuntime+  ln+  saysLn ["instance HoppyFHR.CppException ", typeName,+          if doDecls then " where" else ""]+  when doDecls $ indent $ do+    ctorName <- toHsDataCtorName Unmanaged Nonconst cls+    ctorGcName <- toHsDataCtorName Managed Nonconst cls+    addImports $ mconcat [hsImports "Prelude" ["($)", "(.)", "(=<<)"],+                          hsImportForForeign,+                          hsImportForMap,+                          hsImportForPrelude]+    sayLn "cppExceptionInfo _ ="+    indent $ do+      saysLn ["HoppyFHR.ExceptionClassInfo (HoppyFHR.ExceptionId ",+              show $ getExceptionId exceptionId, ") ", show typeName,+              " upcasts' delete' copy' toGc'"]++      -- Note, similar "delete" and "toGc" functions are generated for the class's+      -- Deletable instance.+      saysLn ["where delete' ptr' = ", toHsClassDeleteFnName' cls,+              " (HoppyF.castPtr ptr' :: HoppyF.Ptr ", typeNameConst, ")"]++      indentSpaces 6 $ do+        ctorName <- toHsDataCtorName Unmanaged Nonconst cls+        ln+        saysLn ["copy' = HoppyP.fmap (HoppyF.castPtr . HoppyFHR.toPtr) . HoppyFHR.copy . ",+                ctorName, " . HoppyF.castPtr"]++        ln+        saysLn ["toGc' ptr' = HoppyF.newForeignPtr ",+                -- The foreign delete function takes a const pointer; we cast it to+                -- take a Ptr () to match up with the ForeignPtr () we're creating,+                -- assuming that data pointers have the same representation.+                "(HoppyF.castFunPtr ", toHsClassDeleteFnPtrName' cls,+                " :: HoppyF.FunPtr (HoppyF.Ptr () -> HoppyP.IO ())) ",+                "ptr'"]++        sayLn "upcasts' = HoppyDM.fromList"+        indent $ case classSuperclasses cls of+          [] -> sayLn "[]"+          _ -> do+            let genCast :: Bool -> [Class] -> Class -> Generator ()+                genCast first path ancestorCls =+                  when (classIsException ancestorCls) $ do+                    let path' = ancestorCls : path+                    ancestorId <- getClassExceptionId ancestorCls+                    ancestorCastChain <- forM (zip path' $ drop 1 path') $ \(from, to) ->+                      -- We're upcasting, so 'from' is the subclass.+                      toHsCastPrimitiveName from to from+                    saysLn $ concat [ [if first then "[" else ",",+                                       " ( HoppyFHR.ExceptionId ",+                                       show $ getExceptionId ancestorId,+                                       ", \\(e' :: HoppyF.Ptr ()) -> "]+                                    , intersperse " $ " $+                                        "HoppyF.castPtr" :+                                        ancestorCastChain +++                                        ["HoppyF.castPtr e' :: HoppyF.Ptr ()"]+                                    , [")"]+                                    ]+                    forM_ (classSuperclasses ancestorCls) $ genCast False path'++            forM_ (zip (classSuperclasses cls) (True : repeat False)) $+              \(ancestorCls, first) -> genCast first [cls] ancestorCls+            sayLn "]"++    ln+    saysLn ["cppExceptionBuild fptr' ptr' = ", ctorGcName,+            " fptr' (HoppyF.castPtr ptr' :: HoppyF.Ptr ", typeName, ")"]+    ln+    saysLn ["cppExceptionBuildToGc ptr' = HoppyFHR.toGc $ ", ctorName,+            " (HoppyF.castPtr ptr' :: HoppyF.Ptr ", typeName, ")"]++  -- Generate a const CppException instance that piggybacks off of the+  -- non-const implementation.+  ln+  saysLn ["instance HoppyFHR.CppException ", typeNameConst,+          if doDecls then " where" else ""]+  when doDecls $ indent $ do+    addImports $ mconcat [hsImport1 "Prelude" "(.)",+                          hsImportForPrelude]+    constCastFnName <- toHsConstCastFnName Const cls+    saysLn ["cppExceptionInfo _ = HoppyFHR.cppExceptionInfo (HoppyP.undefined :: ",+            typeName, ")"]+    saysLn ["cppExceptionBuild = (", constCastFnName,+            " .) . HoppyFHR.cppExceptionBuild"]+    saysLn ["cppExceptionBuildToGc = HoppyP.fmap ", constCastFnName,+            " . HoppyFHR.cppExceptionBuildToGc"]++  -- Generate a non-const CppThrowable instance.+  ln+  saysLn ["instance HoppyFHR.CppThrowable ", typeName,+          if doDecls then " where" else ""]+  when doDecls $ indent $ do+    ctorName <- toHsDataCtorName Unmanaged Nonconst cls+    ctorGcName <- toHsDataCtorName Managed Nonconst cls+    addImports $ mconcat [hsImportForForeign,+                          hsImportForPrelude]+    saysLn ["toSomeCppException this'@(", ctorName, " ptr') = HoppyFHR.SomeCppException ",+            "(HoppyFHR.cppExceptionInfo this') HoppyP.Nothing (HoppyF.castPtr ptr')"]+    saysLn ["toSomeCppException this'@(", ctorGcName, " fptr' ptr') = HoppyFHR.SomeCppException ",+            "(HoppyFHR.cppExceptionInfo this') (HoppyP.Just fptr') (HoppyF.castPtr ptr')"]++sayExportClassCastPrimitives :: SayExportMode -> Class -> Generator ()+sayExportClassCastPrimitives mode cls = withErrorContext "generating cast primitives" $ do+  clsType <- toHsDataTypeName Const cls+  case mode of+    SayExportForeignImports ->+      forAncestors cls $ \super -> do+        hsCastFnName <- toHsCastPrimitiveName cls cls super+        hsDownCastFnName <- toHsCastPrimitiveName cls super cls+        superType <- toHsDataTypeName Const super+        addImports hsImportForForeign+        addExport hsCastFnName+        saysLn [ "foreign import ccall \"", classCastFnCppName cls super+               , "\" ", hsCastFnName, " :: HoppyF.Ptr ", clsType, " -> HoppyF.Ptr ", superType+               ]+        unless (classIsSubclassOfMonomorphic cls || classIsMonomorphicSuperclass super) $ do+          addExport hsDownCastFnName+          saysLn [ "foreign import ccall \"", classCastFnCppName super cls+                 , "\" ", hsDownCastFnName, " :: HoppyF.Ptr ", superType, " -> HoppyF.Ptr ", clsType+                 ]+        return True++    SayExportDecls ->+      -- Generate a downcast typeclass and instances for all ancestor classes+      -- for the current constness.  These don't need to be in the boot file,+      -- since they're not used by other generated bindings.+      unless (classIsSubclassOfMonomorphic cls) $+      forM_ [minBound..] $ \cst -> do+        downCastClassName <- toHsDownCastClassName cst cls+        downCastMethodName <- toHsDownCastMethodName cst cls+        typeName <- toHsDataTypeName cst cls+        addExport' downCastClassName+        ln+        saysLn ["class ", downCastClassName, " a where"]+        indent $ saysLn [downCastMethodName, " :: ",+                         prettyPrint $ HsTyFun (HsTyVar $ HsIdent "a") $+                         HsTyCon $ UnQual $ HsIdent typeName]+        ln+        forAncestors cls $ \super -> case classIsMonomorphicSuperclass super of+          True -> return False+          False -> do+            superTypeName <- toHsDataTypeName cst super+            primitiveCastFn <- toHsCastPrimitiveName cls super cls+            saysLn ["instance ", downCastClassName, " ", superTypeName, " where"]++            -- If Foo is a superclass of Bar:+            --+            -- instance BarSuper Foo where+            --   downToBar castFooToNonconst . downcast' . castFooToConst+            --     where downcast' (FooConst ptr') = BarConst $ castFooToBar ptr'+            --           downcast' (FooConstGc fptr' ptr') = BarConstGc fptr' $ castFooToBar ptr'+            --+            -- instance BarSuperConst FooConst where+            --   downToBarConst = downcast'+            --     where downcast' (FooConst ptr') = BarConst $ castFooToBar ptr'+            --           downcast' (FooConstGc fptr' ptr') = BarConstGc fptr' $ castFooToBar ptr'++            indent $ do+              case cst of+                Const -> saysLn [downCastMethodName, " = cast'"]+                Nonconst -> do+                  addImports $ hsImport1 "Prelude" "(.)"+                  castClsToNonconst <- toHsConstCastFnName Nonconst cls+                  castSuperToConst <- toHsConstCastFnName Const super+                  saysLn [downCastMethodName, " = ", castClsToNonconst, " . cast' . ",+                          castSuperToConst]+              indent $ do+                sayLn "where"+                indent $ do+                  clsCtorName <- toHsDataCtorName Unmanaged Const cls+                  clsCtorGcName <- toHsDataCtorName Managed Const cls+                  superCtorName <- toHsDataCtorName Unmanaged Const super+                  superCtorGcName <- toHsDataCtorName Managed Const super+                  saysLn ["cast' (", superCtorName, " ptr') = ",+                          clsCtorName, " $ ", primitiveCastFn, " ptr'"]+                  saysLn ["cast' (", superCtorGcName, " fptr' ptr') = ",+                          clsCtorGcName , " fptr' $ ", primitiveCastFn, " ptr'"]+            return True++    SayExportBoot -> do+      forAncestors cls $ \super -> do+        hsCastFnName <- toHsCastPrimitiveName cls cls super+        superType <- toHsDataTypeName Const super+        addImports $ hsImportForForeign+        addExport hsCastFnName+        saysLn [hsCastFnName, " :: HoppyF.Ptr ", clsType, " -> HoppyF.Ptr ", superType]+        return True++  where forAncestors :: Class -> (Class -> Generator Bool) -> Generator ()+        forAncestors cls' f = forM_ (classSuperclasses cls') $ \super -> do+          recur <- f super+          when recur $ forAncestors super f++-- | Outputs the @ExceptionDb@ needed by all Haskell gateway functions that deal+-- with exceptions.+sayExceptionSupport :: Bool -> Generator ()+sayExceptionSupport doDecls = do+  iface <- askInterface+  addExport "exceptionDb'"+  addImports hsImportForRuntime+  ln+  sayLn "exceptionDb' :: HoppyFHR.ExceptionDb"+  when doDecls $ do+    addImports $ mconcat [hsImport1 "Prelude" "($)",+                          hsImportForMap]+    sayLn "exceptionDb' = HoppyFHR.ExceptionDb $ HoppyDM.fromList"+    indent $ do+      let classes = interfaceAllExceptionClasses iface+      case classes of+        [] -> sayLn "[]"+        _ -> do+          addImports hsImportForPrelude+          forM_ (zip classes (True : repeat False)) $ \(cls, first) -> do+            exceptionId <-+              fromMaybeM (throwError $ "sayExceptionSupport: Internal error, " ++ show cls +++                          " has no exception ID.") $+              interfaceExceptionClassId iface cls+            typeName <- toHsDataTypeName Nonconst cls+            saysLn [if first then "[ (" else ", (",+                    "HoppyFHR.ExceptionId ", show $ getExceptionId exceptionId,+                    ", HoppyFHR.cppExceptionInfo (HoppyP.undefined :: ",+                    typeName, "))"]+          sayLn "]"++-- | Implements special logic on top of 'cppTypeToHsTypeAndUse', that computes+-- the Haskell __qualified__ type for a function, including typeclass+-- constraints.+fnToHsTypeAndUse :: HsTypeSide+                 -> Purity+                 -> [Type]+                 -> Type+                 -> ExceptionHandlers+                 -> Generator HsQualType+fnToHsTypeAndUse side purity paramTypes returnType exceptionHandlers = do+  let catches = not $ null $ exceptionHandlersList exceptionHandlers++  params <- mapM contextForParam $+            (if catches && side == HsCSide+             then (++ [("excId", ptrT intT), ("excPtr", ptrT $ ptrT voidT)])+             else id) $+            zip (map toArgName [1..]) paramTypes+  let context = mapMaybe fst params :: HsContext+      hsParams = map snd params++  -- Determine the 'HsHsSide' return type for the function.  Do the conversion+  -- to a Haskell type, and wrap the result in 'IO' if the function is impure.+  -- (HsCSide types always get wrapped in IO.)+  hsReturnInitial <- cppTypeToHsTypeAndUse side returnType+  hsReturnForPurity <- case (purity, side) of+    (Pure, HsHsSide) -> return hsReturnInitial+    _ -> do+      addImports hsImportForPrelude+      return $ HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyP.IO") hsReturnInitial++  return $ HsQualType context $ foldr HsTyFun hsReturnForPurity hsParams++  where contextForParam :: (String, Type) -> Generator (Maybe HsAsst, HsType)+        contextForParam (s, t) = case t of+          Internal_TBitspace b -> receiveBitspace s t b+          Internal_TPtr (Internal_TObj cls) -> receivePtr s cls Nonconst+          Internal_TPtr (Internal_TConst (Internal_TObj cls)) -> receiveValue s t cls+          Internal_TRef (Internal_TObj cls) -> receivePtr s cls Nonconst+          Internal_TRef (Internal_TConst (Internal_TObj cls)) -> receiveValue s t cls+          Internal_TObj cls -> receiveValue s t cls+          Internal_TConst t' -> contextForParam (s, t')+          _ -> handoff side t++        -- Use whatever type 'cppTypeToHsTypeAndUse' suggests, with no typeclass+        -- constraints.+        handoff :: HsTypeSide -> Type -> Generator (Maybe HsAsst, HsType)+        handoff side t = (,) Nothing <$> cppTypeToHsTypeAndUse side t++        -- Receives a @IsFooBitspace a => a@.+        receiveBitspace s t b = case side of+          HsCSide -> handoff side t+          HsHsSide -> do+            bitspaceClassName <- toHsBitspaceClassName b+            let t' = HsTyVar $ HsIdent s+            return (Just (UnQual $ HsIdent bitspaceClassName, [t']),+                    t')++        -- Receives a @FooPtr this => this@.+        receivePtr :: String -> Class -> Constness -> Generator (Maybe HsAsst, HsType)+        receivePtr s cls cst = case side of+          HsHsSide -> do+            ptrClassName <- toHsPtrClassName cst cls+            let t' = HsTyVar $ HsIdent s+            return (Just (UnQual $ HsIdent ptrClassName, [t']),+                    t')+          HsCSide -> do+            addImports $ hsImportForForeign+            typeName <- toHsDataTypeName cst cls+            return (Nothing, HsTyApp (HsTyCon $ UnQual $ HsIdent "HoppyF.Ptr") $+                             HsTyVar $ HsIdent typeName)++        -- Receives a @FooValue a => a@.+        receiveValue :: String -> Type -> Class -> Generator (Maybe HsAsst, HsType)+        receiveValue s t cls = case side of+          HsCSide -> handoff side t+          HsHsSide -> do+            addImports hsImportForRuntime+            valueClassName <- toHsValueClassName cls+            let t' = HsTyVar $ HsIdent s+            return (Just (UnQual $ HsIdent valueClassName, [t']),+                    t')++getMethodEffectiveParams :: Class -> Method -> [Type]+getMethodEffectiveParams cls method =+  (case methodImpl method of+     RealMethod {} -> case methodApplicability method of+       MNormal -> (ptrT (objT cls):)+       MConst -> (ptrT (constT $ objT cls):)+       MStatic -> id+     FnMethod {} -> id) $+  methodParams method++getEffectiveExceptionHandlers :: ExceptionHandlers -> Generator ExceptionHandlers+getEffectiveExceptionHandlers handlers = do+  ifaceHandlers <- interfaceExceptionHandlers <$> askInterface+  moduleHandlers <- getExceptionHandlers <$> askModule+  -- Exception handlers declared lower in the hierarchy take precedence over+  -- those in the hierarchy; ExceptionHandlers is a left-biased monoid.+  return $ mconcat [handlers, moduleHandlers, ifaceHandlers]++getEffectiveCallbackThrows :: Callback -> Generator Bool+getEffectiveCallbackThrows cb = case callbackThrows cb of+  Just b -> return b+  Nothing -> moduleCallbacksThrow <$> askModule >>= \case+    Just b -> return b+    Nothing -> interfaceCallbacksThrow <$> askInterface++getClassExceptionId :: Class -> Generator ExceptionId+getClassExceptionId cls = do+  iface <- askInterface+  fromMaybeM (throwError $ concat+              ["Internal error, exception class ", show cls, " doesn't have an exception ID"]) $+    interfaceExceptionClassId iface cls
src/Foreign/Hoppy/Generator/Spec.hs view
@@ -1,1877 +1,32 @@ -- This file is part of Hoppy. ----- Copyright 2015-2016 Bryan Gardiner <bog@khumba.net>------ This program is free software: you can redistribute it and/or modify--- it under the terms of the GNU Affero General Public License as published by--- the Free Software Foundation, either version 3 of the License, or--- (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU Affero General Public License for more details.------ You should have received a copy of the GNU Affero General Public License--- along with this program.  If not, see <http://www.gnu.org/licenses/>.--{-# LANGUAGE CPP #-}---- | The primary data types for specifying C++ interfaces.------ 'Show' instances in this module produce strings of the form @\"\<TypeOfObject--- nameOfObject otherInfo...\>\"@.  They can be used in error messages without--- specifying a noun separately, i.e. write @show cls@ instead of @\"the class--- \" ++ show cls@.-module Foreign.Hoppy.Generator.Spec (-  -- * Interfaces-  Interface,-  ErrorMsg,-  interface,-  interfaceName,-  interfaceModules,-  interfaceNamesToModules,-  interfaceHaskellModuleBase,-  interfaceDefaultHaskellModuleBase,-  interfaceAddHaskellModuleBase,-  -- * C++ includes-  Include,-  includeStd,-  includeLocal,-  includeToString,-  -- * Modules-  Module,-  moduleName,-  moduleHppPath,-  moduleCppPath,-  moduleExports,-  moduleReqs,-  moduleHaskellName,-  makeModule,-  moduleModify,-  moduleModify',-  moduleSetHppPath,-  moduleSetCppPath,-  moduleAddExports,-  moduleAddHaskellName,-  -- * Requirements-  Reqs,-  reqsIncludes,-  reqInclude,-  HasReqs (..),-  addReqs,-  addReqIncludes,-  -- * Names and exports-  ExtName,-  toExtName,-  fromExtName,-  FnName (..),-  IsFnName (..),-  Operator (..),-  OperatorType (..),-  operatorPreferredExtName,-  operatorPreferredExtName',-  operatorType,-  Export (..),-  exportExtName,-  exportAddendum,-  Identifier,-  identifierParts,-  IdPart,-  idPartBase,-  idPartArgs,-  ident, ident', ident1, ident2, ident3, ident4, ident5,-  identT, identT', ident1T, ident2T, ident3T, ident4T, ident5T,-  -- * Basic types-  Type (..),-  normalizeType,-  stripConst,-  -- ** Variables-  Variable, makeVariable, varIdentifier, varExtName, varType, varReqs,-  varIsConst, varGetterExtName, varSetterExtName,-  -- ** Enums-  CppEnum, makeEnum, enumIdentifier, enumExtName, enumValueNames, enumReqs,-  -- ** Bitspaces-  Bitspace, makeBitspace, bitspaceExtName, bitspaceType, bitspaceValueNames, bitspaceEnum,-  bitspaceAddEnum, bitspaceCppTypeIdentifier, bitspaceFromCppValueFn, bitspaceToCppValueFn,-  bitspaceAddCppType, bitspaceReqs,-  -- ** Functions-  Purity (..),-  Function, makeFn, fnCName, fnExtName, fnPurity, fnParams, fnReturn, fnReqs,-  -- ** Classes-  Class, makeClass, classIdentifier, classExtName, classSuperclasses, classCtors, classDtorIsPublic,-  classMethods, classConversion, classReqs, classAddCtors, classSetDtorPrivate, classAddMethods,-  classIsMonomorphicSuperclass, classSetMonomorphicSuperclass,-  classIsSubclassOfMonomorphic, classSetSubclassOfMonomorphic,-  HasClassyExtName (..),-  Ctor, makeCtor, mkCtor, ctorExtName, ctorParams,-  Method,-  MethodImpl (..),-  MethodApplicability (..),-  Constness (..),-  constNegate,-  Staticness (..),-  makeMethod, makeFnMethod, mkMethod, mkMethod', mkConstMethod, mkConstMethod',-  mkStaticMethod, mkStaticMethod',-  mkProps, mkProp, mkStaticProp, mkBoolIsProp, mkBoolHasProp,-  methodImpl, methodExtName, methodApplicability, methodPurity, methodParams,-  methodReturn, methodConst, methodStatic,-  -- *** Conversion to and from foreign values-  ClassConversion (..),-  ClassConversionMode (..),-  classConversionNone,-  classModifyConversion,-  classSetConversion,-  classSetConversionToHeap,-  classSetConversionToGc,-  classSetHaskellConversion,-  ClassHaskellConversion (..),-  -- ** Callbacks-  Callback, makeCallback, callbackExtName, callbackParams, callbackReturn, callbackReqs,-  -- * Addenda-  Addendum (..),-  HasAddendum,-  addAddendumHaskell,-  -- * Haskell imports-  HsModuleName, HsImportSet, HsImportKey (..), HsImportSpecs (..), HsImportName, HsImportVal (..),-  hsWholeModuleImport, hsQualifiedImport, hsImport1, hsImport1', hsImports, hsImports',-  hsImportSetMakeSource,-  -- * Internal to Hoppy-  stringOrIdentifier,-  callbackToTFn,-  -- ** Haskell imports-  makeHsImportSet,-  getHsImportSet,-  hsImportForBits,-  hsImportForInt,-  hsImportForWord,-  hsImportForForeign,-  hsImportForForeignC,-  hsImportForPrelude,-  hsImportForRuntime,-  hsImportForSystemPosixTypes,-  hsImportForUnsafeIO,-  -- ** Error messages-  objToHeapTWrongDirectionErrorMsg,-  tToGcInvalidFormErrorMessage,-  toGcTWrongDirectionErrorMsg,-  ) where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>), (<*>))-#endif-import Control.Arrow ((&&&))-import Control.Monad (liftM2, unless)-#if MIN_VERSION_mtl(2,2,1)-import Control.Monad.Except (MonadError, throwError)-#else-import Control.Monad.Error (MonadError, throwError)-#endif-import Control.Monad.State (MonadState, StateT, execStateT, get, modify)-import Data.Char (isAlpha, isAlphaNum, toUpper)-import Data.Function (on)-import Data.List (intercalate, intersperse)-import qualified Data.Map as M-import Data.Maybe (fromMaybe)-#if !MIN_VERSION_base(4,8,0)-import Data.Monoid (Monoid, mappend, mconcat, mempty)-#endif-import qualified Data.Set as S-import {-# SOURCE #-} qualified Foreign.Hoppy.Generator.Language.Haskell as Haskell-import Language.Haskell.Syntax (HsType)---- | Indicates strings that are error messages.-type ErrorMsg = String---- | A complete specification of a C++ API.  Generators for different languages,--- including the binding generator for C++, use these to produce their output.-data Interface = Interface-  { interfaceName :: String-    -- ^ The textual name of the interface.-  , interfaceModules :: M.Map String Module-    -- ^ All of the individual modules, by 'moduleName'.-  , interfaceNamesToModules :: M.Map ExtName Module-    -- ^ Maps each 'ExtName' exported by some module to the module that exports-    -- the name.-  , interfaceHaskellModuleBase' :: Maybe [String]-    -- ^ See 'interfaceHaskellModuleBase'.-  }--instance Show Interface where-  show iface = concat ["<Interface ", show (interfaceName iface), ">"]---- | Constructs an 'Interface' from the required parts.  Some validation is--- performed; if the resulting interface would be invalid, an error message is--- returned instead.-interface :: String  -- ^ 'interfaceName'-          -> [Module]  -- ^ 'interfaceModules'-          -> Either ErrorMsg Interface-interface ifName modules = do-  -- TODO Check for duplicate module names.-  -- TODO Check for duplicate module file paths.--  -- Check for multiple modules exporting an ExtName.-  let extNamesToModules :: M.Map ExtName [Module]-      extNamesToModules =-        M.unionsWith (++) $-        map (\m -> const [m] <$> moduleExports m) modules--      extNamesInMultipleModules :: [(ExtName, [Module])]-      extNamesInMultipleModules =-        M.toList $-        M.filter (\modules -> case modules of-                     _:_:_ -> True-                     _ -> False)-        extNamesToModules--  unless (null extNamesInMultipleModules) $-    Left $ unlines $-    "Some external name(s) are exported by multiple modules:" :-    map (\(extName, modules) ->-          concat $ "- " : show extName : ": " : intersperse ", " (map show modules))-        extNamesInMultipleModules--  return Interface-    { interfaceName = ifName-    , interfaceModules = M.fromList $ map (moduleName &&& id) modules-    , interfaceNamesToModules = M.map (\[x] -> x) extNamesToModules-    , interfaceHaskellModuleBase' = Nothing-    }---- | The name of the parent Haskell module under which a Haskell module will be--- generated for a Hoppy 'Module'.  This is a list of Haskell module path--- components, in other words, @'Data.List.intercalate' "."@ on the list--- produces a Haskell module name.  Defaults to--- 'interfaceDefaultHaskellModuleBase', and may be overridden with--- 'interfaceAddHaskellModuleBase'.-interfaceHaskellModuleBase :: Interface -> [String]-interfaceHaskellModuleBase =-  fromMaybe interfaceDefaultHaskellModuleBase . interfaceHaskellModuleBase'---- | The default Haskell module under which Hoppy modules will be generated.--- This is @Foreign.Hoppy.Generated@, that is:------ > ["Foreign", "Hoppy", "Generated"]-interfaceDefaultHaskellModuleBase :: [String]-interfaceDefaultHaskellModuleBase = ["Foreign", "Hoppy", "Generated"]---- | Sets an interface to generate all of its modules under the given Haskell--- module prefix.  See 'interfaceHaskellModuleBase'.-interfaceAddHaskellModuleBase :: [String] -> Interface -> Either String Interface-interfaceAddHaskellModuleBase modulePath iface = case interfaceHaskellModuleBase' iface of-  Nothing -> Right iface { interfaceHaskellModuleBase' = Just modulePath }-  Just existingPath ->-    Left $ concat-    [ "addInterfaceHaskellModuleBase: Trying to add Haskell module base "-    , intercalate "." modulePath, " to ", show iface-    , " which already has a module base ", intercalate "." existingPath-    ]---- | An @#include@ directive in a C++ file.-data Include = Include-  { includeToString :: String-    -- ^ Returns the complete @#include ...@ line for an include, including-    -- trailing newline.-  } deriving (Eq, Ord, Show)---- | Creates an @#include \<...\>@ directive.-includeStd :: String -> Include-includeStd path = Include $ "#include <" ++ path ++ ">\n"---- | Creates an @#include "..."@ directive.-includeLocal :: String -> Include-includeLocal path = Include $ "#include \"" ++ path ++ "\"\n"---- | A portion of functionality in a C++ API.  An 'Interface' is composed of--- multiple modules.  A module will generate a single compilation unit--- containing bindings for all of the module's exports.  The C++ code for a--- generated module will @#include@ everything necessary for what is written to--- the header and source files separately.  You can declare include dependencies--- with e.g. 'addReqIncludes', either for individual exports or at the module--- level.  Dependencies between modules are handled automatically, and--- circularity is supported to a certain extent.  See the documentation for the--- individual language modules for further details.-data Module = Module-  { moduleName :: String-    -- ^ The module's name.  A module name must identify a unique module within-    -- an 'Interface'.-  , moduleHppPath :: String-    -- ^ A relative path under a C++ sources root to which the generator will-    -- write a header file for the module's C++ bindings.-  , moduleCppPath :: String-    -- ^ A relative path under a C++ sources root to which the generator will-    -- write a source file for the module's C++ bindings.-  , moduleExports :: M.Map ExtName Export-    -- ^ All of the exports in a module.-  , moduleReqs :: Reqs-    -- ^ Module-level requirements.-  , moduleHaskellName :: Maybe [String]-    -- ^ The generated Haskell module name, underneath the-    -- 'interfaceHaskellModuleBase'.  If absent (by default), the 'moduleName'-    -- is used.  May be modified with 'moduleAddHaskellName'.-  }--instance Eq Module where-  (==) = (==) `on` moduleName--instance Ord Module where-  compare = compare `on` moduleName--instance Show Module where-  show m = concat ["<Module ", moduleName m, ">"]--instance HasReqs Module where-  getReqs = moduleReqs-  setReqs reqs m = m { moduleReqs = reqs }---- | Creates an empty module, ready to be configured with 'moduleModify'.-makeModule :: String  -- ^ 'moduleName'-           -> String  -- ^ 'moduleHppPath'-           -> String  -- ^ 'moduleCppPath'-           -> Module-makeModule name hppPath cppPath = Module-  { moduleName = name-  , moduleHppPath = hppPath-  , moduleCppPath = cppPath-  , moduleExports = M.empty-  , moduleReqs = mempty-  , moduleHaskellName = Nothing-  }---- | Extends a module.  To be used with the module state-monad actions in this--- package.-moduleModify :: Module -> StateT Module (Either String) () -> Either ErrorMsg Module-moduleModify = flip execStateT---- | Same as 'moduleModify', but calls 'error' in the case of failure, which is--- okay in for a generator which would abort in this case anyway.-moduleModify' :: Module -> StateT Module (Either String) () -> Module-moduleModify' m action = case moduleModify m action of-  Left errorMsg ->-    error $ concat-    ["moduleModify' failed to modify ", show m, ": ", errorMsg]-  Right m' -> m'---- | Replaces a module's 'moduleHppPath'.-moduleSetHppPath :: MonadState Module m => String -> m ()-moduleSetHppPath path = modify $ \m -> m { moduleHppPath = path }---- | Replaces a module's 'moduleCppPath'.-moduleSetCppPath :: MonadState Module m => String -> m ()-moduleSetCppPath path = modify $ \m -> m { moduleCppPath = path }---- | Adds exports to a module.  An export must only be added to any module at--- most once, and must not be added to multiple modules.-moduleAddExports :: (MonadError String m, MonadState Module m) => [Export] -> m ()-moduleAddExports exports = do-  m <- get-  let existingExports = moduleExports m-      newExports = M.fromList $ map (exportExtName &&& id) exports-      duplicateNames = (S.intersection `on` M.keysSet) existingExports newExports-  if S.null duplicateNames-    then modify $ \m -> m { moduleExports = existingExports `mappend` newExports }-    else throwError $ concat-         ["moduleAddExports: ", show m, " defines external names multiple times: ",-          show duplicateNames]---- | Changes a module's 'moduleHaskellName' from the default.  This can only be--- called once on a module.-moduleAddHaskellName :: (MonadError String m, MonadState Module m) => [String] -> m ()-moduleAddHaskellName name = do-  m <- get-  case moduleHaskellName m of-    Nothing -> modify $ \m -> m { moduleHaskellName = Just name }-    Just name' ->-      throwError $ concat-      ["moduleAddHaskellName: ", show m, " already has Haskell name ",-       show name', "; trying to add name ", show name, "."]---- | A set of requirements of needed to use an identifier in C++ (function,--- type, etc.), via a set of 'Include's.  The monoid instance has 'mempty' as an--- empty set of includes, and 'mappend' unions two include sets.-data Reqs = Reqs-  { reqsIncludes :: S.Set Include-    -- ^ The includes specified by a 'Reqs'.-  } deriving (Show)--instance Monoid Reqs where-  mempty = Reqs mempty--  mappend (Reqs incl) (Reqs incl') = Reqs $ mappend incl incl'--  mconcat reqs = Reqs $ mconcat $ map reqsIncludes reqs---- | Creates a 'Reqs' that contains the given include.-reqInclude :: Include -> Reqs-reqInclude include = mempty { reqsIncludes = S.singleton include }---- | C++ types that have requirements in order to use them in generated--- bindings.-class HasReqs a where-  {-# MINIMAL getReqs, (setReqs | modifyReqs) #-}--  -- | Returns an object's requirements.-  getReqs :: a -> Reqs--  -- | Replaces an object's requirements with new ones.-  setReqs :: Reqs -> a -> a-  setReqs = modifyReqs . const--  -- | Modifies an object's requirements.-  modifyReqs :: (Reqs -> Reqs) -> a -> a-  modifyReqs f x = setReqs (f $ getReqs x) x---- | Adds to a object's requirements.-addReqs :: HasReqs a => Reqs -> a -> a-addReqs reqs = modifyReqs $ mappend reqs---- | Adds a list of includes to the requirements of an object.-addReqIncludes :: HasReqs a => [Include] -> a -> a-addReqIncludes includes =-  modifyReqs $ mappend mempty { reqsIncludes = S.fromList includes }---- | An external name is a string that generated bindings use to uniquely--- identify an object at runtime.  An external name must start with an--- alphabetic character, and may only contain alphanumeric characters and @'_'@.--- You are free to use whatever naming style you like; case conversions will be--- performed automatically when required.  Hoppy does make use of some--- conventions though, for example with 'Operator's and in the provided bindings--- for the C++ standard library.------ External names must be unique within an interface.  They may not be reused--- between modules.  This assumption is used for symbol naming in compiled--- shared objects and to freely import modules in Haskell bindings.-newtype ExtName = ExtName-  { fromExtName :: String-    -- ^ Returns the string an an 'ExtName' contains.-  } deriving (Eq, Ord)--instance Show ExtName where-  show extName = concat ["$\"", fromExtName extName, "\"$"]---- | Creates an 'ExtName' that contains the given string, erroring if the string--- is an invalid 'ExtName'.-toExtName :: String -> ExtName-toExtName str = case str of-  [] -> error "An ExtName cannot be empty."-  c:cs -> if isAlpha c && all ((||) <$> isAlphaNum <*> (== '_')) cs-          then ExtName str-          else error $-               "An ExtName must start with a letter and only contain letters, numbers, and '_': " ++-               show str---- | Generates an 'ExtName' from an 'Identifier', if the given name is absent.-extNameOrIdentifier :: Identifier -> Maybe ExtName -> ExtName-extNameOrIdentifier ident = fromMaybe $ case identifierParts ident of-  [] -> error "extNameOrIdentifier: Invalid empty identifier."-  parts -> toExtName $ idPartBase $ last parts---- | Like 'extNameOrIdentifier', but works with strings rather than 'ExtName's.-stringOrIdentifier :: Identifier -> Maybe String -> String-stringOrIdentifier ident = fromMaybe $ case identifierParts ident of-  [] -> error "stringOrIdentifier: Invalid empty identifier."-  parts -> idPartBase $ last parts---- | Generates an 'ExtName' from an @'FnName' 'Identifier'@, if the given name--- is absent.-extNameOrFnIdentifier :: FnName Identifier -> Maybe ExtName -> ExtName-extNameOrFnIdentifier name =-  fromMaybe $ case name of-    FnName identifier -> case identifierParts identifier of-      [] -> error "extNameOrFnIdentifier: Empty idenfitier."-      parts -> toExtName $ idPartBase $ last parts-    FnOp op -> operatorPreferredExtName op---- | The C++ name of a function or method.-data FnName name =-  FnName name-  -- ^ A regular, \"alphanumeric\" name.  The exact type depends on what kind of-  -- object is being named.-  | FnOp Operator-    -- ^ An operator name.-  deriving (Eq, Ord)--instance Show name => Show (FnName name) where-  show (FnName name) = concat ["<FnName ", show name, ">"]-  show (FnOp op) = concat ["<FnOp ", show op, ">"]---- | Enables implementing automatic conversions to a @'FnName' t@.-class IsFnName t a where-  toFnName :: a -> FnName t--instance IsFnName t (FnName t) where-  toFnName = id--instance IsFnName t t where-  toFnName = FnName--instance IsFnName t Operator where-  toFnName = FnOp---- | Overloadable C++ operators.-data Operator =-  OpCall  -- ^ @x(...)@-  | OpComma -- ^ @x, y@-  | OpAssign  -- ^ @x = y@-  | OpArray  -- ^ @x[y]@-  | OpDeref  -- ^ @*x@-  | OpAddress  -- ^ @&x@-  | OpAdd  -- ^ @x + y@-  | OpAddAssign  -- ^ @x += y@-  | OpSubtract  -- ^ @x - y@-  | OpSubtractAssign  -- ^ @x -= y@-  | OpMultiply  -- ^ @x * y@-  | OpMultiplyAssign  -- ^ @x *= y@-  | OpDivide  -- ^ @x / y@-  | OpDivideAssign  -- ^ @x /= y@-  | OpModulo  -- ^ @x % y@-  | OpModuloAssign  -- ^ @x %= y@-  | OpPlus  -- ^ @+x@-  | OpMinus  -- ^ @-x@-  | OpIncPre  -- ^ @++x@-  | OpIncPost  -- ^ @x++@-  | OpDecPre  -- ^ @--x@-  | OpDecPost  -- ^ @x--@-  | OpEq  -- ^ @x == y@-  | OpNe  -- ^ @x != y@-  | OpLt  -- ^ @x < y@-  | OpLe  -- ^ @x <= y@-  | OpGt  -- ^ @x > y@-  | OpGe  -- ^ @x >= y@-  | OpNot  -- ^ @!x@-  | OpAnd  -- ^ @x && y@-  | OpOr  -- ^ @x || y@-  | OpBitNot  -- ^ @~x@-  | OpBitAnd  -- ^ @x & y@-  | OpBitAndAssign  -- ^ @x &= y@-  | OpBitOr  -- ^ @x | y@-  | OpBitOrAssign  -- ^ @x |= y@-  | OpBitXor  -- ^ @x ^ y@-  | OpBitXorAssign  -- ^ @x ^= y@-  | OpShl  -- ^ @x << y@-  | OpShlAssign  -- ^ @x <<= y@-  | OpShr  -- ^ @x >> y@-  | OpShrAssign  -- ^ @x >>= y@-  deriving (Bounded, Enum, Eq, Ord, Show)---- | The arity and syntax of an operator.-data OperatorType =-  UnaryPrefixOperator String  -- ^ Prefix unary operators.  Examples: @!x@, @*x@, @++x@.-  | UnaryPostfixOperator String  -- ^ Postfix unary operators.  Examples: @x--, x++@.-  | BinaryOperator String  -- ^ Infix binary operators.  Examples: @x * y@, @x >>= y@.-  | CallOperator  -- ^ @x(...)@ with arbitrary arity.-  | ArrayOperator  -- ^ @x[y]@, a binary operator with non-infix syntax.--data OperatorInfo = OperatorInfo-  { operatorPreferredExtName'' :: ExtName-  , operatorType' :: OperatorType-  }--makeOperatorInfo :: String -> OperatorType -> OperatorInfo-makeOperatorInfo = OperatorInfo . toExtName---- | Returns a conventional string to use for the 'ExtName' of an operator.-operatorPreferredExtName :: Operator -> ExtName-operatorPreferredExtName op = case M.lookup op operatorInfo of-  Just info -> operatorPreferredExtName'' info-  Nothing ->-    error $ concat-    ["operatorPreferredExtName: Internal error, missing info for operator ", show op, "."]---- | Returns a conventional name for an operator, as with--- 'operatorPreferredExtName', but as a string.-operatorPreferredExtName' :: Operator -> String-operatorPreferredExtName' = fromExtName . operatorPreferredExtName---- | Returns the type of an operator.-operatorType :: Operator -> OperatorType-operatorType op = case M.lookup op operatorInfo of-  Just info -> operatorType' info-  Nothing ->-    error $ concat-    ["operatorType: Internal error, missing info for operator ", show op, "."]---- | Metadata for operators.------ TODO Test out this missing data.-operatorInfo :: M.Map Operator OperatorInfo-operatorInfo =-  let input =-        [ (OpCall, makeOperatorInfo "CALL" CallOperator)-        , (OpComma, makeOperatorInfo "COMMA" $ BinaryOperator ",")-        , (OpAssign, makeOperatorInfo "ASSIGN" $ BinaryOperator "=")-        , (OpArray, makeOperatorInfo "ARRAY" ArrayOperator)-        , (OpDeref, makeOperatorInfo "DEREF" $ UnaryPrefixOperator "*")-        , (OpAddress, makeOperatorInfo "ADDRESS" $ UnaryPrefixOperator "&")-        , (OpAdd, makeOperatorInfo "ADD" $ BinaryOperator "+")-        , (OpAddAssign, makeOperatorInfo "ADDA" $ BinaryOperator "+=")-        , (OpSubtract, makeOperatorInfo "SUB" $ BinaryOperator "-")-        , (OpSubtractAssign, makeOperatorInfo "SUBA" $ BinaryOperator "-=")-        , (OpMultiply, makeOperatorInfo "MUL" $ BinaryOperator "*")-        , (OpMultiplyAssign, makeOperatorInfo "MULA" $ BinaryOperator "*=")-        , (OpDivide, makeOperatorInfo "DIV" $ BinaryOperator "/")-        , (OpDivideAssign, makeOperatorInfo "DIVA" $ BinaryOperator "/=")-        , (OpModulo, makeOperatorInfo "MOD" $ BinaryOperator "%")-        , (OpModuloAssign, makeOperatorInfo "MODA" $ BinaryOperator "%=")-        , (OpPlus, makeOperatorInfo "PLUS" $ UnaryPrefixOperator "+")-        , (OpMinus, makeOperatorInfo "NEG" $ UnaryPrefixOperator "-")-        , (OpIncPre, makeOperatorInfo "INC" $ UnaryPrefixOperator "++")-        , (OpIncPost, makeOperatorInfo "INCPOST" $ UnaryPostfixOperator "++")-        , (OpDecPre, makeOperatorInfo "DEC" $ UnaryPrefixOperator "--")-        , (OpDecPost, makeOperatorInfo "DECPOST" $ UnaryPostfixOperator "--")-        , (OpEq, makeOperatorInfo "EQ" $ BinaryOperator "==")-        , (OpNe, makeOperatorInfo "NE" $ BinaryOperator "!=")-        , (OpLt, makeOperatorInfo "LT" $ BinaryOperator "<")-        , (OpLe, makeOperatorInfo "LE" $ BinaryOperator "<=")-        , (OpGt, makeOperatorInfo "GT" $ BinaryOperator ">")-        , (OpGe, makeOperatorInfo "GE" $ BinaryOperator ">=")-        , (OpNot, makeOperatorInfo "NOT" $ UnaryPrefixOperator "!")-        , (OpAnd, makeOperatorInfo "AND" $ BinaryOperator "&&")-        , (OpOr, makeOperatorInfo "OR" $ BinaryOperator "||")-        , (OpBitNot, makeOperatorInfo "BNOT" $ UnaryPrefixOperator "~")-        , (OpBitAnd, makeOperatorInfo "BAND" $ BinaryOperator "&")-        , (OpBitAndAssign, makeOperatorInfo "BANDA" $ BinaryOperator "&=")-        , (OpBitOr, makeOperatorInfo "BOR" $ BinaryOperator "|")-        , (OpBitOrAssign, makeOperatorInfo "BORA" $ BinaryOperator "|=")-        , (OpBitXor, makeOperatorInfo "BXOR" $ BinaryOperator "^")-        , (OpBitXorAssign, makeOperatorInfo "BXORA" $ BinaryOperator "^=")-        , (OpShl, makeOperatorInfo "SHL" $ BinaryOperator "<<")-        , (OpShlAssign, makeOperatorInfo "SHLA" $ BinaryOperator "<<=")-        , (OpShr, makeOperatorInfo "SHR" $ BinaryOperator ">>")-        , (OpShrAssign, makeOperatorInfo "SHR" $ BinaryOperator ">>=")-        ]-  in if map fst input == [minBound..]-     then M.fromList input-     else error "operatorInfo: Operator info list is out of sync with Operator data type."---- | Specifies some C++ object (function or class) to give access to.-data Export =-  ExportVariable Variable  -- ^ Exports a variable.-  | ExportEnum CppEnum  -- ^ Exports an enum.-  | ExportBitspace Bitspace  -- ^ Exports a bitspace.-  | ExportFn Function  -- ^ Exports a function.-  | ExportClass Class  -- ^ Exports a class with all of its contents.-  | ExportCallback Callback  -- ^ Exports a callback.-  deriving (Show)---- | Returns the external name of an export.-exportExtName :: Export -> ExtName-exportExtName export = case export of-  ExportVariable v -> varExtName v-  ExportEnum e -> enumExtName e-  ExportBitspace b -> bitspaceExtName b-  ExportFn f -> fnExtName f-  ExportClass c -> classExtName c-  ExportCallback cb -> callbackExtName cb---- | Returns the export's addendum.  'Export' doesn't have a 'HasAddendum'--- instance because you normally wouldn't want to modify the addendum of one.-exportAddendum export = case export of-  ExportVariable v -> getAddendum v-  ExportEnum e -> getAddendum e-  ExportBitspace bs -> getAddendum bs-  ExportFn f -> getAddendum f-  ExportClass cls -> getAddendum cls-  ExportCallback cb -> getAddendum cb---- | A path to some C++ object, including namespaces.  An identifier consists of--- multiple parts separated by @\"::\"@.  Each part has a name string followed--- by an optional template argument list, where each argument gets rendered from--- a 'Type' (non-type arguments for template metaprogramming are not supported).-newtype Identifier = Identifier-  { identifierParts :: [IdPart]-    -- ^ The separate parts of the identifier, between @::@s.-  } deriving (Eq)--instance Show Identifier where-  show ident =-    (\words -> concat $ "<Identifier " : words ++ [">"]) $-    intersperse "::" $-    map (\part -> case idPartArgs part of-            Nothing -> idPartBase part-            Just args ->-              concat $-              idPartBase part : "<" :-              intersperse ", " (map show args) ++ [">"]) $-    identifierParts ident---- | A single component of an 'Identifier', between @::@s.-data IdPart = IdPart-  { idPartBase :: String-    -- ^ The name within the enclosing scope.-  , idPartArgs :: Maybe [Type]-    -- ^ Template arguments, if present.-  } deriving (Eq, Show)---- | Creates an identifier of the form @a@.-ident :: String -> Identifier-ident a = Identifier [IdPart a Nothing]---- | Creates an identifier of the form @a1::a2::...::aN@.-ident' :: [String] -> Identifier-ident' = Identifier . map (\x -> IdPart x Nothing)---- | Creates an identifier of the form @a::b@.-ident1 :: String -> String -> Identifier-ident1 a b = ident' [a, b]---- | Creates an identifier of the form @a::b::c@.-ident2 :: String -> String -> String -> Identifier-ident2 a b c = ident' [a, b, c]---- | Creates an identifier of the form @a::b::c::d@.-ident3 :: String -> String -> String -> String -> Identifier-ident3 a b c d = ident' [a, b, c, d]---- | Creates an identifier of the form @a::b::c::d::e@.-ident4 :: String -> String -> String -> String -> String -> Identifier-ident4 a b c d e = ident' [a, b, c, d, e]---- | Creates an identifier of the form @a::b::c::d::e::f@.-ident5 :: String -> String -> String -> String -> String -> String -> Identifier-ident5 a b c d e f = ident' [a, b, c, d, e, f]---- | Creates an identifier of the form @a\<...\>@.-identT :: String -> [Type] -> Identifier-identT a ts = Identifier [IdPart a $ Just ts]---- | Creates an identifier with arbitrary many templated and non-templated--- parts.-identT' :: [(String, Maybe [Type])] -> Identifier-identT' = Identifier . map (uncurry IdPart)---- | Creates an identifier of the form @a::b\<...\>@.-ident1T :: String -> String -> [Type] -> Identifier-ident1T a b ts = Identifier [IdPart a Nothing, IdPart b $ Just ts]---- | Creates an identifier of the form @a::b::c\<...\>@.-ident2T :: String -> String -> String -> [Type] -> Identifier-ident2T a b c ts = Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c $ Just ts]---- | Creates an identifier of the form @a::b::c::d\<...\>@.-ident3T :: String -> String -> String -> String -> [Type] -> Identifier-ident3T a b c d ts =-  Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c Nothing,-              IdPart d $ Just ts]---- | Creates an identifier of the form @a::b::c::d::e\<...\>@.-ident4T :: String -> String -> String -> String -> String -> [Type] -> Identifier-ident4T a b c d e ts =-  Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c Nothing,-              IdPart d Nothing, IdPart e $ Just ts]---- | Creates an identifier of the form @a::b::c::d::e::f\<...\>@.-ident5T :: String -> String -> String -> String -> String -> String -> [Type] -> Identifier-ident5T a b c d e f ts =-  Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c Nothing,-              IdPart d Nothing, IdPart e Nothing, IdPart f $ Just ts]---- | A concrete C++ type.  Use the bindings in "Foreign.Hoppy.Generator.Types"--- for values of this type; these data constructors are subject to change--- without notice.-data Type =-    Internal_TVoid-  | Internal_TBool-  | Internal_TChar-  | Internal_TUChar-  | Internal_TShort-  | Internal_TUShort-  | Internal_TInt-  | Internal_TUInt-  | Internal_TLong-  | Internal_TULong-  | Internal_TLLong-  | Internal_TULLong-  | Internal_TFloat-  | Internal_TDouble-  | Internal_TInt8-  | Internal_TInt16-  | Internal_TInt32-  | Internal_TInt64-  | Internal_TWord8-  | Internal_TWord16-  | Internal_TWord32-  | Internal_TWord64-  | Internal_TPtrdiff-  | Internal_TSize-  | Internal_TSSize-  | Internal_TEnum CppEnum-  | Internal_TBitspace Bitspace-  | Internal_TPtr Type-  | Internal_TRef Type-  | Internal_TFn [Type] Type-  | Internal_TCallback Callback-  | Internal_TObj Class-  | Internal_TObjToHeap Class-  | Internal_TToGc Type-  | Internal_TConst Type-  deriving (Eq, Show)---- | Canonicalizes a 'Type' without changing its meaning.  Multiple nested--- 'Internal_TConst's are collapsed into a single one.-normalizeType :: Type -> Type-normalizeType t = case t of-  Internal_TVoid -> t-  Internal_TBool -> t-  Internal_TChar -> t-  Internal_TUChar -> t-  Internal_TShort -> t-  Internal_TUShort -> t-  Internal_TInt -> t-  Internal_TUInt -> t-  Internal_TLong -> t-  Internal_TULong -> t-  Internal_TLLong -> t-  Internal_TULLong -> t-  Internal_TFloat -> t-  Internal_TDouble -> t-  Internal_TInt8 -> t-  Internal_TInt16 -> t-  Internal_TInt32 -> t-  Internal_TInt64 -> t-  Internal_TWord8 -> t-  Internal_TWord16 -> t-  Internal_TWord32 -> t-  Internal_TWord64 -> t-  Internal_TPtrdiff -> t-  Internal_TSize -> t-  Internal_TSSize -> t-  Internal_TEnum _ -> t-  Internal_TBitspace _ -> t-  Internal_TPtr t' -> Internal_TPtr $ normalizeType t'-  Internal_TRef t' -> Internal_TRef $ normalizeType t'-  Internal_TFn paramTypes retType ->-    Internal_TFn (map normalizeType paramTypes) $ normalizeType retType-  Internal_TCallback _ -> t-  Internal_TObj _ -> t-  Internal_TObjToHeap _ -> t-  Internal_TToGc _ -> t-  Internal_TConst (Internal_TConst t') -> normalizeType $ Internal_TConst t'-  Internal_TConst _ -> t---- | Strips leading 'Internal_TConst's off of a type.-stripConst :: Type -> Type-stripConst t = case t of-  Internal_TConst t' -> stripConst t'-  _ -> t---- | A C++ variable.-data Variable = Variable-  { varIdentifier :: Identifier-    -- ^ The identifier used to refer to the variable.-  , varExtName :: ExtName-    -- ^ The variable's external name.-  , varType :: Type-    -- ^ The type of the variable.  This may be-    -- 'Foreign.Hoppy.Generator.Types.constT' to indicate that the variable is-    -- read-only.-  , varReqs :: Reqs-    -- ^ Requirements for bindings to use this variable.-  , varAddendum :: Addendum-    -- ^ The variable's addendum.-  }--instance Eq Variable where-  (==) = (==) `on` varIdentifier--instance Show Variable where-  show v = concat ["<Variable ", show (varExtName v), " ", show (varType v), ">"]--instance HasReqs Variable where-  getReqs = varReqs-  setReqs reqs v = v { varReqs = reqs }--instance HasAddendum Variable where-  getAddendum = varAddendum-  setAddendum addendum v = v { varAddendum = addendum }---- | Creates a binding for a C++ variable.-makeVariable :: Identifier -> Maybe ExtName -> Type -> Variable-makeVariable identifier maybeExtName t =-  Variable identifier (extNameOrIdentifier identifier maybeExtName) t mempty mempty---- | Returns whether the variable is constant, i.e. whether its type is--- @'Foreign.Hoppy.Generator.Types.constT' ...@.-varIsConst :: Variable -> Bool-varIsConst v = case varType v of-  Internal_TConst _ -> True-  _ -> False---- | Returns the external name of the getter function for the variable.-varGetterExtName :: Variable -> ExtName-varGetterExtName = toExtName . (++ "_get") . fromExtName . varExtName---- | Returns the external name of the setter function for the variable.-varSetterExtName :: Variable -> ExtName-varSetterExtName = toExtName . (++ "_set") . fromExtName . varExtName---- | A C++ enum declaration.  An enum should actually be enumerable (in the--- sense of Haskell's 'Enum'); if it's not, consider using a 'Bitspace' instead.-data CppEnum = CppEnum-  { enumIdentifier :: Identifier-    -- ^ The identifier used to refer to the enum.-  , enumExtName :: ExtName-    -- ^ The enum's external name.-  , enumValueNames :: [(Int, [String])]-    -- ^ The numeric values and names of the enum values.  A single value's name-    -- is broken up into words.  How the words and ext name get combined to make-    -- a name in a particular foreign language depends on the language.-  , enumReqs :: Reqs-    -- ^ Requirements for a 'Type' to reference this enum.-  , enumAddendum :: Addendum-    -- ^ The enum's addendum.-  }--instance Eq CppEnum where-  (==) = (==) `on` enumIdentifier--instance Show CppEnum where-  show e = concat ["<Enum ", show (enumExtName e), " ", show (enumIdentifier e), ">"]--instance HasReqs CppEnum where-  getReqs = enumReqs-  setReqs reqs e = e { enumReqs = reqs }--instance HasAddendum CppEnum where-  getAddendum = enumAddendum-  setAddendum addendum e = e { enumAddendum = addendum }---- | Creates a binding for a C++ enum.-makeEnum :: Identifier  -- ^ 'enumIdentifier'-         -> Maybe ExtName-         -- ^ An optional external name; will be automatically derived from-         -- the identifier if absent.-         -> [(Int, [String])]  -- ^ 'enumValueNames'-         -> CppEnum-makeEnum identifier maybeExtName valueNames =-  CppEnum identifier (extNameOrIdentifier identifier maybeExtName) valueNames mempty mempty---- | A C++ numeric space with bitwise operations.  This is similar to a--- 'CppEnum', but in addition to the extra operations, this differs in that--- these values aren't enumerable.------ Additionally, as a kludge for Qtah, a bitspace may have a C++ type--- ('bitspaceCppTypeIdentifier') separate from its numeric type--- ('bitspaceType').  Qt bitspaces aren't raw numbers but are instead type-safe--- @QFlags@ objects that don't implicitly convert from integers, so we need a--- means to do so manually.  Barring general ad-hoc argument and return value--- conversion support, we allow this as follows: when given a C++ type, then a--- bitspace may also have a conversion function between the numeric and C++--- type, in each direction.  If a conversion function is present, it will be--- used for conversions in its respective direction.  The C++ type is not a full--- 'Type', but only an 'Identifier', since additional information is not needed.--- See 'bitspaceAddCppType'.-data Bitspace = Bitspace-  { bitspaceExtName :: ExtName-    -- ^ The bitspace's external name.-  , bitspaceType :: Type-    -- ^ The C++ type used for bits values.  This should be a primitive numeric-    -- type, usually 'Foreign.Hoppy.Generator.Types.intT'.-  , bitspaceValueNames :: [(Int, [String])]-    -- ^ The numeric values and names of the bitspace values.  See-    -- 'enumValueNames'.-  , bitspaceEnum :: Maybe CppEnum-    -- ^ An associated enum, whose values may be converted to values in the-    -- bitspace.-  , bitspaceCppTypeIdentifier :: Maybe Identifier-    -- ^ The optional C++ type for a bitspace.-  , bitspaceToCppValueFn :: Maybe String-    -- ^ The name of a C++ function to convert from 'bitspaceType' to the-    -- bitspace's C++ type.-  , bitspaceFromCppValueFn :: Maybe String-    -- ^ The name of a C++ function to convert from the bitspace's C++ type to-    -- 'bitspaceType'.-  , bitspaceReqs :: Reqs-    -- ^ Requirements for emitting the bindings for a bitspace, i.e. what's-    -- necessary to reference 'bitspaceCppTypeIdentifier',-    -- 'bitspaceFromCppValueFn', and 'bitspaceToCppValueFn'.  'bitspaceType' can-    -- take some numeric types that require includes as well, but you don't need-    -- to list these here.-  , bitspaceAddendum :: Addendum-    -- ^ The bitspace's addendum.-  }--instance Eq Bitspace where-  (==) = (==) `on` bitspaceExtName--instance Show Bitspace where-  show e = concat ["<Bitspace ", show (bitspaceExtName e), " ", show (bitspaceType e), ">"]--instance HasReqs Bitspace where-  getReqs = bitspaceReqs-  setReqs reqs b = b { bitspaceReqs = reqs }--instance HasAddendum Bitspace where-  getAddendum = bitspaceAddendum-  setAddendum addendum bs = bs { bitspaceAddendum = addendum }---- | Creates a binding for a C++ bitspace.-makeBitspace :: ExtName  -- ^ 'bitspaceExtName'-             -> Type  -- ^ 'bitspaceType'-             -> [(Int, [String])]  -- ^ 'bitspaceValueNames'-             -> Bitspace-makeBitspace extName t valueNames =-  Bitspace extName t valueNames Nothing Nothing Nothing Nothing mempty mempty---- | Associates an enum with the bitspace.  See 'bitspaceEnum'.-bitspaceAddEnum :: CppEnum -> Bitspace -> Bitspace-bitspaceAddEnum enum bitspace = case bitspaceEnum bitspace of-  Just enum' ->-    error $ concat-    ["bitspaceAddEnum: Adding ", show enum, " to ", show bitspace,-     ", but it already has ", show enum', "."]-  Nothing ->-    if bitspaceValueNames bitspace /= enumValueNames enum-    then error $ concat-         ["bitspaceAddEnum: Trying to add ", show enum, " to ", show bitspace,-          ", but the values aren't equal.\nBitspace values: ", show $ bitspaceValueNames bitspace,-          "\n    Enum values: ", show $ enumValueNames enum]-    else bitspace { bitspaceEnum = Just enum }---- | @bitspaceAddCppType cppTypeIdentifier toCppValueFn fromCppValueFn@--- associates a C++ type (plus optional conversion functions) with a bitspace.--- At least one conversion should be specified, otherwise adding the C++ type--- will mean nothing.  You should also add use requirements to the bitspace for--- all of these arguments; see 'HasReqs'.-bitspaceAddCppType :: Identifier -> Maybe String -> Maybe String -> Bitspace -> Bitspace-bitspaceAddCppType cppTypeId toCppValueFnMaybe fromCppValueFnMaybe b =-  case bitspaceCppTypeIdentifier b of-    Just cppTypeId' ->-      error $ concat-      ["bitspaceAddCppType: Adding C++ type ", show cppTypeId,-       " to ", show b, ", but it already has ", show cppTypeId', "."]-    Nothing ->-      b { bitspaceCppTypeIdentifier = Just cppTypeId-        , bitspaceToCppValueFn = toCppValueFnMaybe-        , bitspaceFromCppValueFn = fromCppValueFnMaybe-        }---- | Whether or not a function may cause side-effects.------ Haskell bindings for pure functions will not be in 'IO', and calls to pure--- functions will be executed non-strictly.  Calls to impure functions will--- execute in the IO monad.------ Member functions for mutable classes should not be made pure, because it is--- difficult in general to control when the call will be made.-data Purity = Nonpure  -- ^ Side-affects are possible.-            | Pure  -- ^ Side-affects will not happen.-            deriving (Eq, Show)---- | A C++ function declaration.-data Function = Function-  { fnCName :: FnName Identifier-    -- ^ The identifier used to call the function.-  , fnExtName :: ExtName-    -- ^ The function's external name.-  , fnPurity :: Purity-    -- ^ Whether the function is pure.-  , fnParams :: [Type]-    -- ^ The function's parameter types.-  , fnReturn :: Type-    -- ^ The function's return type.-  , fnReqs :: Reqs-    -- ^ Requirements for a binding to call the function.-  , fnAddendum :: Addendum-    -- ^ The function's addendum.-  }--instance Show Function where-  show fn =-    concat ["<Function ", show (fnExtName fn), " ", show (fnCName fn),-            show (fnParams fn), " ", show (fnReturn fn), ">"]--instance HasReqs Function where-  getReqs = fnReqs-  setReqs reqs fn = fn { fnReqs = reqs }--instance HasAddendum Function where-  getAddendum = fnAddendum-  setAddendum addendum fn = fn { fnAddendum = addendum }---- | Creates a binding for a C++ function.-makeFn :: IsFnName Identifier name-       => name-       -> Maybe ExtName-       -- ^ An optional external name; will be automatically derived from-       -- the identifier if absent.-       -> Purity-       -> [Type]  -- ^ Parameter types.-       -> Type  -- ^ Return type.-       -> Function-makeFn cName maybeExtName purity paramTypes retType =-  let fnName = toFnName cName-  in Function fnName-              (extNameOrFnIdentifier fnName maybeExtName)-              purity paramTypes retType mempty mempty---- | A C++ class declaration.  A class's external name is automatically combined--- with the external names of things inside the class, by way of--- 'HasClassyExtName'.-data Class = Class-  { classIdentifier :: Identifier-    -- ^ The identifier used to refer to the class.-  , classExtName :: ExtName-    -- ^ The class's external name.-  , classSuperclasses :: [Class]-    -- ^ The class's public superclasses.-  , classCtors :: [Ctor]-    -- ^ The class's constructors.-  , classDtorIsPublic :: Bool-    -- ^ Whether the class's destructor has public visibility.-  , classMethods :: [Method]-    -- ^ The class's methods.-  , classConversion :: ClassConversion-    -- ^ Behaviour for converting objects to and from foriegn values.-  , classReqs :: Reqs-    -- ^ Requirements for a 'Type' to reference this class.-  , classAddendum :: Addendum-    -- ^ The class's addendum.-  , classIsMonomorphicSuperclass :: Bool-    -- ^ This is true for classes passed through-    -- 'classSetMonomorphicSuperclass'.-  , classIsSubclassOfMonomorphic :: Bool-    -- ^ This is true for classes passed through-    -- 'classSetSubclassOfMonomorphic'.-  }--instance Eq Class where-  (==) = (==) `on` classIdentifier--instance Show Class where-  show cls =-    concat ["<Class ", show (classExtName cls), " ", show (classIdentifier cls), ">"]--instance HasReqs Class where-  getReqs = classReqs-  setReqs reqs cls = cls { classReqs = reqs }--instance HasAddendum Class where-  getAddendum = classAddendum-  setAddendum addendum cls = cls { classAddendum = addendum }---- | Creates a binding for a C++ class and its contents.-makeClass :: Identifier-          -> Maybe ExtName-          -- ^ An optional external name; will be automatically derived from the-          -- identifier if absent.-          -> [Class]  -- ^ Superclasses.-          -> [Ctor]-          -> [Method]-          -> Class-makeClass identifier maybeExtName supers ctors methods = Class-  { classIdentifier = identifier-  , classExtName = extNameOrIdentifier identifier maybeExtName-  , classSuperclasses = supers-  , classCtors = ctors-  , classDtorIsPublic = True-  , classMethods = methods-  , classConversion = classConversionNone-  , classReqs = mempty-  , classAddendum = mempty-  , classIsMonomorphicSuperclass = False-  , classIsSubclassOfMonomorphic = False-  }---- | Adds constructors to a class.-classAddCtors :: [Ctor] -> Class -> Class-classAddCtors ctors cls =-  if null ctors then cls else cls { classCtors = classCtors cls ++ ctors }---- | Marks a class's destructor as private, so that a binding for it won't be--- generated.-classSetDtorPrivate :: Class -> Class-classSetDtorPrivate cls = cls { classDtorIsPublic = False }---- | Explicitly marks a class as being monomorphic (i.e. not having any--- virtual methods or destructors).  By default, Hoppy assumes that a class that--- is derived is also polymorphic, but it can happen that this is not the case.--- Downcasting with @dynamic_cast@ from such classes is not available.  See also--- 'classSetSubclassOfMonomorphic'.-classSetMonomorphicSuperclass :: Class -> Class-classSetMonomorphicSuperclass cls = cls { classIsMonomorphicSuperclass = True }---- | Marks a class as being derived from some monomorphic superclass.  This--- prevents any downcasting to this class.  Generally it is better to use--- 'classSetMonomorphicSuperclass' on the specific superclasses that are--- monomorphic, but in cases where this is not possible, this function can be--- applied to the subclass instead.-classSetSubclassOfMonomorphic :: Class -> Class-classSetSubclassOfMonomorphic cls = cls { classIsSubclassOfMonomorphic = True }---- | Adds methods to a class.-classAddMethods :: [Method] -> Class -> Class-classAddMethods methods cls =-  if null methods then cls else cls { classMethods = classMethods cls ++ methods }---- | When a class object is returned from a function or taken as a parameter by--- value (i.e. with 'Foreign.Hoppy.Generator.Types.objT'), it will be converted--- to or from a foreign (non-C++) object.  Conversion may also be performed--- explicitly.  This data type describes how to perform those conversions.  A--- class may or may not support conversion, for any particular foreign language;--- what is said below only applies to classes that are convertible for a--- language.------ When converting between a C++ value and a foreign value, a pointer to the--- object is passed between C++ and the foreign language.  Then, for each--- foreign language, a binding author can provide pieces of code in that--- language to translate between the pointer and a foreign value (usually by--- invoking the FFI functions generated by Hoppy), and generated bindings will--- perform these conversions automatically.  The code supplied to convert in--- each direction should leave the original object unchanged (and alive, in case--- of manual memory management).  (Internally, during a function call in either--- direction, the side that creates a value is in charge of its lifetime, but--- this is managed by Hoppy.)------ In foreign code, foreign values can be explicitly converted to new C++ (heap)--- objects, and C++ object pointers can be explicitly converted to foreign--- values, via special functions generated for the class.-data ClassConversion = ClassConversion-  { classHaskellConversion :: ClassConversionMode ClassHaskellConversion-    -- ^ Conversions to and from Haskell.--    -- NOTE!  When adding new languages here, add the language to-    -- 'classSetConversionToHeap', and 'classSetConversionToGc' as well if the-    -- language supports garbage collection.-  }---- | Specifies whether (and if so, how) objects of a class get converted to and--- from values in a specific foreign language.-data ClassConversionMode a =-    ClassConversionNone-    -- ^ Indicates that a class __is not__ convertible for a language.  Passing-    -- raw 'Foreign.Hoppy.Generator.Types.objT' values into and out of C++ is-    -- not allowed.-  | ClassConversionManual a-    -- ^ Indicates that a class __is__ convertible for a language.  Passing raw-    -- 'Foreign.Hoppy.Generator.Types.objT' values into and out of C++ is-    -- allowed, and the attached structure describes how to perform the-    -- conversions.-  | ClassConversionToHeap-    -- ^ Indicates that a class __is not__ convertible for a language.-    -- Nevertheless, passing an object from C++ to the foreign language via a-    -- type of @'Foreign.Hoppy.Generator.Types.objT' cls@ is allowed, and-    -- behaves as though the type were-    -- @'Foreign.Hoppy.Generator.Types.objToHeapT' cls@ instead.-  | ClassConversionToGc-    -- ^ Indicates that a class __is not__ convertible for a language.-    -- Nevertheless, passing an object from C++ to the foreign language via a-    -- type of @'Foreign.Hoppy.Generator.Types.objT' cls@ is allowed, and-    -- behaves as though the type were @'Foreign.Hoppy.Generator.Types.toGcT'-    -- ('Foreign.Hoppy.Generator.Types.objT' cls)@ instead.-    ---    -- This should be used for value objects so that you can simply use-    -- @'Foreign.Hoppy.Generator.Types.objT' cls@ in return types, and also-    -- write on @'mkProp' "..." ('Foreign.Hoppy.Generator.Types.objT' cls)@.---- | Encoding parameters for a class that is not encodable or decodable.-classConversionNone :: ClassConversion-classConversionNone = ClassConversion ClassConversionNone---- | Modifies a class's 'ClassConversion' structure with a given function.-classModifyConversion :: (ClassConversion -> ClassConversion) -> Class -> Class-classModifyConversion f cls = cls { classConversion = f $ classConversion cls }---- | Replaces a class's 'ClassConversion' structure.-classSetConversion :: ClassConversion -> Class -> Class-classSetConversion c cls = cls { classConversion = c }---- | Modifies a class's 'ClassConversion' structure by setting all languages--- to use 'ClassConversionToHeap'.-classSetConversionToHeap :: Class -> Class-classSetConversionToHeap cls = flip classModifyConversion cls $ \c ->-  c { classHaskellConversion = ClassConversionToHeap-    }---- | Modifies a class's 'ClassConversion' structure by setting all languages--- that support garbage collection to use 'ClassConversionToGc'.-classSetConversionToGc :: Class -> Class-classSetConversionToGc cls = flip classModifyConversion cls $ \c ->-  c { classHaskellConversion = ClassConversionToGc-    }---- | Replaces a class's 'classHaskellConversion' with a given value.-classSetHaskellConversion :: ClassHaskellConversion -> Class -> Class-classSetHaskellConversion conv = classModifyConversion $ \c ->-  c { classHaskellConversion = ClassConversionManual conv }---- | Controls how conversions between C++ objects and Haskell values happen in--- Haskell bindings.-data ClassHaskellConversion = ClassHaskellConversion-  { classHaskellConversionType :: Haskell.Generator HsType-    -- ^ Produces the Haskell type that represents a value of the corresponding-    -- C++ class.  This generator may add imports, but must not output code or-    -- add exports.-  , classHaskellConversionToCppFn :: Haskell.Generator ()-    -- ^ Produces a Haskell expression that evaluates to a function that takes-    -- an object of the type that 'classHaskellConversionType' generates, and-    -- returns a pointer to a new non-const C++ class object in IO.  The-    -- generator must output code and may add imports, but must not add exports.-  , classHaskellConversionFromCppFn :: Haskell.Generator ()-    -- ^ Produces a Haskell expression that evaluates to a function that takes a-    -- pointer to a const C++ class object, and returns an object of the type-    -- that 'classHaskellConversionType' generates, in IO.  The generator must-    -- output code and may add imports, but must not add exports.-  }---- | Things that live inside of a class, and have the class's external name--- prepended to their own in generated code.  With an external name of @\"bar\"@--- and a class with external name @\"foo\"@, the resulting name will be--- @\"foo_bar\"@.-class HasClassyExtName a where-  -- | Extracts the external name of the object, without the class name added.-  getClassyExtNameSuffix :: a -> ExtName--  -- | Computes the external name to use in generated code, containing both the-  -- class's and object's external names.-  ---  -- See also 'Foreign.Hoppy.Generator.Language.Haskell.General.toHsMethodName'.-  getClassyExtName :: Class -> a -> ExtName-  getClassyExtName cls x =-    toExtName $ concat [fromExtName $ classExtName cls, "_", fromExtName $ getClassyExtNameSuffix x]---- | A C++ class constructor declaration.-data Ctor = Ctor-  { ctorExtName :: ExtName-    -- ^ The constructor's external name.-  , ctorParams :: [Type]-    -- ^ The constructor's parameter types.-  }--instance Show Ctor where-  show ctor = concat ["<Ctor ", show (ctorExtName ctor), " ", show (ctorParams ctor), ">"]--instance HasClassyExtName Ctor where-  getClassyExtNameSuffix = ctorExtName---- | Creates a 'Ctor' with full generality.-makeCtor :: ExtName-         -> [Type]  -- ^ Parameter types.-         -> Ctor-makeCtor = Ctor---- | @mkCtor name@ creates a 'Ctor' whose external name is @className_name@.-mkCtor :: String-       -> [Type]  -- ^ Parameter types.-       -> Ctor-mkCtor = makeCtor . toExtName---- | A C++ class method declaration.------ Any operator function that can be written as a method may have its binding be--- written either as part of the associated class or as a separate entity,--- independently of how the function is declared in C++.-data Method = Method-  { methodImpl :: MethodImpl-    -- ^ The underlying code that the binding calls.-  , methodExtName :: ExtName-    -- ^ The method's external name.-  , methodApplicability :: MethodApplicability-    -- ^ How the method is associated to its class.-  , methodPurity :: Purity-    -- ^ Whether the method is pure.-  , methodParams :: [Type]-    -- ^ The method's parameter types.-  , methodReturn :: Type-    -- ^ The method's return type.-  }--instance Show Method where-  show method =-    concat ["<Method ", show (methodExtName method), " ",-            case methodImpl method of-              RealMethod name -> show name-              FnMethod name -> show name, " ",-            show (methodApplicability method), " ",-            show (methodPurity method), " ",-            show (methodParams method), " ",-            show (methodReturn method), ">"]--instance HasClassyExtName Method where-  getClassyExtNameSuffix = methodExtName---- | The C++ code to which a 'Method' is bound.-data MethodImpl =-  RealMethod (FnName String)-  -- ^ The 'Method' is bound to an actual class method.-  | FnMethod (FnName Identifier)-    -- ^ The 'Method' is bound to a wrapper function.  When wrapping a method-    -- with another function, this is preferrable to just using a 'Function'-    -- binding because a method will still appear to be part of the class in-    -- foreign bindings.-  deriving (Eq, Show)---- | How a method is associated to its class.  A method may be static, const, or--- neither (a regular method).-data MethodApplicability = MNormal | MStatic | MConst-                         deriving (Bounded, Enum, Eq, Show)---- | Whether or not a method is const.-data Constness = Nonconst | Const-               deriving (Bounded, Enum, Eq, Show)---- | Returns the opposite constness value.-constNegate :: Constness -> Constness-constNegate Nonconst = Const-constNegate Const = Nonconst---- | Whether or not a method is static.-data Staticness = Nonstatic | Static-               deriving (Bounded, Enum, Eq, Show)---- | Returns the constness of a method, based on its 'methodApplicability'.-methodConst :: Method -> Constness-methodConst method = case methodApplicability method of-  MConst -> Const-  _ -> Nonconst---- | Returns the staticness of a method, based on its 'methodApplicability'.-methodStatic :: Method -> Staticness-methodStatic method = case methodApplicability method of-  MStatic -> Static-  _ -> Nonstatic---- | Creates a 'Method' with full generality and manual name specification.-makeMethod :: IsFnName String name-           => name  -- ^ The C++ name of the method.-           -> ExtName  -- ^ The external name of the method.-           -> MethodApplicability-           -> Purity-           -> [Type]  -- ^ Parameter types.-           -> Type  -- ^ Return type.-           -> Method-makeMethod name = Method $ RealMethod $ toFnName name---- | Creates a 'Method' that is in fact backed by a C++ non-member function (a--- la 'makeFn'), but appears to be a regular method.  This is useful for--- wrapping a method on the C++ side when its arguments aren't right for binding--- directly.------ A @this@ pointer parameter is __not__ automatically added to the parameter--- list for non-static methods created with @makeFnMethod@.-makeFnMethod :: IsFnName Identifier name-             => name-             -> String-             -> MethodApplicability-             -> Purity-             -> [Type]-             -> Type-             -> Method-makeFnMethod cName foreignName = Method (FnMethod $ toFnName cName) (toExtName foreignName)---- | This function is internal.------ Creates a method similar to 'makeMethod', but with automatic naming.  The--- method's external name will be @className ++ \"_\" ++ cppMethodName@.  If the--- method name is a 'FnOp' then the 'operatorPreferredExtName' will be appeneded--- to the class name.------ For creating multiple bindings to a method, see 'makeMethod''.-makeMethod' :: IsFnName String name-            => name  -- ^ The C++ name of the method.-            -> MethodApplicability-            -> Purity-            -> [Type]  -- ^ Parameter types.-            -> Type  -- ^ Return type.-            -> Method-makeMethod' name = makeMethod''' (toFnName name) Nothing---- | This function is internal.------ Creates a method similar to 'makeMethod'', but with an custom string that--- will be appended to the class name to form the method's external name.  This--- is useful for making multiple bindings to a method, e.g. for overloading and--- optional arguments.-makeMethod'' :: IsFnName String name-             => name  -- ^ The C++ name of the method.-             -> String  -- ^ A foreign name for the method.-             -> MethodApplicability-             -> Purity-             -> [Type]  -- ^ Parameter types.-             -> Type  -- ^ Return type.-             -> Method-makeMethod'' name foreignName = makeMethod''' (toFnName name) $ Just foreignName---- | The implementation of 'makeMethod'' and 'makeMethod'''.-makeMethod''' :: FnName String  -- ^ The C++ name of the method.-              -> Maybe String  -- ^ A foreign name for the method.-              -> MethodApplicability-              -> Purity-              -> [Type]  -- ^ Parameter types.-              -> Type  -- ^ Return type.-              -> Method-makeMethod''' (FnName "") maybeForeignName _ _ paramTypes retType =-  error $ concat ["makeMethod''': Given an empty method name with foreign name ",-                  show maybeForeignName, ", parameter types ", show paramTypes,-                  ", and return type ", show retType, "."]-makeMethod''' name (Just "") _ _ paramTypes retType =-  error $ concat ["makeMethod''': Given an empty foreign name with method ",-                  show name, ", parameter types ", show paramTypes, ", and return type ",-                  show retType, "."]-makeMethod''' name maybeForeignName appl purity paramTypes retType =-  let extName = flip fromMaybe (toExtName <$> maybeForeignName) $ case name of-        FnName s -> toExtName s-        FnOp op -> operatorPreferredExtName op-  in makeMethod name extName appl purity paramTypes retType---- | Creates a nonconst, nonstatic 'Method' for @class::methodName@ and whose--- external name is @class_methodName@.  If the name is an operator, then the--- 'operatorPreferredExtName' will be used in the external name.------ For creating multiple bindings to a method, see 'mkMethod''.-mkMethod :: IsFnName String name-         => name  -- ^ The C++ name of the method.-         -> [Type]  -- ^ Parameter types.-         -> Type  -- ^ Return type.-         -> Method-mkMethod name = makeMethod' name MNormal Nonpure---- | Creates a nonconst, nonstatic 'Method' for method @class::methodName@ and--- whose external name is @class_methodName@.  This enables multiple 'Method's--- with different foreign names (and hence different external names) to bind to--- the same method, e.g. to make use of optional arguments or overloading.  See--- 'mkMethod' for a simpler form.-mkMethod' :: IsFnName String name-          => name  -- ^ The C++ name of the method.-          -> String  -- ^ A foreign name for the method.-          -> [Type]  -- ^ Parameter types.-          -> Type  -- ^ Return type.-          -> Method-mkMethod' cName foreignName = makeMethod'' cName foreignName MNormal Nonpure---- | Same as 'mkMethod', but returns an 'MConst' method.-mkConstMethod :: IsFnName String name => name -> [Type] -> Type -> Method-mkConstMethod name = makeMethod' name MConst Nonpure---- | Same as 'mkMethod'', but returns an 'MConst' method.-mkConstMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> Method-mkConstMethod' cName foreignName = makeMethod'' cName foreignName MConst Nonpure---- | Same as 'mkMethod', but returns an 'MStatic' method.-mkStaticMethod :: IsFnName String name => name -> [Type] -> Type -> Method-mkStaticMethod name = makeMethod' name MStatic Nonpure---- | Same as 'mkMethod'', but returns an 'MStatic' method.-mkStaticMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> Method-mkStaticMethod' cName foreignName = makeMethod'' cName foreignName MStatic Nonpure---- | Used in conjunction with 'mkProp' and friends, this creates a list of--- 'Method's for binding to getter/setter method pairs.  This can be used as--- follows:------ > myClass =--- >   makeClass ... $--- >   [ methods... ] ++--- >   mkProps--- >   [ mkBoolIsProp myClass "adjustable"--- >   , mkProp myClass "maxWidth" intT--- >   ]-mkProps :: [[Method]] -> [Method]-mkProps = concat---- | Creates a getter/setter binding pair for methods:------ > T getFoo() const--- > void setFoo(T)-mkProp :: String -> Type -> [Method]-mkProp name t =-  let c:cs = name-      setName = 's' : 'e' : 't' : toUpper c : cs-  in [ mkConstMethod name [] t-     , mkMethod setName [t] Internal_TVoid-     ]---- | Creates a getter/setter binding pair for static methods:------ > static T getFoo() const--- > static void setFoo(T)-mkStaticProp :: String -> Type -> [Method]-mkStaticProp name t =-  let c:cs = name-      setName = 's' : 'e' : 't' : toUpper c : cs-  in [ mkStaticMethod name [] t-     , mkStaticMethod setName [t] Internal_TVoid-     ]---- | Creates a getter/setter binding pair for boolean methods, where the getter--- is prefixed with @is@:------ > bool isFoo() const--- > void setFoo(bool)-mkBoolIsProp :: String -> [Method]-mkBoolIsProp name =-  let c:cs = name-      name' = toUpper c : cs-      isName = 'i':'s':name'-      setName = 's':'e':'t':name'-  in [ mkConstMethod isName [] Internal_TBool-     , mkMethod setName [Internal_TBool] Internal_TVoid-     ]---- | Creates a getter/setter binding pair for boolean methods, where the getter--- is prefixed with @has@:------ > bool hasFoo() const--- > void setFoo(bool)-mkBoolHasProp :: String -> [Method]-mkBoolHasProp name =-  let c:cs = name-      name' = toUpper c : cs-      hasName = 'h':'a':'s':name'-      setName = 's':'e':'t':name'-  in [ mkConstMethod hasName [] Internal_TBool-     , mkMethod setName [Internal_TBool] Internal_TVoid-     ]---- | A non-C++ function that can be invoked via a C++ functor.-data Callback = Callback-  { callbackExtName :: ExtName-    -- ^ The callback's external name.-  , callbackParams :: [Type]-    -- ^ The callback's parameter types.-  , callbackReturn :: Type-    -- ^ The callback's return type.-  , callbackReqs :: Reqs-    -- ^ Requirements for the callback.-  , callbackAddendum :: Addendum-    -- ^ The callback's addendum.-  }--instance Eq Callback where-  (==) = (==) `on` callbackExtName--instance Show Callback where-  show cb =-    concat ["<Callback ", show (callbackExtName cb), " ", show (callbackParams cb), " ",-            show (callbackReturn cb)]--instance HasReqs Callback where-  getReqs = callbackReqs-  setReqs reqs cb = cb { callbackReqs = reqs }--instance HasAddendum Callback where-  getAddendum = callbackAddendum-  setAddendum addendum cb = cb { callbackAddendum = addendum }---- | Creates a binding for constructing callbacks into foreign code.-makeCallback :: ExtName-             -> [Type]  -- ^ Parameter types.-             -> Type  -- ^ Return type.-             -> Callback-makeCallback extName paramTypes retType = Callback extName paramTypes retType mempty mempty---- | Creates a 'Foreign.Hoppy.Generator.Types.fnT' from a callback's parameter--- and return types.-callbackToTFn :: Callback -> Type-callbackToTFn = Internal_TFn <$> callbackParams <*> callbackReturn---- | A collection of imports for a Haskell module.  This is a monoid: import--- Statements are merged to give the union of imported bindings.------ This structure supports two specific types of imports:---     - @import Foo (...)@---     - @import qualified Foo as Bar@--- Imports with @as@ but without @qualified@, and @qualified@ imports with a--- spec list, are not supported.  This satisfies the needs of the code--- generator, and keeps the merging logic simple.-newtype HsImportSet = HsImportSet-  { getHsImportSet :: M.Map HsImportKey HsImportSpecs-    -- ^ Returns the import set's internal map from module names to imported-    -- bindings.-  } deriving (Show)--instance Monoid HsImportSet where-  mempty = HsImportSet M.empty--  mappend (HsImportSet m) (HsImportSet m') =-    HsImportSet $ M.unionWith mergeImportSpecs m m'--  mconcat sets =-    HsImportSet $ M.unionsWith mergeImportSpecs $ map getHsImportSet sets---- | A literal piece of code that will be inserted into a generated source file--- after the regular binding glue.  The 'Monoid' instance concatenates code--- (actions).-data Addendum = Addendum-  { addendumHaskell :: Haskell.Generator ()-    -- ^ Code to be output into the Haskell binding.  May also add imports and-    -- exports.-  }--instance Monoid Addendum where-  mempty = Addendum $ return ()-  mappend (Addendum a) (Addendum b) = Addendum $ a >> b---- | A typeclass for types that have an addendum.-class HasAddendum a where-  {-# MINIMAL getAddendum, (setAddendum | modifyAddendum) #-}--  -- | Returns an object's addendum.-  getAddendum :: a -> Addendum--  -- | Replaces and object's addendum with another.-  setAddendum :: Addendum -> a -> a-  setAddendum addendum = modifyAddendum $ const addendum--  -- | Modified an object's addendum.-  modifyAddendum :: (Addendum -> Addendum) -> a -> a-  modifyAddendum f x = setAddendum (f $ getAddendum x) x---- | Adds a Haskell addendum to an object.-addAddendumHaskell :: HasAddendum a => Haskell.Generator () -> a -> a-addAddendumHaskell gen = modifyAddendum $ \addendum ->-  addendum `mappend` mempty { addendumHaskell = gen }---- | Constructor for an import set.-makeHsImportSet :: M.Map HsImportKey HsImportSpecs -> HsImportSet-makeHsImportSet = HsImportSet---- | Sets all of the import specifications in an import set to be--- @{-#SOURCE#-}@ imports.-hsImportSetMakeSource :: HsImportSet -> HsImportSet-hsImportSetMakeSource (HsImportSet m) =-  HsImportSet $ M.map (\specs -> specs { hsImportSource = True }) m---- | A Haskell module name.-type HsModuleName = String---- | References an occurrence of an import statement, under which bindings can--- be imported.  Only imported specs under equal 'HsImportKey's may be merged.-data HsImportKey = HsImportKey-  { hsImportModule :: HsModuleName-  , hsImportQualifiedName :: Maybe HsModuleName-  } deriving (Eq, Ord, Show)---- | A specification of bindings to import from a module.  If 'Nothing', then--- the entire module is imported.  If @'Just' 'M.empty'@, then only instances--- are imported.-data HsImportSpecs = HsImportSpecs-  { getHsImportSpecs :: Maybe (M.Map HsImportName HsImportVal)-  , hsImportSource :: Bool-  } deriving (Show)---- | Combines two 'HsImportSpecs's into one that imports everything that the two--- did separately.-mergeImportSpecs :: HsImportSpecs -> HsImportSpecs -> HsImportSpecs-mergeImportSpecs (HsImportSpecs mm s) (HsImportSpecs mm' s') =-  HsImportSpecs (liftM2 mergeMaps mm mm') (s || s')-  where mergeMaps = M.unionWith mergeValues-        mergeValues v v' = case (v, v') of-          (HsImportValAll, _) -> HsImportValAll-          (_, HsImportValAll) -> HsImportValAll-          (HsImportValSome s, HsImportValSome s') -> HsImportValSome $ s ++ s'-          (x@(HsImportValSome _), _) -> x-          (_, x@(HsImportValSome _)) -> x-          (HsImportVal, HsImportVal) -> HsImportVal---- | An identifier that can be imported from a module.  Symbols may be used here--- when surrounded by parentheses.  Examples are @\"fmap\"@ and @\"(++)\"@.-type HsImportName = String---- | Specifies how a name is imported.-data HsImportVal =-  HsImportVal-  -- ^ The name is imported, and nothing underneath it is.-  | HsImportValSome [HsImportName]-    -- ^ The name is imported, as are specific names underneath it.  This is a-    -- @X (a, b, c)@ import.-  | HsImportValAll-    -- ^ The name is imported, along with all names underneath it.  This is a @X-    -- (..)@ import.-  deriving (Show)---- | An import for the entire contents of a Haskell module.-hsWholeModuleImport :: HsModuleName -> HsImportSet-hsWholeModuleImport moduleName =-  HsImportSet $ M.singleton (HsImportKey moduleName Nothing) $-  HsImportSpecs Nothing False---- | A qualified import of a Haskell module.-hsQualifiedImport :: HsModuleName -> HsModuleName -> HsImportSet-hsQualifiedImport moduleName qualifiedName =-  HsImportSet $ M.singleton (HsImportKey moduleName $ Just qualifiedName) $-  HsImportSpecs Nothing False---- | An import of a single name from a Haskell module.-hsImport1 :: HsModuleName -> HsImportName -> HsImportSet-hsImport1 moduleName valueName = hsImport1' moduleName valueName HsImportVal---- | A detailed import of a single name from a Haskell module.-hsImport1' :: HsModuleName -> HsImportName -> HsImportVal -> HsImportSet-hsImport1' moduleName valueName valueType =-  HsImportSet $ M.singleton (HsImportKey moduleName Nothing) $-  HsImportSpecs (Just $ M.singleton valueName valueType) False---- | An import of multiple names from a Haskell module.-hsImports :: HsModuleName -> [HsImportName] -> HsImportSet-hsImports moduleName names =-  hsImports' moduleName $ map (\name -> (name, HsImportVal)) names---- | A detailed import of multiple names from a Haskell module.-hsImports' :: HsModuleName -> [(HsImportName, HsImportVal)] -> HsImportSet-hsImports' moduleName values =-  HsImportSet $ M.singleton (HsImportKey moduleName Nothing) $-  HsImportSpecs (Just $ M.fromList values) False---- | Imports "Data.Bits" qualified as @HoppyDB@.-hsImportForBits :: HsImportSet-hsImportForBits = hsQualifiedImport "Data.Bits" "HoppyDB"---- | Imports "Data.Int" qualified as @HoppyDI@.-hsImportForInt :: HsImportSet-hsImportForInt = hsQualifiedImport "Data.Int" "HoppyDI"---- | Imports "Data.Word" qualified as @HoppyDW@.-hsImportForWord :: HsImportSet-hsImportForWord = hsQualifiedImport "Data.Word" "HoppyDW"---- | Imports "Foreign" qualified as @HoppyF@.-hsImportForForeign :: HsImportSet-hsImportForForeign = hsQualifiedImport "Foreign" "HoppyF"---- | Imports "Foreign.C" qualified as @HoppyFC@.-hsImportForForeignC :: HsImportSet-hsImportForForeignC = hsQualifiedImport "Foreign.C" "HoppyFC"---- | Imports "Prelude" qualified as @HoppyP@.-hsImportForPrelude :: HsImportSet-hsImportForPrelude = hsQualifiedImport "Prelude" "HoppyP"---- | Imports "Foreign.Hoppy.Runtime" qualified as @HoppyFHR@.-hsImportForRuntime :: HsImportSet-hsImportForRuntime = hsQualifiedImport "Foreign.Hoppy.Runtime" "HoppyFHR"---- | Imports "System.Posix.Types" qualified as @HoppySPT@.-hsImportForSystemPosixTypes :: HsImportSet-hsImportForSystemPosixTypes = hsQualifiedImport "System.Posix.Types" "HoppySPT"---- | Imports "System.IO.Unsafe" qualified as @HoppySIU@.-hsImportForUnsafeIO :: HsImportSet-hsImportForUnsafeIO = hsQualifiedImport "System.IO.Unsafe" "HoppySIU"---- | Returns an error message indicating that--- 'Foreign.Hoppy.Generator.Types.objToHeapT' is used where data is going from a--- foreign language into C++.-objToHeapTWrongDirectionErrorMsg :: Maybe String -> Class -> String-objToHeapTWrongDirectionErrorMsg maybeCaller cls =-  concat [maybe "" (++ ": ") maybeCaller,-          "(TObjToHeap ", show cls, ") cannot be passed into C++",-          maybe "" (const ".") maybeCaller]---- | Returns an error message indicating that--- 'Foreign.Hoppy.Generator.Types.objToHeapT' is used where data is going from a--- foreign language into C++.-tToGcInvalidFormErrorMessage :: Maybe String -> Type -> String-tToGcInvalidFormErrorMessage maybeCaller typeArg =-  concat [maybe "" (++ ": ") maybeCaller,-          "(", show (Internal_TToGc typeArg), ") is an invalid form for TToGc.",-          maybe "" (const ".") maybeCaller]---- | Returns an error message indicating that--- 'Foreign.Hoppy.Generator.Types.toGcT' is used where data is going from a--- foreign language into C++.-toGcTWrongDirectionErrorMsg :: Maybe String -> Type -> String-toGcTWrongDirectionErrorMsg maybeCaller typeArg =-  concat [maybe "" (++ ": ") maybeCaller,-          "(", show (Internal_TToGc typeArg), ") cannot be passed into C++",-          maybe "" (const ".") maybeCaller]+-- Copyright 2016 Bryan Gardiner <bog@khumba.net>+--+-- This program is free software: you can redistribute it and/or modify+-- it under the terms of the GNU Affero General Public License as published by+-- the Free Software Foundation, either version 3 of the License, or+-- (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU Affero General Public License for more details.+--+-- You should have received a copy of the GNU Affero General Public License+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.++-- | The primary data types for specifying C++ interfaces.+--+-- 'Show' instances in this module produce strings of the form @\"\<TypeOfObject+-- nameOfObject otherInfo...\>\"@.  They can be used in error messages without+-- specifying a noun separately, i.e. write @show cls@ instead of @\"the class+-- \" ++ show cls@.+module Foreign.Hoppy.Generator.Spec (+  module Foreign.Hoppy.Generator.Spec.Base,+  module Foreign.Hoppy.Generator.Spec.Conversion,+  module Foreign.Hoppy.Generator.Spec.ClassFeature,+  ) where++import Foreign.Hoppy.Generator.Spec.Base+import Foreign.Hoppy.Generator.Spec.ClassFeature+import Foreign.Hoppy.Generator.Spec.Conversion
+ src/Foreign/Hoppy/Generator/Spec/Base.hs view
@@ -0,0 +1,2484 @@+-- This file is part of Hoppy.+--+-- Copyright 2015-2016 Bryan Gardiner <bog@khumba.net>+--+-- This program is free software: you can redistribute it and/or modify+-- it under the terms of the GNU Affero General Public License as published by+-- the Free Software Foundation, either version 3 of the License, or+-- (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU Affero General Public License for more details.+--+-- You should have received a copy of the GNU Affero General Public License+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.++{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}++module Foreign.Hoppy.Generator.Spec.Base (+  -- * Interfaces+  Interface,+  ErrorMsg,+  InterfaceOptions (..),+  defaultInterfaceOptions,+  interface,+  interface',+  interfaceName,+  interfaceModules,+  interfaceNamesToModules,+  interfaceHaskellModuleBase,+  interfaceDefaultHaskellModuleBase,+  interfaceAddHaskellModuleBase,+  interfaceHaskellModuleImportNames,+  interfaceExceptionHandlers,+  interfaceCallbacksThrow,+  interfaceSetCallbacksThrow,+  interfaceExceptionClassId,+  interfaceExceptionSupportModule,+  interfaceSetExceptionSupportModule,+  -- * C++ includes+  Include,+  includeStd,+  includeLocal,+  includeToString,+  -- * Modules+  Module,+  moduleName,+  moduleHppPath,+  moduleCppPath,+  moduleExports,+  moduleReqs,+  moduleExceptionHandlers,+  moduleCallbacksThrow,+  moduleSetCallbacksThrow,+  moduleAddendum,+  moduleHaskellName,+  makeModule,+  moduleModify,+  moduleModify',+  moduleSetHppPath,+  moduleSetCppPath,+  moduleAddExports,+  moduleAddHaskellName,+  -- * Requirements+  Reqs,+  reqsIncludes,+  reqInclude,+  HasReqs (..),+  addReqs,+  addReqIncludes,+  -- * Names and exports+  ExtName,+  toExtName,+  isValidExtName,+  fromExtName,+  HasExtNames (..),+  getAllExtNames,+  FnName (..),+  IsFnName (..),+  Operator (..),+  OperatorType (..),+  operatorPreferredExtName,+  operatorPreferredExtName',+  operatorType,+  Export (..),+  exportAddendum,+  Identifier,+  identifierParts,+  IdPart,+  idPartBase,+  idPartArgs,+  ident, ident', ident1, ident2, ident3, ident4, ident5,+  identT, identT', ident1T, ident2T, ident3T, ident4T, ident5T,+  -- * Basic types+  Type (..),+  normalizeType,+  stripConst,+  -- ** Variables+  Variable, makeVariable, varIdentifier, varExtName, varType, varReqs,+  varIsConst, varGetterExtName, varSetterExtName,+  -- ** Enums+  CppEnum, makeEnum, enumIdentifier, enumExtName, enumValueNames, enumReqs,+  enumValuePrefix, enumSetValuePrefix,+  -- ** Bitspaces+  Bitspace, makeBitspace, bitspaceExtName, bitspaceType, bitspaceValueNames, bitspaceEnum,+  bitspaceAddEnum, bitspaceCppTypeIdentifier, bitspaceFromCppValueFn, bitspaceToCppValueFn,+  bitspaceAddCppType, bitspaceReqs,+  bitspaceValuePrefix, bitspaceSetValuePrefix,+  -- ** Functions+  Purity (..),+  Function, makeFn, fnCName, fnExtName, fnPurity, fnParams, fnReturn, fnReqs, fnExceptionHandlers,+  -- ** Classes+  Class, makeClass, classIdentifier, classExtName, classSuperclasses,+  classEntities, classAddEntities, classVariables, classCtors, classMethods,+  classDtorIsPublic, classSetDtorPrivate,+  classConversion, classReqs, classEntityPrefix, classSetEntityPrefix,+  classIsMonomorphicSuperclass, classSetMonomorphicSuperclass,+  classIsSubclassOfMonomorphic, classSetSubclassOfMonomorphic,+  classIsException, classMakeException,+  ClassEntity (..),+  IsClassEntity (..), classEntityExtName, classEntityForeignName, classEntityForeignName',+  ClassVariable,+  makeClassVariable, makeClassVariable_,+  mkClassVariable, mkClassVariable_,+  mkStaticClassVariable, mkStaticClassVariable_,+  classVarCName, classVarExtName, classVarType, classVarStatic, classVarGettable,+  classVarGetterExtName, classVarGetterForeignName,+  classVarSetterExtName, classVarSetterForeignName,+  Ctor, makeCtor, makeCtor_, mkCtor, mkCtor_, ctorExtName, ctorParams, ctorExceptionHandlers,+  Method,+  MethodImpl (..),+  MethodApplicability (..),+  Constness (..),+  constNegate,+  Staticness (..),+  makeMethod, makeMethod_,+  makeFnMethod, makeFnMethod_,+  mkMethod, mkMethod_, mkMethod', mkMethod'_,+  mkConstMethod, mkConstMethod_, mkConstMethod', mkConstMethod'_,+  mkStaticMethod, mkStaticMethod_, mkStaticMethod', mkStaticMethod'_,+  Prop,  -- The data constructor is private.+  mkProp, mkProp_,+  mkStaticProp, mkStaticProp_,+  mkBoolIsProp, mkBoolIsProp_,+  mkBoolHasProp, mkBoolHasProp_,+  methodImpl, methodExtName, methodApplicability, methodPurity, methodParams,+  methodReturn, methodExceptionHandlers, methodConst, methodStatic,+  -- *** Conversion to and from foreign values+  ClassConversion (..),+  classConversionNone,+  classModifyConversion,+  classSetConversion,+  ClassHaskellConversion (..),+  classHaskellConversionNone,+  classSetHaskellConversion,+  -- ** Callbacks+  Callback, makeCallback,+  callbackExtName, callbackParams, callbackReturn, callbackThrows, callbackReqs,+  callbackSetThrows,+  -- * Exceptions+  ExceptionId (..),+  exceptionCatchAllId,+  ExceptionHandler (..),+  ExceptionHandlers (..),+  HandlesExceptions (getExceptionHandlers),+  handleExceptions,+  -- * Addenda+  Addendum (..),+  HasAddendum (..),+  addAddendumHaskell,+  -- * Haskell imports+  HsModuleName, HsImportSet, HsImportKey (..), HsImportSpecs (..), HsImportName, HsImportVal (..),+  hsWholeModuleImport, hsQualifiedImport, hsImport1, hsImport1', hsImports, hsImports',+  hsImportSetMakeSource,+  -- * Internal to Hoppy+  interfaceAllExceptionClasses,+  classFindCopyCtor,+  -- ** Haskell imports+  makeHsImportSet,+  getHsImportSet,+  hsImportForBits,+  hsImportForException,+  hsImportForInt,+  hsImportForWord,+  hsImportForForeign,+  hsImportForForeignC,+  hsImportForMap,+  hsImportForPrelude,+  hsImportForRuntime,+  hsImportForSystemPosixTypes,+  hsImportForTypeable,+  hsImportForUnsafeIO,+  -- ** Error messages+  objToHeapTWrongDirectionErrorMsg,+  tToGcInvalidFormErrorMessage,+  toGcTWrongDirectionErrorMsg,+  ) where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>), (<*>))+#endif+import Control.Arrow ((&&&))+import Control.Monad (liftM2, unless)+#if MIN_VERSION_mtl(2,2,1)+import Control.Monad.Except (MonadError, throwError)+#else+import Control.Monad.Error (MonadError, throwError)+#endif+import Control.Monad.State (MonadState, StateT, execStateT, get, modify)+import Data.Char (isAlpha, isAlphaNum, toUpper)+import Data.Function (on)+import Data.List (intercalate, intersperse)+import qualified Data.Map as M+import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, mapMaybe)+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (Monoid, mappend, mconcat, mempty)+#endif+import qualified Data.Set as S+import Foreign.Hoppy.Generator.Common+import {-# SOURCE #-} qualified Foreign.Hoppy.Generator.Language.Haskell as Haskell+import Language.Haskell.Syntax (HsType)++-- | Indicates strings that are error messages.+type ErrorMsg = String++-- | A complete specification of a C++ API.  Generators for different languages,+-- including the binding generator for C++, use these to produce their output.+--+-- 'Interface' does not have a 'HandlesExceptions' instance because+-- 'modifyExceptionHandlers' does not work for it (handled exceptions cannot be+-- modified after an 'Interface' is constructed).+data Interface = Interface+  { interfaceName :: String+    -- ^ The textual name of the interface.+  , interfaceModules :: M.Map String Module+    -- ^ All of the individual modules, by 'moduleName'.+  , interfaceNamesToModules :: M.Map ExtName Module+    -- ^ Maps each 'ExtName' exported by some module to the module that exports+    -- the name.+  , interfaceHaskellModuleBase' :: Maybe [String]+    -- ^ See 'interfaceHaskellModuleBase'.+  , interfaceHaskellModuleImportNames :: M.Map Module String+    -- ^ Short qualified module import names that generated modules use to refer+    -- to each other tersely.+  , interfaceExceptionHandlers :: ExceptionHandlers+    -- ^ Exceptions that all functions in the interface may throw.+  , interfaceCallbacksThrow :: Bool+    -- ^ Whether callbacks within the interface support throwing C++ exceptions+    -- from Haskell into C++ during their execution.  This may be overridden by+    -- 'moduleCallbacksThrow' and 'callbackThrows'.+  , interfaceExceptionNamesToIds :: M.Map ExtName ExceptionId+    -- ^ Maps from external names of exception classes to their exception IDs.+  , interfaceExceptionSupportModule :: Maybe Module+    -- ^ When an interface uses C++ exceptions, then one module needs to+    -- manually be selected to contain some interface-specific runtime support.+    -- This is the selected module.+  }++instance Show Interface where+  show iface = concat ["<Interface ", show (interfaceName iface), ">"]++-- | Optional parameters when constructing an 'Interface' with 'interface'.+data InterfaceOptions = InterfaceOptions+  { interfaceOptionsExceptionHandlers :: ExceptionHandlers+  }++-- | Options used by 'interface'.  This contains no exception handlers.+defaultInterfaceOptions :: InterfaceOptions+defaultInterfaceOptions = InterfaceOptions mempty++-- | Constructs an 'Interface' from the required parts.  Some validation is+-- performed; if the resulting interface would be invalid, an error message is+-- returned instead.+--+-- This function passes 'defaultInterfaceOptions' to 'interface''.+interface :: String  -- ^ 'interfaceName'+          -> [Module]  -- ^ 'interfaceModules'+          -> Either ErrorMsg Interface+interface ifName modules = interface' ifName modules defaultInterfaceOptions++-- | Same as 'interface', but accepts some optional arguments.+interface' :: String  -- ^ 'interfaceName'+           -> [Module]  -- ^ 'interfaceModules'+           -> InterfaceOptions+           -> Either ErrorMsg Interface+interface' ifName modules options = do+  -- TODO Check for duplicate module names.+  -- TODO Check for duplicate module file paths.++  -- Check for multiple modules exporting an ExtName.+  let extNamesToModules :: M.Map ExtName [Module]+      extNamesToModules =+        M.unionsWith (++) $+        for modules $ \mod ->+        let extNames = concatMap getAllExtNames $ M.elems $ moduleExports mod+        in M.fromList $ zip extNames $ repeat [mod]++      extNamesInMultipleModules :: [(ExtName, [Module])]+      extNamesInMultipleModules =+        M.toList $+        M.filter (\modules -> case modules of+                     _:_:_ -> True+                     _ -> False)+        extNamesToModules++  unless (null extNamesInMultipleModules) $+    Left $ unlines $+    "Some external name(s) are exported by multiple modules:" :+    map (\(extName, modules) ->+          concat $ "- " : show extName : ": " : intersperse ", " (map show modules))+        extNamesInMultipleModules++  let haskellModuleImportNames =+        M.fromList $+        (\a b f -> zipWith f a b) modules [1..] $+        \mod index -> (mod, 'M' : show index)++  -- Generate a unique exception ID integer for each exception class.  IDs 0 and+  -- 1 are reserved.+  let exceptionNamesToIds =+        M.fromList $+        zip (map classExtName $ interfaceAllExceptionClasses' modules)+            (map ExceptionId [exceptionFirstFreeId..])++  return Interface+    { interfaceName = ifName+    , interfaceModules = M.fromList $ map (moduleName &&& id) modules+    , interfaceNamesToModules = M.map (\[x] -> x) extNamesToModules+    , interfaceHaskellModuleBase' = Nothing+    , interfaceHaskellModuleImportNames = haskellModuleImportNames+    , interfaceExceptionHandlers = interfaceOptionsExceptionHandlers options+    , interfaceCallbacksThrow = False+    , interfaceExceptionNamesToIds = exceptionNamesToIds+    , interfaceExceptionSupportModule = Nothing+    }++-- | The name of the parent Haskell module under which a Haskell module will be+-- generated for a Hoppy 'Module'.  This is a list of Haskell module path+-- components, in other words, @'Data.List.intercalate' "."@ on the list+-- produces a Haskell module name.  Defaults to+-- 'interfaceDefaultHaskellModuleBase', and may be overridden with+-- 'interfaceAddHaskellModuleBase'.+interfaceHaskellModuleBase :: Interface -> [String]+interfaceHaskellModuleBase =+  fromMaybe interfaceDefaultHaskellModuleBase . interfaceHaskellModuleBase'++-- | The default Haskell module under which Hoppy modules will be generated.+-- This is @Foreign.Hoppy.Generated@, that is:+--+-- > ["Foreign", "Hoppy", "Generated"]+interfaceDefaultHaskellModuleBase :: [String]+interfaceDefaultHaskellModuleBase = ["Foreign", "Hoppy", "Generated"]++-- | Sets an interface to generate all of its modules under the given Haskell+-- module prefix.  See 'interfaceHaskellModuleBase'.+interfaceAddHaskellModuleBase :: [String] -> Interface -> Either String Interface+interfaceAddHaskellModuleBase modulePath iface = case interfaceHaskellModuleBase' iface of+  Nothing -> Right iface { interfaceHaskellModuleBase' = Just modulePath }+  Just existingPath ->+    Left $ concat+    [ "addInterfaceHaskellModuleBase: Trying to add Haskell module base "+    , intercalate "." modulePath, " to ", show iface+    , " which already has a module base ", intercalate "." existingPath+    ]++-- | Returns the the exception ID for a class in an interface, if it has one+-- (i.e. if it's been marked as an exception class with 'classMakeException').+interfaceExceptionClassId :: Interface -> Class -> Maybe ExceptionId+interfaceExceptionClassId iface cls =+  M.lookup (classExtName cls) $ interfaceExceptionNamesToIds iface++-- | Returns all of the exception classes in an interface.+interfaceAllExceptionClasses :: Interface -> [Class]+interfaceAllExceptionClasses = interfaceAllExceptionClasses' . M.elems . interfaceModules++interfaceAllExceptionClasses' :: [Module] -> [Class]+interfaceAllExceptionClasses' modules =+  flip concatMap modules $ \mod ->+  catMaybes $+  for (M.elems $ moduleExports mod) $ \export -> case export of+    ExportClass cls | classIsException cls -> Just cls+    _ -> Nothing++-- | Changes 'callbackThrows' for all callbacks in an interface that don't have it+-- set explicitly at the module or callback level.+interfaceSetCallbacksThrow :: Bool -> Interface -> Interface+interfaceSetCallbacksThrow b iface = iface { interfaceCallbacksThrow = b }++-- | Sets an interface's exception support module, for interfaces that use+-- exceptions.+interfaceSetExceptionSupportModule :: Module -> Interface -> Interface+interfaceSetExceptionSupportModule mod iface = case interfaceExceptionSupportModule iface of+  Nothing -> iface { interfaceExceptionSupportModule = Just mod }+  Just existingMod ->+    if mod == existingMod+    then iface+    else error $ "interfaceSetExceptionSupportModule: " ++ show iface +++         " already has exception support module " ++ show existingMod +++         ", trying to set " ++ show mod ++ "."++-- | An @#include@ directive in a C++ file.+data Include = Include+  { includeToString :: String+    -- ^ Returns the complete @#include ...@ line for an include, including+    -- trailing newline.+  } deriving (Eq, Ord, Show)++-- | Creates an @#include \<...\>@ directive.+includeStd :: String -> Include+includeStd path = Include $ "#include <" ++ path ++ ">\n"++-- | Creates an @#include "..."@ directive.+includeLocal :: String -> Include+includeLocal path = Include $ "#include \"" ++ path ++ "\"\n"++-- | A portion of functionality in a C++ API.  An 'Interface' is composed of+-- multiple modules.  A module will generate a single compilation unit+-- containing bindings for all of the module's exports.  The C++ code for a+-- generated module will @#include@ everything necessary for what is written to+-- the header and source files separately.  You can declare include dependencies+-- with e.g. 'addReqIncludes', either for individual exports or at the module+-- level.  Dependencies between modules are handled automatically, and+-- circularity is supported to a certain extent.  See the documentation for the+-- individual language modules for further details.+data Module = Module+  { moduleName :: String+    -- ^ The module's name.  A module name must identify a unique module within+    -- an 'Interface'.+  , moduleHppPath :: String+    -- ^ A relative path under a C++ sources root to which the generator will+    -- write a header file for the module's C++ bindings.+  , moduleCppPath :: String+    -- ^ A relative path under a C++ sources root to which the generator will+    -- write a source file for the module's C++ bindings.+  , moduleExports :: M.Map ExtName Export+    -- ^ All of the exports in a module.+  , moduleReqs :: Reqs+    -- ^ Module-level requirements.+  , moduleHaskellName :: Maybe [String]+    -- ^ The generated Haskell module name, underneath the+    -- 'interfaceHaskellModuleBase'.  If absent (by default), the 'moduleName'+    -- is used.  May be modified with 'moduleAddHaskellName'.+  , moduleExceptionHandlers :: ExceptionHandlers+    -- ^ Exceptions that all functions in the module may throw.+  , moduleCallbacksThrow :: Maybe Bool+    -- ^ Whether callbacks exported from the module support exceptions being+    -- thrown during their execution.  When present, this overrides+    -- 'interfaceCallbacksThrow'.  This maybe overridden by 'callbackThrows'.+  , moduleAddendum :: Addendum+    -- ^ The module's addendum.+  }++instance Eq Module where+  (==) = (==) `on` moduleName++instance Ord Module where+  compare = compare `on` moduleName++instance Show Module where+  show m = concat ["<Module ", moduleName m, ">"]++instance HasReqs Module where+  getReqs = moduleReqs+  setReqs reqs m = m { moduleReqs = reqs }++instance HasAddendum Module where+  getAddendum = moduleAddendum+  setAddendum addendum m = m { moduleAddendum = addendum }++instance HandlesExceptions Module where+  getExceptionHandlers = moduleExceptionHandlers+  modifyExceptionHandlers f m = m { moduleExceptionHandlers = f $ moduleExceptionHandlers m }++-- | Creates an empty module, ready to be configured with 'moduleModify'.+makeModule :: String  -- ^ 'moduleName'+           -> String  -- ^ 'moduleHppPath'+           -> String  -- ^ 'moduleCppPath'+           -> Module+makeModule name hppPath cppPath = Module+  { moduleName = name+  , moduleHppPath = hppPath+  , moduleCppPath = cppPath+  , moduleExports = M.empty+  , moduleReqs = mempty+  , moduleHaskellName = Nothing+  , moduleExceptionHandlers = mempty+  , moduleCallbacksThrow = Nothing+  , moduleAddendum = mempty+  }++-- | Extends a module.  To be used with the module state-monad actions in this+-- package.+moduleModify :: Module -> StateT Module (Either String) () -> Either ErrorMsg Module+moduleModify = flip execStateT++-- | Same as 'moduleModify', but calls 'error' in the case of failure, which is+-- okay in for a generator which would abort in this case anyway.+moduleModify' :: Module -> StateT Module (Either String) () -> Module+moduleModify' m action = case moduleModify m action of+  Left errorMsg ->+    error $ concat+    ["moduleModify' failed to modify ", show m, ": ", errorMsg]+  Right m' -> m'++-- | Replaces a module's 'moduleHppPath'.+moduleSetHppPath :: MonadState Module m => String -> m ()+moduleSetHppPath path = modify $ \m -> m { moduleHppPath = path }++-- | Replaces a module's 'moduleCppPath'.+moduleSetCppPath :: MonadState Module m => String -> m ()+moduleSetCppPath path = modify $ \m -> m { moduleCppPath = path }++-- | Adds exports to a module.  An export must only be added to any module at+-- most once, and must not be added to multiple modules.+moduleAddExports :: (MonadError String m, MonadState Module m) => [Export] -> m ()+moduleAddExports exports = do+  m <- get+  let existingExports = moduleExports m+      newExports = M.fromList $ map (getPrimaryExtName &&& id) exports+      duplicateNames = (S.intersection `on` M.keysSet) existingExports newExports+  if S.null duplicateNames+    then modify $ \m -> m { moduleExports = existingExports `mappend` newExports }+    else throwError $ concat+         ["moduleAddExports: ", show m, " defines external names multiple times: ",+          show duplicateNames]++-- | Changes a module's 'moduleHaskellName' from the default.  This can only be+-- called once on a module.+moduleAddHaskellName :: (MonadError String m, MonadState Module m) => [String] -> m ()+moduleAddHaskellName name = do+  m <- get+  case moduleHaskellName m of+    Nothing -> modify $ \m -> m { moduleHaskellName = Just name }+    Just name' ->+      throwError $ concat+      ["moduleAddHaskellName: ", show m, " already has Haskell name ",+       show name', "; trying to add name ", show name, "."]++-- | Changes 'callbackThrows' for all callbacks in a module that don't have it+-- set explicitly.+moduleSetCallbacksThrow :: MonadState Module m => Maybe Bool -> m ()+moduleSetCallbacksThrow b = modify $ \m -> m { moduleCallbacksThrow = b }++-- | A set of requirements of needed to use an identifier in C++ (function,+-- type, etc.), via a set of 'Include's.  The monoid instance has 'mempty' as an+-- empty set of includes, and 'mappend' unions two include sets.+data Reqs = Reqs+  { reqsIncludes :: S.Set Include+    -- ^ The includes specified by a 'Reqs'.+  } deriving (Show)++instance Monoid Reqs where+  mempty = Reqs mempty++  mappend (Reqs incl) (Reqs incl') = Reqs $ mappend incl incl'++  mconcat reqs = Reqs $ mconcat $ map reqsIncludes reqs++-- | Creates a 'Reqs' that contains the given include.+reqInclude :: Include -> Reqs+reqInclude include = mempty { reqsIncludes = S.singleton include }++-- | C++ types that have requirements in order to use them in generated+-- bindings.+class HasReqs a where+  {-# MINIMAL getReqs, (setReqs | modifyReqs) #-}++  -- | Returns an object's requirements.+  getReqs :: a -> Reqs++  -- | Replaces an object's requirements with new ones.+  setReqs :: Reqs -> a -> a+  setReqs = modifyReqs . const++  -- | Modifies an object's requirements.+  modifyReqs :: (Reqs -> Reqs) -> a -> a+  modifyReqs f x = setReqs (f $ getReqs x) x++-- | Adds to a object's requirements.+addReqs :: HasReqs a => Reqs -> a -> a+addReqs reqs = modifyReqs $ mappend reqs++-- | Adds a list of includes to the requirements of an object.+addReqIncludes :: HasReqs a => [Include] -> a -> a+addReqIncludes includes =+  modifyReqs $ mappend mempty { reqsIncludes = S.fromList includes }++-- | An external name is a string that generated bindings use to uniquely+-- identify an object at runtime.  An external name must start with an+-- alphabetic character, and may only contain alphanumeric characters and @'_'@.+-- You are free to use whatever naming style you like; case conversions will be+-- performed automatically when required.  Hoppy does make use of some+-- conventions though, for example with 'Operator's and in the provided bindings+-- for the C++ standard library.+--+-- External names must be unique within an interface.  They may not be reused+-- between modules.  This assumption is used for symbol naming in compiled+-- shared objects and to freely import modules in Haskell bindings.+newtype ExtName = ExtName+  { fromExtName :: String+    -- ^ Returns the string an an 'ExtName' contains.+  } deriving (Eq, Monoid, Ord)++instance Show ExtName where+  show extName = concat ["$\"", fromExtName extName, "\"$"]++-- | Creates an 'ExtName' that contains the given string, erroring if the string+-- is an invalid 'ExtName'.+toExtName :: String -> ExtName+toExtName str = case str of+  -- Keep this logic in sync with isValidExtName.+  [] -> error "An ExtName cannot be empty."+  _ -> if isValidExtName str+       then ExtName str+       else error $+            "An ExtName must start with a letter and only contain letters, numbers, and '_': " +++            show str++-- | Returns true if the given string is represents a valid 'ExtName'.+isValidExtName :: String -> Bool+isValidExtName str = case str of+  -- Keep this logic in sync with toExtName.+  [] -> False+  c:cs -> isAlpha c && all ((||) <$> isAlphaNum <*> (== '_')) cs++-- | Generates an 'ExtName' from an 'Identifier', if the given name is absent.+extNameOrIdentifier :: Identifier -> Maybe ExtName -> ExtName+extNameOrIdentifier ident = fromMaybe $ case identifierParts ident of+  [] -> error "extNameOrIdentifier: Invalid empty identifier."+  parts -> toExtName $ idPartBase $ last parts++-- | Generates an 'ExtName' from an @'FnName' 'Identifier'@, if the given name+-- is absent.+extNameOrFnIdentifier :: FnName Identifier -> Maybe ExtName -> ExtName+extNameOrFnIdentifier name =+  fromMaybe $ case name of+    FnName identifier -> case identifierParts identifier of+      [] -> error "extNameOrFnIdentifier: Empty idenfitier."+      parts -> toExtName $ idPartBase $ last parts+    FnOp op -> operatorPreferredExtName op++-- | Generates an 'ExtName' from a string, if the given name is absent.+extNameOrString :: String -> Maybe ExtName -> ExtName+extNameOrString str = fromMaybe $ toExtName str++-- | Types that have an external name, and also optionally have nested entities+-- with external names as well.  See 'getAllExtNames'.+class HasExtNames a where+  -- | Returns the external name by which a given entity is referenced.+  getPrimaryExtName :: a -> ExtName++  -- | Returns external names nested within the given entity.  Does not include+  -- the primary external name.+  getNestedExtNames :: a -> [ExtName]+  getNestedExtNames _ = []++-- | Returns a list of all of the external names an entity contains.  This+-- combines both 'getPrimaryExtName' and 'getNestedExtNames'.+getAllExtNames :: HasExtNames a => a -> [ExtName]+getAllExtNames x = getPrimaryExtName x : getNestedExtNames x++-- | The C++ name of a function or method.+data FnName name =+  FnName name+  -- ^ A regular, \"alphanumeric\" name.  The exact type depends on what kind of+  -- object is being named.+  | FnOp Operator+    -- ^ An operator name.+  deriving (Eq, Ord)++instance Show name => Show (FnName name) where+  show (FnName name) = concat ["<FnName ", show name, ">"]+  show (FnOp op) = concat ["<FnOp ", show op, ">"]++-- | Enables implementing automatic conversions to a @'FnName' t@.+class IsFnName t a where+  toFnName :: a -> FnName t++instance IsFnName t (FnName t) where+  toFnName = id++instance IsFnName t t where+  toFnName = FnName++instance IsFnName t Operator where+  toFnName = FnOp++-- | Overloadable C++ operators.+data Operator =+  OpCall  -- ^ @x(...)@+  | OpComma -- ^ @x, y@+  | OpAssign  -- ^ @x = y@+  | OpArray  -- ^ @x[y]@+  | OpDeref  -- ^ @*x@+  | OpAddress  -- ^ @&x@+  | OpAdd  -- ^ @x + y@+  | OpAddAssign  -- ^ @x += y@+  | OpSubtract  -- ^ @x - y@+  | OpSubtractAssign  -- ^ @x -= y@+  | OpMultiply  -- ^ @x * y@+  | OpMultiplyAssign  -- ^ @x *= y@+  | OpDivide  -- ^ @x / y@+  | OpDivideAssign  -- ^ @x /= y@+  | OpModulo  -- ^ @x % y@+  | OpModuloAssign  -- ^ @x %= y@+  | OpPlus  -- ^ @+x@+  | OpMinus  -- ^ @-x@+  | OpIncPre  -- ^ @++x@+  | OpIncPost  -- ^ @x++@+  | OpDecPre  -- ^ @--x@+  | OpDecPost  -- ^ @x--@+  | OpEq  -- ^ @x == y@+  | OpNe  -- ^ @x != y@+  | OpLt  -- ^ @x < y@+  | OpLe  -- ^ @x <= y@+  | OpGt  -- ^ @x > y@+  | OpGe  -- ^ @x >= y@+  | OpNot  -- ^ @!x@+  | OpAnd  -- ^ @x && y@+  | OpOr  -- ^ @x || y@+  | OpBitNot  -- ^ @~x@+  | OpBitAnd  -- ^ @x & y@+  | OpBitAndAssign  -- ^ @x &= y@+  | OpBitOr  -- ^ @x | y@+  | OpBitOrAssign  -- ^ @x |= y@+  | OpBitXor  -- ^ @x ^ y@+  | OpBitXorAssign  -- ^ @x ^= y@+  | OpShl  -- ^ @x << y@+  | OpShlAssign  -- ^ @x <<= y@+  | OpShr  -- ^ @x >> y@+  | OpShrAssign  -- ^ @x >>= y@+  deriving (Bounded, Enum, Eq, Ord, Show)++-- | The arity and syntax of an operator.+data OperatorType =+  UnaryPrefixOperator String  -- ^ Prefix unary operators.  Examples: @!x@, @*x@, @++x@.+  | UnaryPostfixOperator String  -- ^ Postfix unary operators.  Examples: @x--, x++@.+  | BinaryOperator String  -- ^ Infix binary operators.  Examples: @x * y@, @x >>= y@.+  | CallOperator  -- ^ @x(...)@ with arbitrary arity.+  | ArrayOperator  -- ^ @x[y]@, a binary operator with non-infix syntax.++data OperatorInfo = OperatorInfo+  { operatorPreferredExtName'' :: ExtName+  , operatorType' :: OperatorType+  }++makeOperatorInfo :: String -> OperatorType -> OperatorInfo+makeOperatorInfo = OperatorInfo . toExtName++-- | Returns a conventional string to use for the 'ExtName' of an operator.+operatorPreferredExtName :: Operator -> ExtName+operatorPreferredExtName op = case M.lookup op operatorInfo of+  Just info -> operatorPreferredExtName'' info+  Nothing ->+    error $ concat+    ["operatorPreferredExtName: Internal error, missing info for operator ", show op, "."]++-- | Returns a conventional name for an operator, as with+-- 'operatorPreferredExtName', but as a string.+operatorPreferredExtName' :: Operator -> String+operatorPreferredExtName' = fromExtName . operatorPreferredExtName++-- | Returns the type of an operator.+operatorType :: Operator -> OperatorType+operatorType op = case M.lookup op operatorInfo of+  Just info -> operatorType' info+  Nothing ->+    error $ concat+    ["operatorType: Internal error, missing info for operator ", show op, "."]++-- | Metadata for operators.+--+-- TODO Test out this missing data.+operatorInfo :: M.Map Operator OperatorInfo+operatorInfo =+  let input =+        [ (OpCall, makeOperatorInfo "CALL" CallOperator)+        , (OpComma, makeOperatorInfo "COMMA" $ BinaryOperator ",")+        , (OpAssign, makeOperatorInfo "ASSIGN" $ BinaryOperator "=")+        , (OpArray, makeOperatorInfo "ARRAY" ArrayOperator)+        , (OpDeref, makeOperatorInfo "DEREF" $ UnaryPrefixOperator "*")+        , (OpAddress, makeOperatorInfo "ADDRESS" $ UnaryPrefixOperator "&")+        , (OpAdd, makeOperatorInfo "ADD" $ BinaryOperator "+")+        , (OpAddAssign, makeOperatorInfo "ADDA" $ BinaryOperator "+=")+        , (OpSubtract, makeOperatorInfo "SUB" $ BinaryOperator "-")+        , (OpSubtractAssign, makeOperatorInfo "SUBA" $ BinaryOperator "-=")+        , (OpMultiply, makeOperatorInfo "MUL" $ BinaryOperator "*")+        , (OpMultiplyAssign, makeOperatorInfo "MULA" $ BinaryOperator "*=")+        , (OpDivide, makeOperatorInfo "DIV" $ BinaryOperator "/")+        , (OpDivideAssign, makeOperatorInfo "DIVA" $ BinaryOperator "/=")+        , (OpModulo, makeOperatorInfo "MOD" $ BinaryOperator "%")+        , (OpModuloAssign, makeOperatorInfo "MODA" $ BinaryOperator "%=")+        , (OpPlus, makeOperatorInfo "PLUS" $ UnaryPrefixOperator "+")+        , (OpMinus, makeOperatorInfo "NEG" $ UnaryPrefixOperator "-")+        , (OpIncPre, makeOperatorInfo "INC" $ UnaryPrefixOperator "++")+        , (OpIncPost, makeOperatorInfo "INCPOST" $ UnaryPostfixOperator "++")+        , (OpDecPre, makeOperatorInfo "DEC" $ UnaryPrefixOperator "--")+        , (OpDecPost, makeOperatorInfo "DECPOST" $ UnaryPostfixOperator "--")+        , (OpEq, makeOperatorInfo "EQ" $ BinaryOperator "==")+        , (OpNe, makeOperatorInfo "NE" $ BinaryOperator "!=")+        , (OpLt, makeOperatorInfo "LT" $ BinaryOperator "<")+        , (OpLe, makeOperatorInfo "LE" $ BinaryOperator "<=")+        , (OpGt, makeOperatorInfo "GT" $ BinaryOperator ">")+        , (OpGe, makeOperatorInfo "GE" $ BinaryOperator ">=")+        , (OpNot, makeOperatorInfo "NOT" $ UnaryPrefixOperator "!")+        , (OpAnd, makeOperatorInfo "AND" $ BinaryOperator "&&")+        , (OpOr, makeOperatorInfo "OR" $ BinaryOperator "||")+        , (OpBitNot, makeOperatorInfo "BNOT" $ UnaryPrefixOperator "~")+        , (OpBitAnd, makeOperatorInfo "BAND" $ BinaryOperator "&")+        , (OpBitAndAssign, makeOperatorInfo "BANDA" $ BinaryOperator "&=")+        , (OpBitOr, makeOperatorInfo "BOR" $ BinaryOperator "|")+        , (OpBitOrAssign, makeOperatorInfo "BORA" $ BinaryOperator "|=")+        , (OpBitXor, makeOperatorInfo "BXOR" $ BinaryOperator "^")+        , (OpBitXorAssign, makeOperatorInfo "BXORA" $ BinaryOperator "^=")+        , (OpShl, makeOperatorInfo "SHL" $ BinaryOperator "<<")+        , (OpShlAssign, makeOperatorInfo "SHLA" $ BinaryOperator "<<=")+        , (OpShr, makeOperatorInfo "SHR" $ BinaryOperator ">>")+        , (OpShrAssign, makeOperatorInfo "SHR" $ BinaryOperator ">>=")+        ]+  in if map fst input == [minBound..]+     then M.fromList input+     else error "operatorInfo: Operator info list is out of sync with Operator data type."++-- | Specifies some C++ object (function or class) to give access to.+data Export =+  ExportVariable Variable  -- ^ Exports a variable.+  | ExportEnum CppEnum  -- ^ Exports an enum.+  | ExportBitspace Bitspace  -- ^ Exports a bitspace.+  | ExportFn Function  -- ^ Exports a function.+  | ExportClass Class  -- ^ Exports a class with all of its contents.+  | ExportCallback Callback  -- ^ Exports a callback.+  deriving (Show)++instance HasExtNames Export where+  getPrimaryExtName x = case x of+    ExportVariable v -> getPrimaryExtName v+    ExportEnum e -> getPrimaryExtName e+    ExportBitspace b -> getPrimaryExtName b+    ExportFn f -> getPrimaryExtName f+    ExportClass cls -> getPrimaryExtName cls+    ExportCallback cb -> getPrimaryExtName cb++  getNestedExtNames x = case x of+    ExportVariable v -> getNestedExtNames v+    ExportEnum e -> getNestedExtNames e+    ExportBitspace b -> getNestedExtNames b+    ExportFn f -> getNestedExtNames f+    ExportClass cls -> getNestedExtNames cls+    ExportCallback cb -> getNestedExtNames cb++-- | Returns the export's addendum.  'Export' doesn't have a 'HasAddendum'+-- instance because you normally wouldn't want to modify the addendum of one.+exportAddendum export = case export of+  ExportVariable v -> getAddendum v+  ExportEnum e -> getAddendum e+  ExportBitspace bs -> getAddendum bs+  ExportFn f -> getAddendum f+  ExportClass cls -> getAddendum cls+  ExportCallback cb -> getAddendum cb++-- | A path to some C++ object, including namespaces.  An identifier consists of+-- multiple parts separated by @\"::\"@.  Each part has a name string followed+-- by an optional template argument list, where each argument gets rendered from+-- a 'Type' (non-type arguments for template metaprogramming are not supported).+newtype Identifier = Identifier+  { identifierParts :: [IdPart]+    -- ^ The separate parts of the identifier, between @::@s.+  } deriving (Eq)++instance Show Identifier where+  show ident =+    (\words -> concat $ "<Identifier " : words ++ [">"]) $+    intersperse "::" $+    map (\part -> case idPartArgs part of+            Nothing -> idPartBase part+            Just args ->+              concat $+              idPartBase part : "<" :+              intersperse ", " (map show args) ++ [">"]) $+    identifierParts ident++-- | A single component of an 'Identifier', between @::@s.+data IdPart = IdPart+  { idPartBase :: String+    -- ^ The name within the enclosing scope.+  , idPartArgs :: Maybe [Type]+    -- ^ Template arguments, if present.+  } deriving (Eq, Show)++-- | Creates an identifier of the form @a@.+ident :: String -> Identifier+ident a = Identifier [IdPart a Nothing]++-- | Creates an identifier of the form @a1::a2::...::aN@.+ident' :: [String] -> Identifier+ident' = Identifier . map (\x -> IdPart x Nothing)++-- | Creates an identifier of the form @a::b@.+ident1 :: String -> String -> Identifier+ident1 a b = ident' [a, b]++-- | Creates an identifier of the form @a::b::c@.+ident2 :: String -> String -> String -> Identifier+ident2 a b c = ident' [a, b, c]++-- | Creates an identifier of the form @a::b::c::d@.+ident3 :: String -> String -> String -> String -> Identifier+ident3 a b c d = ident' [a, b, c, d]++-- | Creates an identifier of the form @a::b::c::d::e@.+ident4 :: String -> String -> String -> String -> String -> Identifier+ident4 a b c d e = ident' [a, b, c, d, e]++-- | Creates an identifier of the form @a::b::c::d::e::f@.+ident5 :: String -> String -> String -> String -> String -> String -> Identifier+ident5 a b c d e f = ident' [a, b, c, d, e, f]++-- | Creates an identifier of the form @a\<...\>@.+identT :: String -> [Type] -> Identifier+identT a ts = Identifier [IdPart a $ Just ts]++-- | Creates an identifier with arbitrary many templated and non-templated+-- parts.+identT' :: [(String, Maybe [Type])] -> Identifier+identT' = Identifier . map (uncurry IdPart)++-- | Creates an identifier of the form @a::b\<...\>@.+ident1T :: String -> String -> [Type] -> Identifier+ident1T a b ts = Identifier [IdPart a Nothing, IdPart b $ Just ts]++-- | Creates an identifier of the form @a::b::c\<...\>@.+ident2T :: String -> String -> String -> [Type] -> Identifier+ident2T a b c ts = Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c $ Just ts]++-- | Creates an identifier of the form @a::b::c::d\<...\>@.+ident3T :: String -> String -> String -> String -> [Type] -> Identifier+ident3T a b c d ts =+  Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c Nothing,+              IdPart d $ Just ts]++-- | Creates an identifier of the form @a::b::c::d::e\<...\>@.+ident4T :: String -> String -> String -> String -> String -> [Type] -> Identifier+ident4T a b c d e ts =+  Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c Nothing,+              IdPart d Nothing, IdPart e $ Just ts]++-- | Creates an identifier of the form @a::b::c::d::e::f\<...\>@.+ident5T :: String -> String -> String -> String -> String -> String -> [Type] -> Identifier+ident5T a b c d e f ts =+  Identifier [IdPart a Nothing, IdPart b Nothing, IdPart c Nothing,+              IdPart d Nothing, IdPart e Nothing, IdPart f $ Just ts]++-- | A concrete C++ type.  Use the bindings in "Foreign.Hoppy.Generator.Types"+-- for values of this type; these data constructors are subject to change+-- without notice.+data Type =+    Internal_TVoid+  | Internal_TBool+  | Internal_TChar+  | Internal_TUChar+  | Internal_TShort+  | Internal_TUShort+  | Internal_TInt+  | Internal_TUInt+  | Internal_TLong+  | Internal_TULong+  | Internal_TLLong+  | Internal_TULLong+  | Internal_TFloat+  | Internal_TDouble+  | Internal_TInt8+  | Internal_TInt16+  | Internal_TInt32+  | Internal_TInt64+  | Internal_TWord8+  | Internal_TWord16+  | Internal_TWord32+  | Internal_TWord64+  | Internal_TPtrdiff+  | Internal_TSize+  | Internal_TSSize+  | Internal_TEnum CppEnum+  | Internal_TBitspace Bitspace+  | Internal_TPtr Type+  | Internal_TRef Type+  | Internal_TFn [Type] Type+  | Internal_TCallback Callback+  | Internal_TObj Class+  | Internal_TObjToHeap Class+  | Internal_TToGc Type+  | Internal_TConst Type+  deriving (Eq, Show)++-- | Canonicalizes a 'Type' without changing its meaning.  Multiple nested+-- 'Internal_TConst's are collapsed into a single one.+normalizeType :: Type -> Type+normalizeType t = case t of+  Internal_TVoid -> t+  Internal_TBool -> t+  Internal_TChar -> t+  Internal_TUChar -> t+  Internal_TShort -> t+  Internal_TUShort -> t+  Internal_TInt -> t+  Internal_TUInt -> t+  Internal_TLong -> t+  Internal_TULong -> t+  Internal_TLLong -> t+  Internal_TULLong -> t+  Internal_TFloat -> t+  Internal_TDouble -> t+  Internal_TInt8 -> t+  Internal_TInt16 -> t+  Internal_TInt32 -> t+  Internal_TInt64 -> t+  Internal_TWord8 -> t+  Internal_TWord16 -> t+  Internal_TWord32 -> t+  Internal_TWord64 -> t+  Internal_TPtrdiff -> t+  Internal_TSize -> t+  Internal_TSSize -> t+  Internal_TEnum _ -> t+  Internal_TBitspace _ -> t+  Internal_TPtr t' -> Internal_TPtr $ normalizeType t'+  Internal_TRef t' -> Internal_TRef $ normalizeType t'+  Internal_TFn paramTypes retType ->+    Internal_TFn (map normalizeType paramTypes) $ normalizeType retType+  Internal_TCallback _ -> t+  Internal_TObj _ -> t+  Internal_TObjToHeap _ -> t+  Internal_TToGc _ -> t+  Internal_TConst (Internal_TConst t') -> normalizeType $ Internal_TConst t'+  Internal_TConst _ -> t++-- | Strips leading 'Internal_TConst's off of a type.+stripConst :: Type -> Type+stripConst t = case t of+  Internal_TConst t' -> stripConst t'+  _ -> t++-- | A C++ variable.+data Variable = Variable+  { varIdentifier :: Identifier+    -- ^ The identifier used to refer to the variable.+  , varExtName :: ExtName+    -- ^ The variable's external name.+  , varType :: Type+    -- ^ The variable's type.  This may be+    -- 'Foreign.Hoppy.Generator.Types.constT' to indicate that the variable is+    -- read-only.+  , varReqs :: Reqs+    -- ^ Requirements for bindings to use this variable.+  , varAddendum :: Addendum+    -- ^ The variable's addendum.+  }++instance Eq Variable where+  (==) = (==) `on` varExtName++instance Show Variable where+  show v = concat ["<Variable ", show (varExtName v), " ", show (varType v), ">"]++instance HasExtNames Variable where+  getPrimaryExtName = varExtName+  getNestedExtNames v = [varGetterExtName v, varSetterExtName v]++instance HasReqs Variable where+  getReqs = varReqs+  setReqs reqs v = v { varReqs = reqs }++instance HasAddendum Variable where+  getAddendum = varAddendum+  setAddendum addendum v = v { varAddendum = addendum }++-- | Creates a binding for a C++ variable.+makeVariable :: Identifier -> Maybe ExtName -> Type -> Variable+makeVariable identifier maybeExtName t =+  Variable identifier (extNameOrIdentifier identifier maybeExtName) t mempty mempty++-- | Returns whether the variable is constant, i.e. whether its type is+-- @'Foreign.Hoppy.Generator.Types.constT' ...@.+varIsConst :: Variable -> Bool+varIsConst v = case varType v of+  Internal_TConst _ -> True+  _ -> False++-- | Returns the external name of the getter function for the variable.+varGetterExtName :: Variable -> ExtName+varGetterExtName = toExtName . (++ "_get") . fromExtName . varExtName++-- | Returns the external name of the setter function for the variable.+varSetterExtName :: Variable -> ExtName+varSetterExtName = toExtName . (++ "_set") . fromExtName . varExtName++-- | A C++ enum declaration.  An enum should actually be enumerable (in the+-- sense of Haskell's 'Enum'); if it's not, consider using a 'Bitspace' instead.+data CppEnum = CppEnum+  { enumIdentifier :: Identifier+    -- ^ The identifier used to refer to the enum.+  , enumExtName :: ExtName+    -- ^ The enum's external name.+  , enumValueNames :: [(Int, [String])]+    -- ^ The numeric values and names of the enum values.  A single value's name+    -- is broken up into words.  How the words and ext name get combined to make+    -- a name in a particular foreign language depends on the language.+  , enumReqs :: Reqs+    -- ^ Requirements for a 'Type' to reference this enum.+  , enumAddendum :: Addendum+    -- ^ The enum's addendum.+  , enumValuePrefix :: String+    -- ^ The prefix applied to value names ('enumValueNames') when determining+    -- the names of values in foreign languages.  This defaults to the external+    -- name of the enum, plus an underscore.+    --+    -- See 'enumSetValuePrefix'.+  }++instance Eq CppEnum where+  (==) = (==) `on` enumExtName++instance Show CppEnum where+  show e = concat ["<Enum ", show (enumExtName e), " ", show (enumIdentifier e), ">"]++instance HasExtNames CppEnum where+  getPrimaryExtName = enumExtName++instance HasReqs CppEnum where+  getReqs = enumReqs+  setReqs reqs e = e { enumReqs = reqs }++instance HasAddendum CppEnum where+  getAddendum = enumAddendum+  setAddendum addendum e = e { enumAddendum = addendum }++-- | Creates a binding for a C++ enum.+makeEnum :: Identifier  -- ^ 'enumIdentifier'+         -> Maybe ExtName+         -- ^ An optional external name; will be automatically derived from+         -- the identifier if absent.+         -> [(Int, [String])]  -- ^ 'enumValueNames'+         -> CppEnum+makeEnum identifier maybeExtName valueNames =+  let extName = extNameOrIdentifier identifier maybeExtName+  in CppEnum+     identifier+     extName+     valueNames+     mempty+     mempty+     (fromExtName extName ++ "_")++-- | Sets the prefix applied to the names of enum values' identifiers in foreign+-- languages.+--+-- See 'enumValuePrefix'.+enumSetValuePrefix :: String -> CppEnum -> CppEnum+enumSetValuePrefix prefix enum = enum { enumValuePrefix = prefix }++-- | A C++ numeric space with bitwise operations.  This is similar to a+-- 'CppEnum', but in addition to the extra operations, this differs in that+-- these values aren't enumerable.+--+-- Additionally, as a kludge for Qtah, a bitspace may have a C++ type+-- ('bitspaceCppTypeIdentifier') separate from its numeric type+-- ('bitspaceType').  Qt bitspaces aren't raw numbers but are instead type-safe+-- @QFlags@ objects that don't implicitly convert from integers, so we need a+-- means to do so manually.  Barring general ad-hoc argument and return value+-- conversion support, we allow this as follows: when given a C++ type, then a+-- bitspace may also have a conversion function between the numeric and C+++-- type, in each direction.  If a conversion function is present, it will be+-- used for conversions in its respective direction.  The C++ type is not a full+-- 'Type', but only an 'Identifier', since additional information is not needed.+-- See 'bitspaceAddCppType'.+data Bitspace = Bitspace+  { bitspaceExtName :: ExtName+    -- ^ The bitspace's external name.+  , bitspaceType :: Type+    -- ^ The C++ type used for bits values.  This should be a primitive numeric+    -- type, usually 'Foreign.Hoppy.Generator.Types.intT'.+  , bitspaceValueNames :: [(Int, [String])]+    -- ^ The numeric values and names of the bitspace values.  See+    -- 'enumValueNames'.+  , bitspaceEnum :: Maybe CppEnum+    -- ^ An associated enum, whose values may be converted to values in the+    -- bitspace.+  , bitspaceCppTypeIdentifier :: Maybe Identifier+    -- ^ The optional C++ type for a bitspace.+  , bitspaceToCppValueFn :: Maybe String+    -- ^ The name of a C++ function to convert from 'bitspaceType' to the+    -- bitspace's C++ type.+  , bitspaceFromCppValueFn :: Maybe String+    -- ^ The name of a C++ function to convert from the bitspace's C++ type to+    -- 'bitspaceType'.+  , bitspaceReqs :: Reqs+    -- ^ Requirements for emitting the bindings for a bitspace, i.e. what's+    -- necessary to reference 'bitspaceCppTypeIdentifier',+    -- 'bitspaceFromCppValueFn', and 'bitspaceToCppValueFn'.  'bitspaceType' can+    -- take some numeric types that require includes as well, but you don't need+    -- to list these here.+  , bitspaceAddendum :: Addendum+    -- ^ The bitspace's addendum.+  , bitspaceValuePrefix :: String+    -- ^ The prefix applied to value names ('bitspaceValueNames') when+    -- determining the names of values in foreign languages.  This defaults to+    -- the external name of the bitspace, plus an underscore.+    --+    -- See 'bitspaceSetValuePrefix'.+  }++instance Eq Bitspace where+  (==) = (==) `on` bitspaceExtName++instance Show Bitspace where+  show e = concat ["<Bitspace ", show (bitspaceExtName e), " ", show (bitspaceType e), ">"]++instance HasExtNames Bitspace where+  getPrimaryExtName = bitspaceExtName++instance HasReqs Bitspace where+  getReqs = bitspaceReqs+  setReqs reqs b = b { bitspaceReqs = reqs }++instance HasAddendum Bitspace where+  getAddendum = bitspaceAddendum+  setAddendum addendum bs = bs { bitspaceAddendum = addendum }++-- | Creates a binding for a C++ bitspace.+makeBitspace :: ExtName  -- ^ 'bitspaceExtName'+             -> Type  -- ^ 'bitspaceType'+             -> [(Int, [String])]  -- ^ 'bitspaceValueNames'+             -> Bitspace+makeBitspace extName t valueNames =+  Bitspace extName t valueNames Nothing Nothing Nothing Nothing mempty mempty+  (fromExtName extName ++ "_")++-- | Sets the prefix applied to the names of enum values' identifiers in foreign+-- languages.+--+-- See 'enumValuePrefix'.+bitspaceSetValuePrefix :: String -> Bitspace -> Bitspace+bitspaceSetValuePrefix prefix bitspace = bitspace { bitspaceValuePrefix = prefix }++-- | Associates an enum with the bitspace.  See 'bitspaceEnum'.+bitspaceAddEnum :: CppEnum -> Bitspace -> Bitspace+bitspaceAddEnum enum bitspace = case bitspaceEnum bitspace of+  Just enum' ->+    error $ concat+    ["bitspaceAddEnum: Adding ", show enum, " to ", show bitspace,+     ", but it already has ", show enum', "."]+  Nothing ->+    if bitspaceValueNames bitspace /= enumValueNames enum+    then error $ concat+         ["bitspaceAddEnum: Trying to add ", show enum, " to ", show bitspace,+          ", but the values aren't equal.\nBitspace values: ", show $ bitspaceValueNames bitspace,+          "\n    Enum values: ", show $ enumValueNames enum]+    else bitspace { bitspaceEnum = Just enum }++-- | @bitspaceAddCppType cppTypeIdentifier toCppValueFn fromCppValueFn@+-- associates a C++ type (plus optional conversion functions) with a bitspace.+-- At least one conversion should be specified, otherwise adding the C++ type+-- will mean nothing.  You should also add use requirements to the bitspace for+-- all of these arguments; see 'HasReqs'.+bitspaceAddCppType :: Identifier -> Maybe String -> Maybe String -> Bitspace -> Bitspace+bitspaceAddCppType cppTypeId toCppValueFnMaybe fromCppValueFnMaybe b =+  case bitspaceCppTypeIdentifier b of+    Just cppTypeId' ->+      error $ concat+      ["bitspaceAddCppType: Adding C++ type ", show cppTypeId,+       " to ", show b, ", but it already has ", show cppTypeId', "."]+    Nothing ->+      b { bitspaceCppTypeIdentifier = Just cppTypeId+        , bitspaceToCppValueFn = toCppValueFnMaybe+        , bitspaceFromCppValueFn = fromCppValueFnMaybe+        }++-- | Whether or not a function may cause side-effects.+--+-- Haskell bindings for pure functions will not be in 'IO', and calls to pure+-- functions will be executed non-strictly.  Calls to impure functions will+-- execute in the IO monad.+--+-- Member functions for mutable classes should not be made pure, because it is+-- difficult in general to control when the call will be made.+data Purity = Nonpure  -- ^ Side-affects are possible.+            | Pure  -- ^ Side-affects will not happen.+            deriving (Eq, Show)++-- | A C++ function declaration.+data Function = Function+  { fnCName :: FnName Identifier+    -- ^ The identifier used to call the function.+  , fnExtName :: ExtName+    -- ^ The function's external name.+  , fnPurity :: Purity+    -- ^ Whether the function is pure.+  , fnParams :: [Type]+    -- ^ The function's parameter types.+  , fnReturn :: Type+    -- ^ The function's return type.+  , fnReqs :: Reqs+    -- ^ Requirements for a binding to call the function.+  , fnExceptionHandlers :: ExceptionHandlers+    -- ^ Exceptions that the function might throw.+  , fnAddendum :: Addendum+    -- ^ The function's addendum.+  }++instance Show Function where+  show fn =+    concat ["<Function ", show (fnExtName fn), " ", show (fnCName fn),+            show (fnParams fn), " ", show (fnReturn fn), ">"]++instance HasExtNames Function where+  getPrimaryExtName = fnExtName++instance HasReqs Function where+  getReqs = fnReqs+  setReqs reqs fn = fn { fnReqs = reqs }++instance HandlesExceptions Function where+  getExceptionHandlers = fnExceptionHandlers+  modifyExceptionHandlers f fn = fn { fnExceptionHandlers = f $ fnExceptionHandlers fn }++instance HasAddendum Function where+  getAddendum = fnAddendum+  setAddendum addendum fn = fn { fnAddendum = addendum }++-- | Creates a binding for a C++ function.+makeFn :: IsFnName Identifier name+       => name+       -> Maybe ExtName+       -- ^ An optional external name; will be automatically derived from+       -- the identifier if absent.+       -> Purity+       -> [Type]  -- ^ Parameter types.+       -> Type  -- ^ Return type.+       -> Function+makeFn cName maybeExtName purity paramTypes retType =+  let fnName = toFnName cName+  in Function fnName+              (extNameOrFnIdentifier fnName maybeExtName)+              purity paramTypes retType mempty mempty mempty++-- | A C++ class declaration.  See 'IsClassEntity' for more information about the+-- interaction between a class's names and the names of entities within the+-- class.+data Class = Class+  { classIdentifier :: Identifier+    -- ^ The identifier used to refer to the class.+  , classExtName :: ExtName+    -- ^ The class's external name.+  , classSuperclasses :: [Class]+    -- ^ The class's public superclasses.+  , classEntities :: [ClassEntity]+    -- ^ The class's entities.+  , classDtorIsPublic :: Bool+    -- ^ The class's methods.+  , classConversion :: ClassConversion+    -- ^ Behaviour for converting objects to and from foriegn values.+  , classReqs :: Reqs+    -- ^ Requirements for a 'Type' to reference this class.+  , classAddendum :: Addendum+    -- ^ The class's addendum.+  , classIsMonomorphicSuperclass :: Bool+    -- ^ This is true for classes passed through+    -- 'classSetMonomorphicSuperclass'.+  , classIsSubclassOfMonomorphic :: Bool+    -- ^ This is true for classes passed through+    -- 'classSetSubclassOfMonomorphic'.+  , classIsException :: Bool+    -- ^ Whether to support using the class as a C++ exception.+  , classEntityPrefix :: String+    -- ^ The prefix applied to the external names of entities (methods, etc.)+    -- within this class when determining the names of foreign languages'+    -- corresponding bindings.  This defaults to the external name of the class,+    -- plus an underscore.  Changing this allows you to potentially have+    -- entities with the same foreign name in separate modules.  This may be the+    -- empty string, in which case the foreign name will simply be the external+    -- name of the entity.+    --+    -- This does __not__ affect the things' external names themselves; external+    -- names must still be unique in an interface.  For instance, a method with+    -- external name @bar@ in a class with external name @Flab@ and prefix+    -- @Flob_@ will use the effective external name @Flab_bar@, but the+    -- generated name in say Haskell would be @Flob_bar@.+    --+    -- See 'IsClassEntity' and 'classSetEntityPrefix'.+  }++instance Eq Class where+  (==) = (==) `on` classExtName++instance Ord Class where+  compare = compare `on` classExtName++instance Show Class where+  show cls =+    concat ["<Class ", show (classExtName cls), " ", show (classIdentifier cls), ">"]++instance HasExtNames Class where+  getPrimaryExtName = classExtName++  getNestedExtNames cls = concatMap (classEntityExtNames cls) $ classEntities cls++instance HasReqs Class where+  getReqs = classReqs+  setReqs reqs cls = cls { classReqs = reqs }++instance HasAddendum Class where+  getAddendum = classAddendum+  setAddendum addendum cls = cls { classAddendum = addendum }++-- | Creates a binding for a C++ class and its contents.+makeClass :: Identifier+          -> Maybe ExtName+          -- ^ An optional external name; will be automatically derived from the+          -- identifier if absent.+          -> [Class]  -- ^ Superclasses.+          -> [ClassEntity]+          -> Class+makeClass identifier maybeExtName supers entities =+  let extName = extNameOrIdentifier identifier maybeExtName+  in Class+     { classIdentifier = identifier+     , classExtName = extName+     , classSuperclasses = supers+     , classEntities = entities+     , classDtorIsPublic = True+     , classConversion = classConversionNone+     , classReqs = mempty+     , classAddendum = mempty+     , classIsMonomorphicSuperclass = False+     , classIsSubclassOfMonomorphic = False+     , classIsException = False+     , classEntityPrefix = fromExtName extName ++ "_"+     }++-- | Sets the prefix applied to foreign languages' entities generated from+-- methods, etc. within the class.+--+-- See 'IsClassEntity' and 'classEntityPrefix'.+classSetEntityPrefix :: String -> Class -> Class+classSetEntityPrefix prefix cls = cls { classEntityPrefix = prefix }++-- | Adds constructors to a class.+classAddEntities :: [ClassEntity] -> Class -> Class+classAddEntities ents cls =+  if null ents then cls else cls { classEntities = classEntities cls ++ ents }++-- | Returns all of the class's variables.+classVariables :: Class -> [ClassVariable]+classVariables = mapMaybe pickVar . classEntities+  where pickVar ent = case ent of+          CEVar v -> Just v+          CECtor _ -> Nothing+          CEMethod _ -> Nothing+          CEProp _ -> Nothing++-- | Returns all of the class's constructors.+classCtors :: Class -> [Ctor]+classCtors = mapMaybe pickCtor . classEntities+  where pickCtor ent = case ent of+          CEVar _ -> Nothing+          CECtor ctor -> Just ctor+          CEMethod _ -> Nothing+          CEProp _ -> Nothing++-- | Returns all of the class's methods, including methods generated from+-- 'Prop's.+classMethods :: Class -> [Method]+classMethods = concatMap pickMethods . classEntities+  where pickMethods ent = case ent of+          CEVar _ -> []+          CECtor _ -> []+          CEMethod m -> [m]+          CEProp (Prop ms) -> ms++-- | Marks a class's destructor as private, so that a binding for it won't be+-- generated.+classSetDtorPrivate :: Class -> Class+classSetDtorPrivate cls = cls { classDtorIsPublic = False }++-- | Explicitly marks a class as being monomorphic (i.e. not having any+-- virtual methods or destructors).  By default, Hoppy assumes that a class that+-- is derived is also polymorphic, but it can happen that this is not the case.+-- Downcasting with @dynamic_cast@ from such classes is not available.  See also+-- 'classSetSubclassOfMonomorphic'.+classSetMonomorphicSuperclass :: Class -> Class+classSetMonomorphicSuperclass cls = cls { classIsMonomorphicSuperclass = True }++-- | Marks a class as being derived from some monomorphic superclass.  This+-- prevents any downcasting to this class.  Generally it is better to use+-- 'classSetMonomorphicSuperclass' on the specific superclasses that are+-- monomorphic, but in cases where this is not possible, this function can be+-- applied to the subclass instead.+classSetSubclassOfMonomorphic :: Class -> Class+classSetSubclassOfMonomorphic cls = cls { classIsSubclassOfMonomorphic = True }++-- | Marks a class as being used as an exception.  This makes the class+-- throwable and catchable.+classMakeException :: Class -> Class+classMakeException cls = case classIsException cls of+  False -> cls { classIsException = True }+  True -> cls++-- | Separately from passing object handles between C++ and foreign languages,+-- objects can also be made to implicitly convert to native values in foreign+-- languages.  A single such type may be associated with any C++ class for each+-- foreign language.  The foreign type and the conversion process in each+-- direction are specified using this object.  Converting a C++ object to a+-- foreign value is also called decoding, and vice versa is called encoding.  A+-- class may be convertible in one direction and not the other.+--+-- To use these implicit conversions, instead of specifying an object handle+-- type such as+-- @'Foreign.Hoppy.Generator.Types.ptrT' . 'Foreign.Hoppy.Generator.Types.objT'@+-- or+-- @'Foreign.Hoppy.Generator.Types.refT' . 'Foreign.Hoppy.Generator.Types.objT'@,+-- use 'Foreign.Hoppy.Generator.Types.objT' directly.+--+-- The subfields in this object specify how to do conversions between C++ and+-- foreign languages.+data ClassConversion = ClassConversion+  { classHaskellConversion :: ClassHaskellConversion+    -- ^ Conversions to and from Haskell.++    -- NOTE!  When adding new languages here, add the language to+    -- 'classSetConversionToHeap', and 'classSetConversionToGc' as well if the+    -- language supports garbage collection.+  }++-- | Conversion behaviour for a class that is not convertible.+classConversionNone :: ClassConversion+classConversionNone = ClassConversion classHaskellConversionNone++-- | Modifies a class's 'ClassConversion' structure with a given function.+classModifyConversion :: (ClassConversion -> ClassConversion) -> Class -> Class+classModifyConversion f cls =+  let cls' = cls { classConversion = f $ classConversion cls }+      conv = classConversion cls'+      haskellConv = classHaskellConversion conv+  in case undefined of+    _ | (isJust (classHaskellConversionToCppFn haskellConv) ||+         isJust (classHaskellConversionFromCppFn haskellConv)) &&+        isNothing (classHaskellConversionType haskellConv) ->+      error $ "classModifyConversion: " ++ show cls' +++      " was given a Haskell-to-C++ or C++-to-Haskell conversion function" +++      " but no Haskell type.  Please provide a classHaskellConversionType."+    _ -> cls'++-- | Replaces a class's 'ClassConversion' structure.+classSetConversion :: ClassConversion -> Class -> Class+classSetConversion c = classModifyConversion $ const c++-- | Controls how conversions between C++ objects and Haskell values happen in+-- Haskell bindings.+data ClassHaskellConversion = ClassHaskellConversion+  { classHaskellConversionType :: Maybe (Haskell.Generator HsType)+    -- ^ Produces the Haskell type that represents a value of the corresponding+    -- C++ class.  This generator may add imports, but must not output code or+    -- add exports.+  , classHaskellConversionToCppFn :: Maybe (Haskell.Generator ())+    -- ^ Produces a Haskell expression that evaluates to a function that takes+    -- an object of the type that 'classHaskellConversionType' generates, and+    -- returns a non-const handle for a new C++ object in IO.  The generator+    -- must output code and may add imports, but must not add exports.+    --+    -- If this field is present, then 'classHaskellConversionType' must also be+    -- present.+  , classHaskellConversionFromCppFn :: Maybe (Haskell.Generator ())+    -- ^ Produces a Haskell expression that evaluates to a function that takes a+    -- const handle for a C++ object, and returns an value of the type that+    -- 'classHaskellConversionType' generates, in IO.  The generator must output+    -- code and may add imports, but must not add exports.+    --+    -- If this field is present, then 'classHaskellConversionType' must also be+    -- present.+  }++-- | Conversion behaviour for a class that is not convertible to or from+-- Haskell.+classHaskellConversionNone :: ClassHaskellConversion+classHaskellConversionNone =+  ClassHaskellConversion+  { classHaskellConversionType = Nothing+  , classHaskellConversionToCppFn = Nothing+  , classHaskellConversionFromCppFn = Nothing+  }++-- | Replaces a class's 'classHaskellConversion' with a given value.+classSetHaskellConversion :: ClassHaskellConversion -> Class -> Class+classSetHaskellConversion conv = classModifyConversion $ \c ->+  c { classHaskellConversion = conv }++-- | Things that live inside of a class, and have the class's external name+-- prepended to their own in generated code.  With an external name of @\"bar\"@+-- and a class with external name @\"foo\"@, the resulting name will be+-- @\"foo_bar\"@.+--+-- See 'classEntityPrefix' and 'classSetEntityPrefix'.+class IsClassEntity a where+  -- | Extracts the external name of the object, without the class name added.+  classEntityExtNameSuffix :: a -> ExtName++-- | Computes the external name to use in generated code, containing both the+-- class's and object's external names.  This is the concatenation of the+-- class's and entity's external names, separated by an underscore.+classEntityExtName :: IsClassEntity a => Class -> a -> ExtName+classEntityExtName cls x =+  toExtName $ fromExtName (classExtName cls) ++ "_" ++ fromExtName (classEntityExtNameSuffix x)++-- | Computes the name under which a class entity is to be exposed in foreign+-- languages.  This is the concatenation of a class's entity prefix, and the+-- external name of the entity.+classEntityForeignName :: IsClassEntity a => Class -> a -> ExtName+classEntityForeignName cls x =+  classEntityForeignName' cls $ classEntityExtNameSuffix x++-- | Computes the name under which a class entity is to be exposed in foreign+-- languages, given a class and an entity's external name.  The result is the+-- concatenation of a class's entity prefix, and the external name of the+-- entity.+classEntityForeignName' :: Class -> ExtName -> ExtName+classEntityForeignName' cls extName =+  toExtName $ classEntityPrefix cls ++ fromExtName extName++-- | A C++ entity that belongs to a class.+data ClassEntity =+    CEVar ClassVariable+  | CECtor Ctor+  | CEMethod Method+  | CEProp Prop++-- | Returns all of the names in a 'ClassEntity' within the corresponding+-- 'Class'.+classEntityExtNames :: Class -> ClassEntity -> [ExtName]+classEntityExtNames cls ent = case ent of+  CEVar v -> [classEntityExtName cls v]+  CECtor ctor -> [classEntityExtName cls ctor]+  CEMethod m -> [classEntityExtName cls m]+  CEProp (Prop methods) -> map (classEntityExtName cls) methods++-- | A C++ member variable.+data ClassVariable = ClassVariable+  { classVarCName :: String+    -- ^ The variable's C++ name.+  , classVarExtName :: ExtName+    -- ^ The variable's external name.+  , classVarType :: Type+    -- ^ The variable's type.  This may be+    -- 'Foreign.Hoppy.Generator.Types.constT' to indicate that the variable is+    -- read-only.+  , classVarStatic :: Staticness+    -- ^ Whether the variable is static (i.e. whether it exists once in the+    -- class itself and not in each instance).+  , classVarGettable :: Bool+    -- ^ Whether the variable should have an accompanying getter. Note this+    -- exists only for disabling getters on callback variables - as there is+    -- currently no functionality to pass callbacks out of c+++  }++instance Show ClassVariable where+  show v =+    concat ["<ClassVariable ",+            show $ classVarCName v, " ",+            show $ classVarExtName v, " ",+            show $ classVarStatic v, " ",+            show $ classVarType v, ">"]++instance IsClassEntity ClassVariable where+  classEntityExtNameSuffix = classVarExtName++-- | Creates a 'ClassVariable' with full generality and manual name specification.+--+-- The result is wrapped in a 'CEVar'.  For an unwrapped value, use+-- 'makeClassVariable_'.+makeClassVariable :: String -> Maybe ExtName -> Type -> Staticness -> Bool -> ClassEntity+makeClassVariable cName maybeExtName tp static gettable =+  CEVar $ makeClassVariable_ cName maybeExtName tp static gettable++-- | The unwrapped version of 'makeClassVariable'.+makeClassVariable_ :: String -> Maybe ExtName -> Type -> Staticness -> Bool -> ClassVariable+makeClassVariable_ cName maybeExtName =+  ClassVariable cName $ extNameOrString cName maybeExtName++-- | Creates a 'ClassVariable' for a nonstatic class variable for+-- @class::varName@ whose external name is @class_varName@.+--+-- The result is wrapped in a 'CEVar'.  For an unwrapped value, use+-- 'mkClassVariable_'.+mkClassVariable :: String -> Type -> ClassEntity+mkClassVariable = (CEVar .) . mkClassVariable_++-- | The unwrapped version of 'mkClassVariable'.+mkClassVariable_ :: String -> Type -> ClassVariable+mkClassVariable_ cName t = makeClassVariable_ cName Nothing t Nonstatic True++-- | Same as 'mkClassVariable', but returns a static variable instead.+--+-- The result is wrapped in a 'CEVar'.  For an unwrapped value, use+-- 'mkStaticClassVariable_'.+mkStaticClassVariable :: String -> Type -> ClassEntity+mkStaticClassVariable = (CEVar .) . mkStaticClassVariable_++-- | The unwrapped version of 'mkStaticClassVariable'.+mkStaticClassVariable_ :: String -> Type -> ClassVariable+mkStaticClassVariable_ cName t = makeClassVariable_ cName Nothing t Static True++-- | Returns the external name of the getter function for the class variable.+classVarGetterExtName :: Class -> ClassVariable -> ExtName+classVarGetterExtName cls v =+  toExtName $ fromExtName (classEntityExtName cls v) ++ "_get"++-- | Returns the foreign name of the getter function for the class variable.+classVarGetterForeignName :: Class -> ClassVariable -> ExtName+classVarGetterForeignName cls v =+  toExtName $ fromExtName (classEntityForeignName cls v) ++ "_get"++-- | Returns the external name of the setter function for the class variable.+classVarSetterExtName :: Class -> ClassVariable -> ExtName+classVarSetterExtName cls v =+  toExtName $ fromExtName (classEntityExtName cls v) ++ "_set"++-- | Returns the foreign name of the setter function for the class variable.+classVarSetterForeignName :: Class -> ClassVariable -> ExtName+classVarSetterForeignName cls v =+  toExtName $ fromExtName (classEntityForeignName cls v) ++ "_set"++-- | A C++ class constructor declaration.+data Ctor = Ctor+  { ctorExtName :: ExtName+    -- ^ The constructor's external name.+  , ctorParams :: [Type]+    -- ^ The constructor's parameter types.+  , ctorExceptionHandlers :: ExceptionHandlers+    -- ^ Exceptions that the constructor may throw.+  }++instance Show Ctor where+  show ctor = concat ["<Ctor ", show (ctorExtName ctor), " ", show (ctorParams ctor), ">"]++instance HandlesExceptions Ctor where+  getExceptionHandlers = ctorExceptionHandlers+  modifyExceptionHandlers f ctor = ctor { ctorExceptionHandlers = f $ ctorExceptionHandlers ctor }++instance IsClassEntity Ctor where+  classEntityExtNameSuffix = ctorExtName++-- | Creates a 'Ctor' with full generality.+--+-- The result is wrapped in a 'CECtor'.  For an unwrapped value, use+-- 'makeCtor_'.+makeCtor :: ExtName+         -> [Type]  -- ^ Parameter types.+         -> ClassEntity+makeCtor = (CECtor .) . makeCtor_++-- | The unwrapped version of 'makeCtor'.+makeCtor_ :: ExtName -> [Type] -> Ctor+makeCtor_ extName paramTypes = Ctor extName paramTypes mempty++-- | @mkCtor name@ creates a 'Ctor' whose external name is @className_name@.+--+-- The result is wrapped in a 'CECtor'.  For an unwrapped value, use+-- 'makeCtor_'.+mkCtor :: String+       -> [Type]  -- ^ Parameter types.+       -> ClassEntity+mkCtor = (CECtor .) . mkCtor_++-- | The unwrapped version of 'mkCtor'.+mkCtor_ :: String -> [Type] -> Ctor+mkCtor_ = makeCtor_ . toExtName++-- | Searches a class for a copy constructor, returning it if found.+classFindCopyCtor :: Class -> Maybe Ctor+classFindCopyCtor cls = case mapMaybe check $ classEntities cls of+  [ctor] -> Just ctor+  _ -> Nothing+  where check entity = case entity of+          CECtor ctor ->+            let params = map (stripConst . normalizeType) (ctorParams ctor)+            in if params == [Internal_TObj cls] ||+                  params == [Internal_TRef $ Internal_TConst $ Internal_TObj cls]+            then Just ctor+            else Nothing+          _ -> Nothing++-- | A C++ class method declaration.+--+-- Any operator function that can be written as a method may have its binding be+-- written either as part of the associated class or as a separate entity,+-- independently of how the function is declared in C++.+data Method = Method+  { methodImpl :: MethodImpl+    -- ^ The underlying code that the binding calls.+  , methodExtName :: ExtName+    -- ^ The method's external name.+  , methodApplicability :: MethodApplicability+    -- ^ How the method is associated to its class.+  , methodPurity :: Purity+    -- ^ Whether the method is pure.+  , methodParams :: [Type]+    -- ^ The method's parameter types.+  , methodReturn :: Type+    -- ^ The method's return type.+  , methodExceptionHandlers :: ExceptionHandlers+    -- ^ Exceptions that the method might throw.+  }++instance Show Method where+  show method =+    concat ["<Method ", show (methodExtName method), " ",+            case methodImpl method of+              RealMethod name -> show name+              FnMethod name -> show name, " ",+            show (methodApplicability method), " ",+            show (methodPurity method), " ",+            show (methodParams method), " ",+            show (methodReturn method), ">"]++instance HandlesExceptions Method where+  getExceptionHandlers = methodExceptionHandlers++  modifyExceptionHandlers f method =+    method { methodExceptionHandlers = f $ methodExceptionHandlers method }++instance IsClassEntity Method where+  classEntityExtNameSuffix = methodExtName++-- | The C++ code to which a 'Method' is bound.+data MethodImpl =+  RealMethod (FnName String)+  -- ^ The 'Method' is bound to an actual class method.+  | FnMethod (FnName Identifier)+    -- ^ The 'Method' is bound to a wrapper function.  When wrapping a method+    -- with another function, this is preferrable to just using a 'Function'+    -- binding because a method will still appear to be part of the class in+    -- foreign bindings.+  deriving (Eq, Show)++-- | How a method is associated to its class.  A method may be static, const, or+-- neither (a regular method).+data MethodApplicability = MNormal | MStatic | MConst+                         deriving (Bounded, Enum, Eq, Show)++-- | Whether or not a method is const.+data Constness = Nonconst | Const+               deriving (Bounded, Enum, Eq, Show)++-- | Returns the opposite constness value.+constNegate :: Constness -> Constness+constNegate Nonconst = Const+constNegate Const = Nonconst++-- | Whether or not a method is static.+data Staticness = Nonstatic | Static+               deriving (Bounded, Enum, Eq, Show)++-- | Returns the constness of a method, based on its 'methodApplicability'.+methodConst :: Method -> Constness+methodConst method = case methodApplicability method of+  MConst -> Const+  _ -> Nonconst++-- | Returns the staticness of a method, based on its 'methodApplicability'.+methodStatic :: Method -> Staticness+methodStatic method = case methodApplicability method of+  MStatic -> Static+  _ -> Nonstatic++-- | Creates a 'Method' with full generality and manual name specification.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'makeMethod_'.+makeMethod :: IsFnName String name+           => name  -- ^ The C++ name of the method.+           -> ExtName  -- ^ The external name of the method.+           -> MethodApplicability+           -> Purity+           -> [Type]  -- ^ Parameter types.+           -> Type  -- ^ Return type.+           -> ClassEntity+makeMethod = (((((CEMethod .) .) .) .) .) . makeMethod_++-- | The unwrapped version of 'makeMethod'.+makeMethod_ :: IsFnName String name+            => name+            -> ExtName+            -> MethodApplicability+            -> Purity+            -> [Type]+            -> Type+            -> Method+makeMethod_ cName extName appl purity paramTypes retType =+  Method (RealMethod $ toFnName cName) extName appl purity paramTypes retType mempty++-- | Creates a 'Method' that is in fact backed by a C++ non-member function (a+-- la 'makeFn'), but appears to be a regular method.  This is useful for+-- wrapping a method on the C++ side when its arguments aren't right for binding+-- directly.+--+-- A @this@ pointer parameter is __not__ automatically added to the parameter+-- list for non-static methods created with @makeFnMethod@.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'makeFnMethod_'.+makeFnMethod :: IsFnName Identifier name+             => name+             -> String+             -> MethodApplicability+             -> Purity+             -> [Type]+             -> Type+             -> ClassEntity+makeFnMethod = (((((CEMethod .) .) .) .) .) . makeFnMethod_++-- | The unwrapped version of 'makeFnMethod'.+makeFnMethod_ :: IsFnName Identifier name+              => name+              -> String+              -> MethodApplicability+              -> Purity+              -> [Type]+              -> Type+              -> Method+makeFnMethod_ cName foreignName appl purity paramTypes retType =+  Method (FnMethod $ toFnName cName) (toExtName foreignName)+         appl purity paramTypes retType mempty++-- | This function is internal.+--+-- Creates a method similar to 'makeMethod', but with automatic naming.  The+-- method's external name will be @className ++ \"_\" ++ cppMethodName@.  If the+-- method name is a 'FnOp' then the 'operatorPreferredExtName' will be appeneded+-- to the class name.+--+-- For creating multiple bindings to a method, see 'makeMethod''.+makeMethod' :: IsFnName String name+            => name  -- ^ The C++ name of the method.+            -> MethodApplicability+            -> Purity+            -> [Type]  -- ^ Parameter types.+            -> Type  -- ^ Return type.+            -> Method+makeMethod' name = makeMethod''' (toFnName name) Nothing++-- | This function is internal.+--+-- Creates a method similar to 'makeMethod'', but with an custom string that+-- will be appended to the class name to form the method's external name.  This+-- is useful for making multiple bindings to a method, e.g. for overloading and+-- optional arguments.+makeMethod'' :: IsFnName String name+             => name  -- ^ The C++ name of the method.+             -> String  -- ^ A foreign name for the method.+             -> MethodApplicability+             -> Purity+             -> [Type]  -- ^ Parameter types.+             -> Type  -- ^ Return type.+             -> Method+makeMethod'' name foreignName = makeMethod''' (toFnName name) $ Just foreignName++-- | The implementation of 'makeMethod'' and 'makeMethod'''.+makeMethod''' :: FnName String  -- ^ The C++ name of the method.+              -> Maybe String  -- ^ A foreign name for the method.+              -> MethodApplicability+              -> Purity+              -> [Type]  -- ^ Parameter types.+              -> Type  -- ^ Return type.+              -> Method+makeMethod''' (FnName "") maybeForeignName _ _ paramTypes retType =+  error $ concat ["makeMethod''': Given an empty method name with foreign name ",+                  show maybeForeignName, ", parameter types ", show paramTypes,+                  ", and return type ", show retType, "."]+makeMethod''' name (Just "") _ _ paramTypes retType =+  error $ concat ["makeMethod''': Given an empty foreign name with method ",+                  show name, ", parameter types ", show paramTypes, ", and return type ",+                  show retType, "."]+makeMethod''' name maybeForeignName appl purity paramTypes retType =+  let extName = flip fromMaybe (toExtName <$> maybeForeignName) $ case name of+        FnName s -> toExtName s+        FnOp op -> operatorPreferredExtName op+  in makeMethod_ name extName appl purity paramTypes retType++-- | Creates a nonconst, nonstatic 'Method' for @class::methodName@ and whose+-- external name is @class_methodName@.  If the name is an operator, then the+-- 'operatorPreferredExtName' will be used in the external name.+--+-- For creating multiple bindings to a method, see 'mkMethod''.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'mkMethod_'.+mkMethod :: IsFnName String name+         => name  -- ^ The C++ name of the method.+         -> [Type]  -- ^ Parameter types.+         -> Type  -- ^ Return type.+         -> ClassEntity+mkMethod = ((CEMethod .) .) . mkMethod_++-- | The unwrapped version of 'mkMethod'.+mkMethod_ :: IsFnName String name+          => name+          -> [Type]+          -> Type+          -> Method+mkMethod_ name = makeMethod' name MNormal Nonpure++-- | Creates a nonconst, nonstatic 'Method' for method @class::methodName@ and+-- whose external name is @class_methodName@.  This enables multiple 'Method's+-- with different foreign names (and hence different external names) to bind to+-- the same method, e.g. to make use of optional arguments or overloading.  See+-- 'mkMethod' for a simpler form.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'mkMethod'_'.+mkMethod' :: IsFnName String name+          => name  -- ^ The C++ name of the method.+          -> String  -- ^ A foreign name for the method.+          -> [Type]  -- ^ Parameter types.+          -> Type  -- ^ Return type.+          -> ClassEntity+mkMethod' = (((CEMethod .) .) .) . mkMethod'_++-- | The unwrapped version of 'mkMethod''.+mkMethod'_ :: IsFnName String name+           => name+           -> String+           -> [Type]+           -> Type+           -> Method+mkMethod'_ cName foreignName = makeMethod'' cName foreignName MNormal Nonpure++-- | Same as 'mkMethod', but returns an 'MConst' method.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'mkConstMethod_'.+mkConstMethod :: IsFnName String name => name -> [Type] -> Type -> ClassEntity+mkConstMethod = ((CEMethod .) .) . mkConstMethod_++-- | The unwrapped version of 'mkConstMethod'.+mkConstMethod_ :: IsFnName String name => name -> [Type] -> Type -> Method+mkConstMethod_ name = makeMethod' name MConst Nonpure++-- | Same as 'mkMethod'', but returns an 'MConst' method.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'mkConstMethod'_'.+mkConstMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> ClassEntity+mkConstMethod' = (((CEMethod .) .) .) . mkConstMethod'_++-- | The unwrapped version of 'mkConstMethod''.+mkConstMethod'_ :: IsFnName String name => name -> String -> [Type] -> Type -> Method+mkConstMethod'_ cName foreignName = makeMethod'' cName foreignName MConst Nonpure++-- | Same as 'mkMethod', but returns an 'MStatic' method.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'mkStaticMethod_'.+mkStaticMethod :: IsFnName String name => name -> [Type] -> Type -> ClassEntity+mkStaticMethod = ((CEMethod .) .) . mkStaticMethod_++-- | The unwrapped version of 'mkStaticMethod'.+mkStaticMethod_ :: IsFnName String name => name -> [Type] -> Type -> Method+mkStaticMethod_ name = makeMethod' name MStatic Nonpure++-- | Same as 'mkMethod'', but returns an 'MStatic' method.+--+-- The result is wrapped in a 'CEMethod'.  For an unwrapped value, use+-- 'mkStaticMethod'_'.+mkStaticMethod' :: IsFnName String name => name -> String -> [Type] -> Type -> ClassEntity+mkStaticMethod' = (((CEMethod .) .) .) . mkStaticMethod'_++-- | The unwrapped version of 'mkStaticMethod''.+mkStaticMethod'_ :: IsFnName String name => name -> String -> [Type] -> Type -> Method+mkStaticMethod'_ cName foreignName = makeMethod'' cName foreignName MStatic Nonpure++-- | A \"property\" getter/setter pair.+newtype Prop = Prop [Method]++-- | Creates a getter/setter binding pair for methods:+--+-- > T foo() const+-- > void setFoo(T)+--+-- The result is wrapped in a 'CEProp'.  For an unwrapped value, use+-- 'mkProp_'.+mkProp :: String -> Type -> ClassEntity+mkProp = (CEProp .) . mkProp_++-- | The unwrapped version of 'mkProp'.+mkProp_ :: String -> Type -> Prop+mkProp_ name t =+  let c:cs = name+      setName = 's' : 'e' : 't' : toUpper c : cs+  in Prop [ mkConstMethod_ name [] t+          , mkMethod_ setName [t] Internal_TVoid+          ]++-- | Creates a getter/setter binding pair for static methods:+--+-- > static T foo() const+-- > static void setFoo(T)+mkStaticProp :: String -> Type -> ClassEntity+mkStaticProp = (CEProp .) . mkStaticProp_++-- | The unwrapped version of 'mkStaticProp'.+mkStaticProp_ :: String -> Type -> Prop+mkStaticProp_ name t =+  let c:cs = name+      setName = 's' : 'e' : 't' : toUpper c : cs+  in Prop [ mkStaticMethod_ name [] t+          , mkStaticMethod_ setName [t] Internal_TVoid+          ]++-- | Creates a getter/setter binding pair for boolean methods, where the getter+-- is prefixed with @is@:+--+-- > bool isFoo() const+-- > void setFoo(bool)+--+-- The result is wrapped in a 'CEProp'.  For an unwrapped value, use+-- 'mkBoolIsProp_'.+mkBoolIsProp :: String -> ClassEntity+mkBoolIsProp = CEProp . mkBoolIsProp_++-- | The unwrapped version of 'mkBoolIsProp'.+mkBoolIsProp_ :: String -> Prop+mkBoolIsProp_ name =+  let c:cs = name+      name' = toUpper c : cs+      isName = 'i':'s':name'+      setName = 's':'e':'t':name'+  in Prop [ mkConstMethod_ isName [] Internal_TBool+          , mkMethod_ setName [Internal_TBool] Internal_TVoid+          ]++-- | Creates a getter/setter binding pair for boolean methods, where the getter+-- is prefixed with @has@:+--+-- > bool hasFoo() const+-- > void setFoo(bool)+--+-- The result is wrapped in a 'CEProp'.  For an unwrapped value, use+-- 'mkBoolHasProp_'.+mkBoolHasProp :: String -> ClassEntity+mkBoolHasProp = CEProp . mkBoolHasProp_++-- | The unwrapped version of 'mkBoolHasProp'.+mkBoolHasProp_ :: String -> Prop+mkBoolHasProp_ name =+  let c:cs = name+      name' = toUpper c : cs+      hasName = 'h':'a':'s':name'+      setName = 's':'e':'t':name'+  in Prop [ mkConstMethod_ hasName [] Internal_TBool+          , mkMethod_ setName [Internal_TBool] Internal_TVoid+          ]++-- | A non-C++ function that can be invoked via a C++ functor or function+-- pointer.+data Callback = Callback+  { callbackExtName :: ExtName+    -- ^ The callback's external name.+  , callbackParams :: [Type]+    -- ^ The callback's parameter types.+  , callbackReturn :: Type+    -- ^ The callback's return type.+  , callbackThrows :: Maybe Bool+    -- ^ Whether the callback supports throwing C++ exceptions from Haskell into+    -- C++ during its execution.  When absent, the value is inherited from+    -- 'moduleCallbacksThrow' and 'interfaceCallbacksThrow'.+  , callbackReqs :: Reqs+    -- ^ Requirements for the callback.+  , callbackAddendum :: Addendum+    -- ^ The callback's addendum.+  }++instance Eq Callback where+  (==) = (==) `on` callbackExtName++instance Show Callback where+  show cb =+    concat ["<Callback ", show (callbackExtName cb), " ", show (callbackParams cb), " ",+            show (callbackReturn cb)]++instance HasExtNames Callback where+  getPrimaryExtName = callbackExtName++instance HasReqs Callback where+  getReqs = callbackReqs+  setReqs reqs cb = cb { callbackReqs = reqs }++instance HasAddendum Callback where+  getAddendum = callbackAddendum+  setAddendum addendum cb = cb { callbackAddendum = addendum }++-- | Creates a binding for constructing callbacks into foreign code.+makeCallback :: ExtName+             -> [Type]  -- ^ Parameter types.+             -> Type  -- ^ Return type.+             -> Callback+makeCallback extName paramTypes retType =+  Callback extName paramTypes retType Nothing mempty mempty++-- | Sets whether a callback supports handling thrown C++ exceptions and passing+-- them into C++.+callbackSetThrows :: Bool -> Callback -> Callback+callbackSetThrows value cb = cb { callbackThrows = Just value }++-- | Each exception class has a unique exception ID.+newtype ExceptionId = ExceptionId+  { getExceptionId :: Int  -- ^ Internal.+  } deriving (Eq, Show)++-- | The exception ID that represents the catch-all type.+exceptionCatchAllId :: ExceptionId+exceptionCatchAllId = ExceptionId 1++-- | The lowest exception ID to be used for classes.+exceptionFirstFreeId :: Int+exceptionFirstFreeId = getExceptionId exceptionCatchAllId + 1++-- | Indicates the ability to handle a certain type of C++ exception.+data ExceptionHandler =+    CatchClass Class+    -- ^ Indicates that instances of the given class are handled (including+    -- derived types).+  | CatchAll+    -- ^ Indicates that all C++ exceptions are handled, i.e. @catch (...)@.+  deriving (Eq, Ord)++-- | Represents a list of exception handlers to be used for a body of code.+-- Order is important; a 'CatchAll' will prevent all subsequent handlers from+-- being invoked.+data ExceptionHandlers = ExceptionHandlers+  { exceptionHandlersList :: [ExceptionHandler]+    -- ^ Extracts the list of exception handlers.+  }++instance Monoid ExceptionHandlers where+  mempty = ExceptionHandlers []++  mappend e1 e2 =+    ExceptionHandlers+    (S.toList $ S.fromList $ exceptionHandlersList e1 ++ exceptionHandlersList e2)++-- | Types that can handle exceptions.+class HandlesExceptions a where+  -- | Extracts the exception handlers for an object.+  getExceptionHandlers :: a -> ExceptionHandlers++  -- | Modifies an object's exception handlers with a given function.+  modifyExceptionHandlers :: (ExceptionHandlers -> ExceptionHandlers) -> a -> a++-- | Appends additional exception handlers to an object.+handleExceptions :: HandlesExceptions a => [ExceptionHandler] -> a -> a+handleExceptions classes =+  modifyExceptionHandlers $ mappend mempty {exceptionHandlersList = classes}++-- | A collection of imports for a Haskell module.  This is a monoid: import+-- Statements are merged to give the union of imported bindings.+--+-- This structure supports two specific types of imports:+--     - @import Foo (...)@+--     - @import qualified Foo as Bar@+-- Imports with @as@ but without @qualified@, and @qualified@ imports with a+-- spec list, are not supported.  This satisfies the needs of the code+-- generator, and keeps the merging logic simple.+newtype HsImportSet = HsImportSet+  { getHsImportSet :: M.Map HsImportKey HsImportSpecs+    -- ^ Returns the import set's internal map from module names to imported+    -- bindings.+  } deriving (Show)++instance Monoid HsImportSet where+  mempty = HsImportSet M.empty++  mappend (HsImportSet m) (HsImportSet m') =+    HsImportSet $ M.unionWith mergeImportSpecs m m'++  mconcat sets =+    HsImportSet $ M.unionsWith mergeImportSpecs $ map getHsImportSet sets++-- | A literal piece of code that will be inserted into a generated source file+-- after the regular binding glue.  The 'Monoid' instance concatenates code+-- (actions).+data Addendum = Addendum+  { addendumHaskell :: Haskell.Generator ()+    -- ^ Code to be output into the Haskell binding.  May also add imports and+    -- exports.+  }++instance Monoid Addendum where+  mempty = Addendum $ return ()+  mappend (Addendum a) (Addendum b) = Addendum $ a >> b++-- | A typeclass for types that have an addendum.+class HasAddendum a where+  {-# MINIMAL getAddendum, (setAddendum | modifyAddendum) #-}++  -- | Returns an object's addendum.+  getAddendum :: a -> Addendum++  -- | Replaces and object's addendum with another.+  setAddendum :: Addendum -> a -> a+  setAddendum addendum = modifyAddendum $ const addendum++  -- | Modified an object's addendum.+  modifyAddendum :: (Addendum -> Addendum) -> a -> a+  modifyAddendum f x = setAddendum (f $ getAddendum x) x++-- | Adds a Haskell addendum to an object.+addAddendumHaskell :: HasAddendum a => Haskell.Generator () -> a -> a+addAddendumHaskell gen = modifyAddendum $ \addendum ->+  addendum `mappend` mempty { addendumHaskell = gen }++-- | Constructor for an import set.+makeHsImportSet :: M.Map HsImportKey HsImportSpecs -> HsImportSet+makeHsImportSet = HsImportSet++-- | Sets all of the import specifications in an import set to be+-- @{-#SOURCE#-}@ imports.+hsImportSetMakeSource :: HsImportSet -> HsImportSet+hsImportSetMakeSource (HsImportSet m) =+  HsImportSet $ M.map (\specs -> specs { hsImportSource = True }) m++-- | A Haskell module name.+type HsModuleName = String++-- | References an occurrence of an import statement, under which bindings can+-- be imported.  Only imported specs under equal 'HsImportKey's may be merged.+data HsImportKey = HsImportKey+  { hsImportModule :: HsModuleName+  , hsImportQualifiedName :: Maybe HsModuleName+  } deriving (Eq, Ord, Show)++-- | A specification of bindings to import from a module.  If 'Nothing', then+-- the entire module is imported.  If @'Just' 'M.empty'@, then only instances+-- are imported.+data HsImportSpecs = HsImportSpecs+  { getHsImportSpecs :: Maybe (M.Map HsImportName HsImportVal)+  , hsImportSource :: Bool+  } deriving (Show)++-- | Combines two 'HsImportSpecs's into one that imports everything that the two+-- did separately.+mergeImportSpecs :: HsImportSpecs -> HsImportSpecs -> HsImportSpecs+mergeImportSpecs (HsImportSpecs mm s) (HsImportSpecs mm' s') =+  HsImportSpecs (liftM2 mergeMaps mm mm') (s || s')+  where mergeMaps = M.unionWith mergeValues+        mergeValues v v' = case (v, v') of+          (HsImportValAll, _) -> HsImportValAll+          (_, HsImportValAll) -> HsImportValAll+          (HsImportValSome s, HsImportValSome s') -> HsImportValSome $ s ++ s'+          (x@(HsImportValSome _), _) -> x+          (_, x@(HsImportValSome _)) -> x+          (HsImportVal, HsImportVal) -> HsImportVal++-- | An identifier that can be imported from a module.  Symbols may be used here+-- when surrounded by parentheses.  Examples are @\"fmap\"@ and @\"(++)\"@.+type HsImportName = String++-- | Specifies how a name is imported.+data HsImportVal =+  HsImportVal+  -- ^ The name is imported, and nothing underneath it is.+  | HsImportValSome [HsImportName]+    -- ^ The name is imported, as are specific names underneath it.  This is a+    -- @X (a, b, c)@ import.+  | HsImportValAll+    -- ^ The name is imported, along with all names underneath it.  This is a @X+    -- (..)@ import.+  deriving (Show)++-- | An import for the entire contents of a Haskell module.+hsWholeModuleImport :: HsModuleName -> HsImportSet+hsWholeModuleImport moduleName =+  HsImportSet $ M.singleton (HsImportKey moduleName Nothing) $+  HsImportSpecs Nothing False++-- | A qualified import of a Haskell module.+hsQualifiedImport :: HsModuleName -> HsModuleName -> HsImportSet+hsQualifiedImport moduleName qualifiedName =+  HsImportSet $ M.singleton (HsImportKey moduleName $ Just qualifiedName) $+  HsImportSpecs Nothing False++-- | An import of a single name from a Haskell module.+hsImport1 :: HsModuleName -> HsImportName -> HsImportSet+hsImport1 moduleName valueName = hsImport1' moduleName valueName HsImportVal++-- | A detailed import of a single name from a Haskell module.+hsImport1' :: HsModuleName -> HsImportName -> HsImportVal -> HsImportSet+hsImport1' moduleName valueName valueType =+  HsImportSet $ M.singleton (HsImportKey moduleName Nothing) $+  HsImportSpecs (Just $ M.singleton valueName valueType) False++-- | An import of multiple names from a Haskell module.+hsImports :: HsModuleName -> [HsImportName] -> HsImportSet+hsImports moduleName names =+  hsImports' moduleName $ map (\name -> (name, HsImportVal)) names++-- | A detailed import of multiple names from a Haskell module.+hsImports' :: HsModuleName -> [(HsImportName, HsImportVal)] -> HsImportSet+hsImports' moduleName values =+  HsImportSet $ M.singleton (HsImportKey moduleName Nothing) $+  HsImportSpecs (Just $ M.fromList values) False++-- | Imports "Data.Bits" qualified as @HoppyDB@.+hsImportForBits :: HsImportSet+hsImportForBits = hsQualifiedImport "Data.Bits" "HoppyDB"++-- | Imports "Control.Exception" qualified as @HoppyCE@.+hsImportForException :: HsImportSet+hsImportForException = hsQualifiedImport "Control.Exception" "HoppyCE"++-- | Imports "Data.Int" qualified as @HoppyDI@.+hsImportForInt :: HsImportSet+hsImportForInt = hsQualifiedImport "Data.Int" "HoppyDI"++-- | Imports "Data.Word" qualified as @HoppyDW@.+hsImportForWord :: HsImportSet+hsImportForWord = hsQualifiedImport "Data.Word" "HoppyDW"++-- | Imports "Foreign" qualified as @HoppyF@.+hsImportForForeign :: HsImportSet+hsImportForForeign = hsQualifiedImport "Foreign" "HoppyF"++-- | Imports "Foreign.C" qualified as @HoppyFC@.+hsImportForForeignC :: HsImportSet+hsImportForForeignC = hsQualifiedImport "Foreign.C" "HoppyFC"++-- | Imports "Data.Map" qualified as @HoppyDM@.+hsImportForMap :: HsImportSet+hsImportForMap = hsQualifiedImport "Data.Map" "HoppyDM"++-- | Imports "Prelude" qualified as @HoppyP@.+hsImportForPrelude :: HsImportSet+hsImportForPrelude = hsQualifiedImport "Prelude" "HoppyP"++-- | Imports "Foreign.Hoppy.Runtime" qualified as @HoppyFHR@.+hsImportForRuntime :: HsImportSet+hsImportForRuntime = hsQualifiedImport "Foreign.Hoppy.Runtime" "HoppyFHR"++-- | Imports "System.Posix.Types" qualified as @HoppySPT@.+hsImportForSystemPosixTypes :: HsImportSet+hsImportForSystemPosixTypes = hsQualifiedImport "System.Posix.Types" "HoppySPT"++-- | Imports "Data.Typeable" qualified as @HoppyDT@.+hsImportForTypeable :: HsImportSet+hsImportForTypeable = hsQualifiedImport "Data.Typeable" "HoppyDT"++-- | Imports "System.IO.Unsafe" qualified as @HoppySIU@.+hsImportForUnsafeIO :: HsImportSet+hsImportForUnsafeIO = hsQualifiedImport "System.IO.Unsafe" "HoppySIU"++-- | Returns an error message indicating that+-- 'Foreign.Hoppy.Generator.Types.objToHeapT' is used where data is going from a+-- foreign language into C++.+objToHeapTWrongDirectionErrorMsg :: Maybe String -> Class -> String+objToHeapTWrongDirectionErrorMsg maybeCaller cls =+  concat [maybe "" (++ ": ") maybeCaller,+          "(TObjToHeap ", show cls, ") cannot be passed into C++",+          maybe "" (const ".") maybeCaller]++-- | Returns an error message indicating that+-- 'Foreign.Hoppy.Generator.Types.objToHeapT' is used where data is going from a+-- foreign language into C++.+tToGcInvalidFormErrorMessage :: Maybe String -> Type -> String+tToGcInvalidFormErrorMessage maybeCaller typeArg =+  concat [maybe "" (++ ": ") maybeCaller,+          "(", show (Internal_TToGc typeArg), ") is an invalid form for TToGc.",+          maybe "" (const ".") maybeCaller]++-- | Returns an error message indicating that+-- 'Foreign.Hoppy.Generator.Types.toGcT' is used where data is going from a+-- foreign language into C++.+toGcTWrongDirectionErrorMsg :: Maybe String -> Type -> String+toGcTWrongDirectionErrorMsg maybeCaller typeArg =+  concat [maybe "" (++ ": ") maybeCaller,+          "(", show (Internal_TToGc typeArg), ") cannot be passed into C++",+          maybe "" (const ".") maybeCaller]
src/Foreign/Hoppy/Generator/Spec/ClassFeature.hs view
@@ -19,6 +19,7 @@  -- | Bindings for common class operations, such as copy construction. module Foreign.Hoppy.Generator.Spec.ClassFeature (+  -- * Class features   ClassFeature (..),   classAddFeatures,   ) where@@ -26,7 +27,7 @@ #if !MIN_VERSION_base(4,8,0) import Data.Monoid (mempty) #endif-import Foreign.Hoppy.Generator.Spec+import Foreign.Hoppy.Generator.Spec.Base import Foreign.Hoppy.Generator.Types  -- | Sets of functionality that can be stamped onto a class with@@ -45,41 +46,37 @@     -- Foo::operator==(const Foo&)@.   deriving (Eq, Show) -featureContents :: ClassFeature -> Class -> ([Ctor], [Method], Reqs)+featureContents :: ClassFeature -> Class -> ([ClassEntity], Reqs) featureContents feature cls = case feature of   Assignable -> assignableContents cls   Comparable -> comparableContents cls   Copyable -> copyableContents cls   Equatable -> equatableContents cls -assignableContents :: Class -> ([Ctor], [Method], Reqs)+assignableContents :: Class -> ([ClassEntity], Reqs) assignableContents cls =-  ([],-   [ mkMethod OpAssign [refT $ constT $ objT cls] $ refT $ objT cls+  ([ mkMethod OpAssign [refT $ constT $ objT cls] $ refT $ objT cls    ],    mempty) -comparableContents :: Class -> ([Ctor], [Method], Reqs)+comparableContents :: Class -> ([ClassEntity], Reqs) comparableContents cls =-  ([],-   [ mkConstMethod OpLt [refT $ constT $ objT cls] boolT+  ([ mkConstMethod OpLt [refT $ constT $ objT cls] boolT    , mkConstMethod OpLe [refT $ constT $ objT cls] boolT    , mkConstMethod OpGt [refT $ constT $ objT cls] boolT    , mkConstMethod OpGe [refT $ constT $ objT cls] boolT    ],    mempty) -copyableContents :: Class -> ([Ctor], [Method], Reqs)+copyableContents :: Class -> ([ClassEntity], Reqs) copyableContents cls =   ([ mkCtor "newCopy" [objT cls]    ],-   [],    mempty) -equatableContents :: Class -> ([Ctor], [Method], Reqs)+equatableContents :: Class -> ([ClassEntity], Reqs) equatableContents cls =-  ([],-   [ mkConstMethod OpEq [objT cls] boolT+  ([ mkConstMethod OpEq [objT cls] boolT    , mkConstMethod OpNe [objT cls] boolT    ],    mempty)@@ -89,9 +86,8 @@ classAddFeatures :: [ClassFeature] -> Class -> Class classAddFeatures features cls =   foldr (\feature cls' ->-          let (ctors, methods, reqs) = featureContents feature cls'+          let (entities, reqs) = featureContents feature cls'           in addReqs reqs $-             classAddCtors ctors $-             classAddMethods methods cls')+             classAddEntities entities cls')         cls         features
+ src/Foreign/Hoppy/Generator/Spec/Conversion.hs view
@@ -0,0 +1,77 @@+-- This file is part of Hoppy.+--+-- Copyright 2015-2016 Bryan Gardiner <bog@khumba.net>+--+-- This program is free software: you can redistribute it and/or modify+-- it under the terms of the GNU Affero General Public License as published by+-- the Free Software Foundation, either version 3 of the License, or+-- (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU Affero General Public License for more details.+--+-- You should have received a copy of the GNU Affero General Public License+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.++{-# LANGUAGE CPP #-}++-- | The primary data types for specifying C++ interfaces.+--+-- 'Show' instances in this module produce strings of the form @\"\<TypeOfObject+-- nameOfObject otherInfo...\>\"@.  They can be used in error messages without+-- specifying a noun separately, i.e. write @show cls@ instead of @\"the class+-- \" ++ show cls@.+module Foreign.Hoppy.Generator.Spec.Conversion (+  -- * Advanced class conversions+  classSetConversionToHeap,+  classSetConversionToGc,+  ) where++#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (mconcat)+#endif+import Foreign.Hoppy.Generator.Language.Haskell+import Foreign.Hoppy.Generator.Spec.Base+import Foreign.Hoppy.Generator.Types++-- | Modifies a class's 'ClassConversion' structure by setting all languages+-- to use 'ClassConversionToHeap'.+classSetConversionToHeap :: Class -> Class+classSetConversionToHeap cls = case classFindCopyCtor cls of+  Just _ ->+    flip classModifyConversion cls $ \c ->+    c { classHaskellConversion = classHaskellConversionToHeap cls+      }+  Nothing -> error $ "classSetConversionToHeap: " ++ show cls ++ " must be copyable."++-- | Modifies a class's 'ClassConversion' structure by setting all languages+-- that support garbage collection to use 'ClassConversionToGc'.+classSetConversionToGc :: Class -> Class+classSetConversionToGc cls = case classFindCopyCtor cls of+  Just _ ->+    flip classModifyConversion cls $ \c ->+    c { classHaskellConversion = classHaskellConversionToGc cls+      }+  Nothing -> error $ "classSetConversionToGc: " ++ show cls ++ " must be copyable."++classHaskellConversionToHeap :: Class -> ClassHaskellConversion+classHaskellConversionToHeap cls =+  ClassHaskellConversion+  { classHaskellConversionType = Just $ cppTypeToHsTypeAndUse HsHsSide $ ptrT $ objT cls+  , classHaskellConversionToCppFn = Nothing+  , classHaskellConversionFromCppFn = Just $ do+      addImports hsImportForRuntime+      sayLn "HoppyFHR.copy"+  }++classHaskellConversionToGc :: Class -> ClassHaskellConversion+classHaskellConversionToGc cls =+  ClassHaskellConversion+  { classHaskellConversionType = Just $ cppTypeToHsTypeAndUse HsHsSide $ ptrT $ objT cls+  , classHaskellConversionToCppFn = Nothing+  , classHaskellConversionFromCppFn = Just $ do+      addImports $ mconcat [hsImport1 "Control.Monad" "(>=>)", hsImportForRuntime]+      sayLn "HoppyFHR.copy >=> HoppyFHR.toGc"+  }
src/Foreign/Hoppy/Generator/Types.hs view
@@ -58,7 +58,7 @@   constT,   ) where -import Foreign.Hoppy.Generator.Spec+import Foreign.Hoppy.Generator.Spec.Base  -- | C++ @void@, Haskell @()@. voidT = Internal_TVoid