packages feed

haskell-gi 0.23.1 → 0.24.0

raw patch · 23 files changed

+1455/−1324 lines, 23 filesdep ~attoparsecdep ~haskell-gi-basebuild-type:Customsetup-changedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: attoparsec, haskell-gi-base

API changes (from Hackage documentation)

- Data.GI.CodeGen.Conversions: TypeAllocInfo :: Bool -> Int -> TypeAllocInfo
- Data.GI.CodeGen.Conversions: [typeAllocInfoIsBoxed] :: TypeAllocInfo -> Bool
- Data.GI.CodeGen.Conversions: [typeAllocInfoSize] :: TypeAllocInfo -> Int
- Data.GI.CodeGen.LibGIRepository: instance Data.GI.Base.BasicTypes.BoxedObject Data.GI.CodeGen.LibGIRepository.BaseInfo
- Data.GI.CodeGen.SymbolNaming: noName :: Text -> CodeGen ()
+ Data.GI.CodeGen.API: [objRefFunc] :: Object -> Maybe Text
+ Data.GI.CodeGen.API: [objUnrefFunc] :: Object -> Maybe Text
+ Data.GI.CodeGen.Conversions: TypeAlloc :: Text -> Int -> TypeAllocInfo
+ Data.GI.CodeGen.Fixups: fixSymbolNaming :: (Name, API) -> (Name, API)
+ Data.GI.CodeGen.LibGIRepository: instance Data.GI.Base.BasicTypes.GBoxed Data.GI.CodeGen.LibGIRepository.BaseInfo
+ Data.GI.CodeGen.LibGIRepository: instance Data.GI.Base.BasicTypes.TypedObject Data.GI.CodeGen.LibGIRepository.BaseInfo
+ Data.GI.CodeGen.LibGIRepository: instance Data.GI.Base.Overloading.HasParentTypes Data.GI.CodeGen.LibGIRepository.BaseInfo
+ Data.GI.CodeGen.Struct: genBoxed :: Name -> Text -> CodeGen ()
+ Data.GI.CodeGen.SymbolNaming: normalizedAPIName :: API -> Name -> Name
+ Data.GI.CodeGen.Type: TGValue :: Type
+ Data.GI.GIR.BasicTypes: TGValue :: Type
+ Data.GI.GIR.Object: [objRefFunc] :: Object -> Maybe Text
+ Data.GI.GIR.Object: [objUnrefFunc] :: Object -> Maybe Text
- Data.GI.CodeGen.API: Object :: Maybe Name -> Text -> Text -> Maybe Text -> [Name] -> Maybe DeprecationInfo -> Documentation -> [Method] -> [Property] -> [Signal] -> Object
+ Data.GI.CodeGen.API: Object :: Maybe Name -> Text -> Text -> Maybe Text -> Maybe Text -> Maybe Text -> [Name] -> Maybe DeprecationInfo -> Documentation -> [Method] -> [Property] -> [Signal] -> Object
- Data.GI.CodeGen.Code: findAPI :: Type -> CodeGen (Maybe API)
+ Data.GI.CodeGen.Code: findAPI :: HasCallStack => Type -> CodeGen (Maybe API)
- Data.GI.CodeGen.Code: findAPIByName :: Name -> CodeGen API
+ Data.GI.CodeGen.Code: findAPIByName :: HasCallStack => Name -> CodeGen API
- Data.GI.CodeGen.Code: getAPI :: Type -> CodeGen API
+ Data.GI.CodeGen.Code: getAPI :: HasCallStack => Type -> CodeGen API
- Data.GI.CodeGen.SymbolNaming: qualifiedAPI :: Name -> CodeGen Text
+ Data.GI.CodeGen.SymbolNaming: qualifiedAPI :: API -> Name -> CodeGen Text
- Data.GI.GIR.Object: Object :: Maybe Name -> Text -> Text -> Maybe Text -> [Name] -> Maybe DeprecationInfo -> Documentation -> [Method] -> [Property] -> [Signal] -> Object
+ Data.GI.GIR.Object: Object :: Maybe Name -> Text -> Text -> Maybe Text -> Maybe Text -> Maybe Text -> [Name] -> Maybe DeprecationInfo -> Documentation -> [Method] -> [Property] -> [Signal] -> Object

Files

ChangeLog.md view
@@ -1,3 +1,7 @@+### 0.23.2+++ Fix a possible segfault in functions that return an out pointer to a dynamically allocated array, but do not initialize the array if it has zero size. See [#289](https://github.com/haskell-gi/haskell-gi/issues/289) for an example.+ ### 0.23.1  + Check whether symbols exist in the dynamic library before trying to generate bindings for them, in order to avoid linker errors.
DocTests.hs view
@@ -1,20 +1,17 @@-import Test.DocTest+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Build_doctests (flags, pkgs, module_sources)+import Test.DocTest (doctest) import System.Process  main :: IO () main = do-  gobjectIntrospectionLibs <- pkgConfigLibs "gobject-introspection-1.0"-  doctest $ [ "-XCPP", "-XOverloadedStrings", "-XRankNTypes", "-XLambdaCase"-            , "-ilib"-            -- For the autogenerated Data.GI.CodeGen.GType (hsc)-            , "-idist/build"-            , "dist/build/lib/c/enumStorage.o"-            ] ++ gobjectIntrospectionLibs ++-            -- The actual modules to test-            [ "Data.GI.CodeGen.GtkDoc"-            , "Data.GI.CodeGen.ModulePath"-            , "Data.GI.CodeGen.SymbolNaming"-            , "Data.GI.CodeGen.Haddock" ]+    gobjectIntrospectionLibs <- pkgConfigLibs "gobject-introspection-1.0"+--    traverse_ putStrLn args -- optionally print arguments+    doctest (gobjectIntrospectionLibs ++ args)+  where+    args = flags ++ pkgs ++ module_sources  pkgConfigLibs :: String -> IO [String] pkgConfigLibs pkg = words <$> readProcess "pkg-config" ["--libs", pkg] ""
Setup.hs view
@@ -1,3 +1,6 @@-#!/usr/bin/env runhaskell-import Distribution.Simple-main = defaultMain+module Main where++import Distribution.Extra.Doctest (defaultMainWithDoctests)++main :: IO ()+main = defaultMainWithDoctests "doctests"
haskell-gi.cabal view
@@ -1,5 +1,5 @@ name:                haskell-gi-version:             0.23.1+version:             0.24.0 synopsis:            Generate Haskell bindings for GObject Introspection capable libraries description:         Generate Haskell bindings for GObject Introspection capable libraries. This includes most notably                      Gtk+, but many other libraries in the GObject ecosystem provide introspection data too.@@ -13,12 +13,18 @@ maintainer:          Iñaki García Etxebarria (inaki@blueleaf.cc) stability:           Experimental category:            Development-build-type:          Simple-tested-with:         GHC == 8.0.1, GHC == 8.4.1, GHC == 8.6.1, GHC == 8.8.1, GHC == 8.10.1+build-type:          Custom+tested-with:         GHC == 8.8.1, GHC == 8.10.1 cabal-version:       2.0  extra-source-files: ChangeLog.md +custom-setup+ setup-depends:+   base >= 4 && <5,+   Cabal,+   cabal-doctest >= 1 && <1.1+ source-repository head   type: git   location: git://github.com/haskell-gi/haskell-gi.git@@ -27,7 +33,7 @@   default-language:    Haskell2010   pkgconfig-depends:   gobject-introspection-1.0 >= 1.32, gobject-2.0 >= 2.32   build-depends:       base >= 4.9 && < 5,-                       haskell-gi-base >= 0.23.0 && <0.24,+                       haskell-gi-base >= 0.24.0 && <0.25,                        Cabal >= 1.24,                        attoparsec >= 0.13,                        containers,@@ -51,8 +57,8 @@   ghc-options: -Wcompat    c-sources:           lib/c/enumStorage.c+  build-tool-depends:  hsc2hs:hsc2hs -  build-tools:         hsc2hs   hs-source-dirs:      lib   exposed-modules:     Data.GI.GIR.Alias,                        Data.GI.GIR.Allocation,@@ -118,10 +124,9 @@ test-suite doctests   type:          exitcode-stdio-1.0   default-language: Haskell2010-  ghc-options:   -threaded+  ghc-options:   -threaded -Wall   main-is:       DocTests.hs   build-depends: base                , process                , doctest >= 0.8                , haskell-gi-               , attoparsec
lib/Data/GI/CodeGen/Callable.hs view
@@ -311,15 +311,16 @@  -- | Callbacks are a fairly special case, we treat them separately. prepareInCallback :: Arg -> Callback -> ExposeClosures -> CodeGen Text-prepareInCallback arg (Callback {cbCallable = cb}) expose = do+prepareInCallback arg callback@(Callback {cbCallable = cb}) expose = do   let name = escapedArgName arg       ptrName = "ptr" <> name       scope = argScope arg    (maker, wrapper, drop) <-       case argType arg of-        TInterface tn@(Name _ n) ->+        TInterface tn ->             do+              let Name _ n = normalizedAPIName (APICallback callback) tn               drop <- if callableHasClosures cb && expose == WithoutClosures                       then Just <$> qualifiedSymbol (callbackDropClosures n) tn                       else return Nothing@@ -388,14 +389,11 @@   ft <- foreignType $ argType arg   allocInfo <- typeAllocInfo (argType arg)   case allocInfo of-    Just (TypeAllocInfo isBoxed n) -> do-         let allocator = if isBoxed-                         then "callocBoxedBytes"-                         else "callocBytes"+    Just (TypeAlloc allocator n) -> do          wrapMaybe arg >>= bool             (do               name'' <- genConversion (prime name') $-                        literal $ M $ allocator <> " " <> tshow n <>+                        literal $ M $ allocator <>                                     " :: " <> typeShow (io ft)               line $ "memcpy " <> name'' <> " " <> name' <> " " <> tshow n               return name'')@@ -418,17 +416,21 @@   then do     allocInfo <- typeAllocInfo (argType arg)     case allocInfo of-      Just (TypeAllocInfo isBoxed n) -> do-          let allocator = if isBoxed-                          then "callocBoxedBytes"-                          else "callocBytes"-          genConversion name $ literal $ M $ allocator <> " " <> tshow n <>+      Just (TypeAlloc allocator _) -> do+          genConversion name $ literal $ M $ allocator <>                             " :: " <> typeShow (io ft)       Nothing ->           notImplementedError $ ("Don't know how to allocate \""                                  <> argCName arg <> "\" of type "                                  <> tshow (argType arg))-  else genConversion name $ literal $ M $ "allocMem :: " <> typeShow (io $ ptr ft)+  else do+    -- Initialize pointers to NULL to avoid a crash in case the function+    -- does not initialize it.+    isPtr <- typeIsPtr (argType arg)+    let alloc = if isPtr+                then "callocMem"+                else "allocMem"+    genConversion name $ literal $ M $ alloc <> " :: " <> typeShow (io $ ptr ft)  -- Convert a non-zero terminated out array, stored in a variable -- named "aname", into the corresponding Haskell object.@@ -439,7 +441,7 @@   if fixed > -1   then do     unpacked <- convert aname $ unpackCArray (tshow fixed) t transfer-    -- Free the memory associated with the array+    -- Free the memory associated with the array.     freeContainerType transfer t aname undefined     return unpacked   else do@@ -453,7 +455,7 @@                                             lname     let lname'' = primeLength lname'     unpacked <- convert aname $ unpackCArray lname'' t transfer-    -- Free the memory associated with the array+    -- Free the memory associated with the array.     freeContainerType transfer t aname lname''     return unpacked @@ -538,21 +540,26 @@                   Nothing -> badIntroError $ "Cannot find closure name!! "                                            <> T.pack (ppShow callable) <> "\n"                                            <> T.pack (ppShow nameMap)-          case argScope cb of-            ScopeTypeInvalid -> badIntroError $ "Invalid scope! "+          -- Check that the given closure is an actual callback type.+          maybeAPI <- findAPI (argType cb)+          case maybeAPI of+            Just (APICallback _) -> do+              case argScope cb of+                ScopeTypeInvalid -> badIntroError $ "Invalid scope! "                                               <> T.pack (ppShow callable)-            ScopeTypeNotified -> do-                line $ "let " <> closureName <> " = castFunPtrToPtr " <> n'-                case argDestroy cb of-                  (-1) -> badIntroError $-                          "ScopeTypeNotified without destructor! "-                           <> T.pack (ppShow callable)-                  k -> let destroyName =-                            escapedArgName $ (args callable)!!k in-                       line $ "let " <> destroyName <> " = safeFreeFunPtrPtr"-            ScopeTypeAsync ->-                line $ "let " <> closureName <> " = nullPtr"-            ScopeTypeCall -> line $ "let " <> closureName <> " = nullPtr"+                ScopeTypeNotified -> do+                  line $ "let " <> closureName <> " = castFunPtrToPtr " <> n'+                  case argDestroy cb of+                    (-1) -> badIntroError $+                            "ScopeTypeNotified without destructor! "+                            <> T.pack (ppShow callable)+                    k -> let destroyName =+                               escapedArgName $ (args callable)!!k in+                           line $ "let " <> destroyName <> " = safeFreeFunPtrPtr"+                ScopeTypeAsync ->+                  line $ "let " <> closureName <> " = nullPtr"+                ScopeTypeCall -> line $ "let " <> closureName <> " = nullPtr"+            _ -> badIntroError $ "Closure \"" <> n <> "\" is not a callback."  freeCallCallbacks :: Callable -> Map.Map Text Text -> ExcCodeGen () freeCallCallbacks callable nameMap =
lib/Data/GI/CodeGen/Code.hs view
@@ -89,6 +89,8 @@ import qualified Data.Text.Lazy.Builder as B import qualified Data.Text.Lazy as LT +import GHC.Stack (HasCallStack)+ import System.Directory (createDirectoryIfMissing) import System.FilePath (joinPath, takeDirectory) @@ -537,19 +539,19 @@ resetTypeVariableScope =   modify' (\(cgs, s) -> (cgs {cgsNextAvailableTyvar = SingleCharTyvar 'a'}, s)) -findAPI :: Type -> CodeGen (Maybe API)-findAPI TError = Just <$> findAPIByName (Name "GLib" "Error")+-- | Try to find the API associated with a given type, if known.+findAPI :: HasCallStack => Type -> CodeGen (Maybe API) findAPI (TInterface n) = Just <$> findAPIByName n findAPI _ = return Nothing  -- | Find the API associated with a given type. If the API cannot be -- found this raises an `error`.-getAPI :: Type -> CodeGen API+getAPI :: HasCallStack => Type -> CodeGen API getAPI t = findAPI t >>= \case            Just a -> return a            Nothing -> terror ("Could not resolve type \"" <> tshow t <> "\".") -findAPIByName :: Name -> CodeGen API+findAPIByName :: HasCallStack => Name -> CodeGen API findAPIByName n@(Name ns _) = do     apis <- getAPIs     case M.lookup n apis of@@ -922,6 +924,7 @@                 , "import qualified Prelude as P"                 , ""                 , "import qualified Data.GI.Base.Attributes as GI.Attributes"+                , "import qualified Data.GI.Base.BasicTypes as B.Types"                 , "import qualified Data.GI.Base.ManagedPtr as B.ManagedPtr"                 , "import qualified Data.GI.Base.GClosure as B.GClosure"                 , "import qualified Data.GI.Base.GError as B.GError"
lib/Data/GI/CodeGen/CodeGen.hs view
@@ -21,7 +21,7 @@ import Data.GI.CodeGen.EnumFlags (genEnum, genFlags) import Data.GI.CodeGen.Fixups (dropMovedItems, guessPropertyNullability,                                detectGObject, dropDuplicatedFields,-                               checkClosureDestructors)+                               checkClosureDestructors, fixSymbolNaming) import Data.GI.CodeGen.GObject import Data.GI.CodeGen.Haddock (deprecatedPragma, addSectionDocumentation,                                 writeHaddock,@@ -36,16 +36,13 @@ import Data.GI.CodeGen.Signal (genSignal, genCallback) import Data.GI.CodeGen.Struct (genStructOrUnionFields, extractCallbacksInStruct,                   fixAPIStructs, ignoreStruct, genZeroStruct, genZeroUnion,-                  genWrappedPtr)-import Data.GI.CodeGen.SymbolNaming (upperName, classConstraint, noName,-                                     submoduleLocation, lowerName, qualifiedAPI)+                  genBoxed, genWrappedPtr)+import Data.GI.CodeGen.SymbolNaming (upperName, classConstraint,+                                     submoduleLocation, lowerName, qualifiedAPI,+                                     normalizedAPIName) import Data.GI.CodeGen.Type import Data.GI.CodeGen.Util (tshow) --- | Standard derived instances for newtypes wrapping @ManagedPtr@s.-newtypeDeriving :: CodeGen ()-newtypeDeriving = indent $ line $ "deriving (Eq)"- genFunction :: Name -> Function -> CodeGen () genFunction n (Function symbol fnMovedTo callable) =     -- Only generate the function if it has not been moved.@@ -62,67 +59,35 @@                           export (NamedSubsection MethodSection $ lowerName n) (lowerName n)                         ) --- | Generate the GValue instances for the given GObject.-genBoxedGValueInstance :: Name -> Text -> CodeGen ()-genBoxedGValueInstance n get_type_fn = do-  let name' = upperName n-      doc = "Convert '" <> name' <> "' to and from 'Data.GI.Base.GValue.GValue' with 'Data.GI.Base.GValue.toGValue' and 'Data.GI.Base.GValue.fromGValue'."--  writeHaddock DocBeforeSymbol doc-+-- | Create the newtype wrapping the ManagedPtr for the given type.+genNewtype :: Text -> CodeGen ()+genNewtype name' = do   group $ do-    bline $ "instance B.GValue.IsGValue " <> name' <> " where"-    indent $ group $ do-      line $ "toGValue o = do"-      indent $ group $ do-        line $ "gtype <- " <> get_type_fn-        line $ "B.ManagedPtr.withManagedPtr o (B.GValue.buildGValue gtype B.GValue.set_boxed)"-      line $ "fromGValue gv = do"-      indent $ group $ do-        line $ "ptr <- B.GValue.get_boxed gv :: IO (Ptr " <> name' <> ")"-        line $ "B.ManagedPtr.newBoxed " <> name' <> " ptr"--genBoxedObject :: Name -> Text -> CodeGen ()-genBoxedObject n typeInit = do-  let name' = upperName n-      get_type_fn = "c_" <> typeInit+    bline $ "newtype " <> name' <> " = " <> name' <> " (SP.ManagedPtr " <> name' <> ")"+    indent $ line $ "deriving (Eq)"    group $ do-    line $ "foreign import ccall \"" <> typeInit <> "\" " <>-            get_type_fn <> " :: "-    indent $ line "IO GType"-  group $ do-       line $ "instance BoxedObject " <> name' <> " where"-       indent $ line $ "boxedType _ = " <> get_type_fn--  genBoxedGValueInstance n get_type_fn--  hsBoot $ line $ "instance BoxedObject " <> name' <> " where"+    bline $ "instance SP.ManagedPtrNewtype " <> name' <> " where"+    indent $ line $ "toManagedPtr (" <> name' <> " p) = p"  -- | Generate wrapper for structures. genStruct :: Name -> Struct -> CodeGen () genStruct n s = unless (ignoreStruct n s) $ do-   let name' = upperName n+   let Name _ name' = normalizedAPIName (APIStruct s) n     writeHaddock DocBeforeSymbol ("Memory-managed wrapper type.")-   let decl = line $ "newtype " <> name' <> " = " <> name' <> " (ManagedPtr " <> name' <> ")"-   hsBoot decl-   decl-   newtypeDeriving+   genNewtype name'+   exportDecl (name' <> ("(..)"))     addSectionDocumentation ToplevelSection (structDocumentation s)     if structIsBoxed s-   then genBoxedObject n (fromJust $ structTypeInit s)+   then genBoxed n (fromJust $ structTypeInit s)    else genWrappedPtr n (structAllocationInfo s) (structSize s) -   exportDecl (name' <> ("(..)"))-    -- Generate a builder for a structure filled with zeroes.    genZeroStruct n s -   noName name'-    -- Generate code for fields.    genStructOrUnionFields n (structFields s) @@ -146,27 +111,21 @@ -- | Generated wrapper for unions. genUnion :: Name -> Union -> CodeGen () genUnion n u = do-  let name' = upperName n+  let Name _ name' = normalizedAPIName (APIUnion u) n    writeHaddock DocBeforeSymbol ("Memory-managed wrapper type.")-  let decl = line $ "newtype " <> name' <> " = " <> name' <> " (ManagedPtr " <> name' <> ")"-  hsBoot decl-  decl-  newtypeDeriving+  genNewtype name'+  exportDecl (name' <> "(..)")    addSectionDocumentation ToplevelSection (unionDocumentation u)    if unionIsBoxed u-  then genBoxedObject n (fromJust $ unionTypeInit u)+  then genBoxed n (fromJust $ unionTypeInit u)   else genWrappedPtr n (unionAllocationInfo u) (unionSize u) -  exportDecl (name' <> "(..)")-   -- Generate a builder for a structure filled with zeroes.   genZeroUnion n u -  noName name'-   -- Generate code for fields.   genStructOrUnionFields n (unionFields u) @@ -285,22 +244,26 @@         line $ "B.ManagedPtr.newObject " <> name' <> " ptr"  -- Type casting with type checking-genGObjectCasts :: Name -> Text -> [Name] -> CodeGen ()-genGObjectCasts n cn_ parents = do+genCasts :: Name -> Text -> [Name] -> CodeGen ()+genCasts n cn_ parents = do+  isGO <- isGObject (TInterface n)   let name' = upperName n       get_type_fn = "c_" <> cn_    group $ do     line $ "foreign import ccall \"" <> cn_ <> "\""-    indent $ line $ get_type_fn <> " :: IO GType"+    indent $ line $ get_type_fn <> " :: IO B.Types.GType"    group $ do-    bline $ "instance GObject " <> name' <> " where"-    indent $ group $ do-            line $ "gobjectType = " <> get_type_fn+    bline $ "instance B.Types.TypedObject " <> name' <> " where"+    indent $ do+      line $ "glibType = " <> get_type_fn -  genGObjectGValueInstance n get_type_fn+  when isGO $ group $ do+      bline $ "instance B.Types.GObject " <> name' +  when isGO $ genGObjectGValueInstance n get_type_fn+   className <- classConstraint n   group $ do     exportDecl className@@ -313,13 +276,16 @@     -- since we sometimes need to refer to @IsX@ itself, without     -- applying it. We instead use the trick of creating a class with     -- a universal instance.-    let constraints = "(GObject o, O.IsDescendantOf " <> name' <> " o)"+    let constraints = if isGO+                      then "(SP.GObject o, O.IsDescendantOf " <> name' <> " o)"+                      else "(SP.BoxedPtr o, SP.TypedObject o, O.IsDescendantOf " <> name' <> " o)"     bline $ "class " <> constraints <> " => " <> className <> " o"     bline $ "instance " <> constraints <> " => " <> className <> " o"      blank -    qualifiedParents <- mapM qualifiedAPI parents+    parentAPIs <- mapM (\n -> getAPI (TInterface n)) parents+    qualifiedParents <- mapM (uncurry qualifiedAPI) (zip parentAPIs parents)     bline $ "instance O.HasParentTypes " <> name'     line $ "type instance O.ParentTypes " <> name' <> " = '["       <> T.intercalate ", " qualifiedParents <> "]"@@ -346,72 +312,66 @@ -- of objects, we deal with these separately. genObject :: Name -> Object -> CodeGen () genObject n o = do-  let name' = upperName n+  let Name _ name' = normalizedAPIName (APIObject o) n   let t = TInterface n   isGO <- isGObject t -  if not isGO-  then line $ "-- APIObject \"" <> name' <>-                "\" does not descend from GObject, it will be ignored."-  else do-    writeHaddock DocBeforeSymbol ("Memory-managed wrapper type.")-    bline $ "newtype " <> name' <> " = " <> name' <> " (ManagedPtr " <> name' <> ")"-    newtypeDeriving-    exportDecl (name' <> "(..)")--    addSectionDocumentation ToplevelSection (objDocumentation o)+  writeHaddock DocBeforeSymbol ("Memory-managed wrapper type.")+  genNewtype name'+  exportDecl (name' <> "(..)") -    -- Type safe casting to parent objects, and implemented interfaces.-    parents <- instanceTree n-    genGObjectCasts n (objTypeInit o) (parents <> objInterfaces o)+  addSectionDocumentation ToplevelSection (objDocumentation o) -    noName name'+  -- Type safe casting to parent objects, and implemented interfaces.+  parents <- instanceTree n+  genCasts n (objTypeInit o) (parents <> objInterfaces o) -    cppIf CPPOverloading $-         fullObjectMethodList n o >>= genMethodList n+  cppIf CPPOverloading $+       fullObjectMethodList n o >>= genMethodList n -    forM_ (objSignals o) $ \s -> genSignal s n+  if isGO+    then do+      forM_ (objSignals o) $ \s -> genSignal s n -    genObjectProperties n o-    cppIf CPPOverloading $-         genNamespacedPropLabels n (objProperties o) (objMethods o)-    cppIf CPPOverloading $-         genObjectSignals n o+      genObjectProperties n o+      cppIf CPPOverloading $+        genNamespacedPropLabels n (objProperties o) (objMethods o)+      cppIf CPPOverloading $+        genObjectSignals n o+    else group $ do+      let allocInfo = AllocationInfo {+            allocCalloc = AllocationOpUnknown,+            allocCopy = case objRefFunc o of+                          Just ref -> AllocationOp ref+                          Nothing -> AllocationOpUnknown,+            allocFree = case objUnrefFunc o of+                          Just unref -> AllocationOp unref+                          Nothing -> AllocationOpUnknown+            }+      genWrappedPtr n allocInfo 0 -    -- Methods-    forM_ (objMethods o) $ \f -> do-      let mn = methodName f-      handleCGExc (\e -> do line ("-- XXX Could not generate method "-                                  <> name' <> "::" <> name mn)-                            printCGError e-                            cppIf CPPOverloading $-                              genUnsupportedMethodInfo n f)-                  (genMethod n f)+  -- Methods+  forM_ (objMethods o) $ \f -> do+    let mn = methodName f+    handleCGExc (\e -> do line ("-- XXX Could not generate method "+                                <> name' <> "::" <> name mn)+                          printCGError e+                          cppIf CPPOverloading $+                            genUnsupportedMethodInfo n f)+                (genMethod n f)  genInterface :: Name -> Interface -> CodeGen () genInterface n iface = do-  let name' = upperName n+  let Name _ name' = normalizedAPIName (APIInterface iface) n    line $ "-- interface " <> name' <> " "   writeHaddock DocBeforeSymbol ("Memory-managed wrapper type.")   deprecatedPragma name' $ ifDeprecated iface-  bline $ "newtype " <> name' <> " = " <> name' <> " (ManagedPtr " <> name' <> ")"-  newtypeDeriving+  genNewtype name'   exportDecl (name' <> "(..)")    addSectionDocumentation ToplevelSection (ifDocumentation iface) -  noName name'--  forM_ (ifSignals iface) $ \s -> handleCGExc-     (\e -> do line $ T.concat ["-- XXX Could not generate signal ", name', "::"-                               , sigName s]-               printCGError e)-     (genSignal s n)--  cppIf CPPOverloading $-     genInterfaceSignals n iface-   isGO <- apiIsGObject n (APIInterface iface)   if isGO   then do@@ -419,7 +379,7 @@     gobjectPrereqs <- filterM nameIsGObject (ifPrerequisites iface)     allParents <- forM gobjectPrereqs $ \p -> (p : ) <$> instanceTree p     let uniqueParents = nub (concat allParents)-    genGObjectCasts n cn_ uniqueParents+    genCasts n cn_ uniqueParents      genInterfaceProperties n iface     cppIf CPPOverloading $@@ -462,6 +422,16 @@                        cppIf CPPOverloading (genUnsupportedMethodInfo n f))              (genMethod n f) +  -- Signals+  forM_ (ifSignals iface) $ \s -> handleCGExc+     (\e -> do line $ T.concat ["-- XXX Could not generate signal ", name', "::"+                               , sigName s]+               printCGError e)+     (genSignal s n)++  cppIf CPPOverloading $+     genInterfaceSignals n iface+ -- Some type libraries include spurious interface/struct methods, -- where a method Mod.Foo::func also appears as an ordinary function -- in the list of APIs. If we find a matching function (without the@@ -496,33 +466,22 @@ genModule' :: M.Map Name API -> CodeGen () genModule' apis = do   mapM_ (uncurry genAPIModule)-            -- We provide these ourselves-          $ filter ((`notElem` [ Name "GLib" "Array"-                               , Name "GLib" "Error"-                               , Name "GLib" "HashTable"-                               , Name "GLib" "List"-                               , Name "GLib" "SList"-                               , Name "GLib" "Variant"-                               , Name "GObject" "Value"-                               , Name "GObject" "Closure"]) . fst)-          $ mapMaybe (traverse dropMovedItems)-            -- Some callback types are defined inside structs-          $ map fixAPIStructs-            -- Try to guess nullability of properties when there is no-            -- nullability info in the GIR.-          $ map guessPropertyNullability-            -- Not every interface providing signals or properties is-            -- correctly annotated as descending from GObject, fix this.-          $ map detectGObject-            -- Some APIs contain duplicated fields by mistake, drop-            -- the duplicates.-          $ map dropDuplicatedFields-            -- Make sure that every argument marked as being a-            -- destructor for a user_data argument has an associated-            -- user_data argument.-          $ map checkClosureDestructors-          $ M.toList-          $ apis+    -- We provide these ourselves+    $ filter ((`notElem` [ Name "GLib" "Array"+                         , Name "GLib" "Error"+                         , Name "GLib" "HashTable"+                         , Name "GLib" "List"+                         , Name "GLib" "SList"+                         , Name "GLib" "Variant"+                         , Name "GObject" "Value"+                         , Name "GObject" "Closure"]) . fst)+    -- Some callback types are defined inside structs+    $ map fixAPIStructs+    -- Some APIs contain duplicated fields by mistake, drop+    -- the duplicates.+    $ map dropDuplicatedFields+    $ mapMaybe (traverse dropMovedItems)+    $ M.toList apis    -- Make sure we generate a "Callbacks" module, since it is imported   -- by other modules. It is fine if it ends up empty.@@ -537,9 +496,29 @@    -- Some API symbols are embedded into structures, extract these and   -- inject them into the set of APIs loaded and being generated.-  let embeddedAPIs = (M.fromList+  let embeddedAPIs = (fixAPIs . M.fromList                      . concatMap extractCallbacksInStruct                      . M.toList) apis   allAPIs <- getAPIs-  recurseWithAPIs (M.union allAPIs embeddedAPIs)-       (genModule' (M.union apis embeddedAPIs))+  let contextAPIs = M.union (fixAPIs allAPIs) embeddedAPIs+      targetAPIs = M.union (fixAPIs apis) embeddedAPIs++  recurseWithAPIs contextAPIs (genModule' targetAPIs)++  where+    fixAPIs :: M.Map Name API -> M.Map Name API+    fixAPIs apis = M.fromList+      -- Try to guess nullability of properties when there is no+      -- nullability info in the GIR.+      $ map guessPropertyNullability+      -- Not every interface providing signals or properties is+      -- correctly annotated as descending from GObject, fix this.+      $ map detectGObject+      -- Make sure that every argument marked as being a+      -- destructor for a user_data argument has an associated+      -- user_data argument.+      $ map checkClosureDestructors+      -- Make sure that the symbols to be generated are valid+      -- Haskell identifiers, when necessary.+      $ map fixSymbolNaming+      $ M.toList apis
− lib/Data/GI/CodeGen/Conversions.hs
@@ -1,1059 +0,0 @@-{-# LANGUAGE PatternGuards, DeriveFunctor #-}--module Data.GI.CodeGen.Conversions-    ( convert-    , genConversion-    , unpackCArray-    , computeArrayLength--    , callableHasClosures--    , hToF-    , fToH-    , transientToH-    , haskellType-    , isoHaskellType-    , foreignType--    , argumentType-    , ExposeClosures(..)-    , elementType-    , elementMap-    , elementTypeAndMap--    , isManaged-    , typeIsNullable-    , typeIsPtr-    , typeIsCallback-    , maybeNullConvert-    , nullPtrForType--    , typeAllocInfo-    , TypeAllocInfo(..)--    , apply-    , mapC-    , literal-    , Constructor(..)-    ) where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>), (<*>), pure, Applicative)-#endif-import Control.Monad (when)-import Data.Maybe (isJust)-#if !MIN_VERSION_base(4,11,0)-import Data.Monoid ((<>))-#endif-import Data.Text (Text)-import qualified Data.Text as T-import GHC.Exts (IsString(..))--import Foreign.C.Types (CInt, CUInt)-import Foreign.Storable (sizeOf)--import Data.GI.CodeGen.API-import Data.GI.CodeGen.Code-import Data.GI.CodeGen.GObject-import Data.GI.CodeGen.SymbolNaming-import Data.GI.CodeGen.Type-import Data.GI.CodeGen.Util---- | The free monad.-data Free f r = Free (f (Free f r)) | Pure r--instance Functor f => Functor (Free f) where-  fmap f = go where-    go (Pure a)  = Pure (f a)-    go (Free fa) = Free (go <$> fa)--instance (Functor f) => Applicative (Free f) where-    pure = Pure-    Pure a <*> Pure b = Pure $ a b-    Pure a <*> Free mb = Free $ fmap a <$> mb-    Free ma <*> b = Free $ (<*> b) <$> ma--instance (Functor f) => Monad (Free f) where-    return = Pure-    (Free x) >>= f = Free (fmap (>>= f) x)-    (Pure r) >>= f = f r---- | Lift some command to the Free monad.-liftF :: (Functor f) => f r -> Free f r-liftF command = Free (fmap Pure command)---- String identifying a constructor in the generated code, which is--- either (by default) a pure function (indicated by the P--- constructor) or a function returning values on a monad (M--- constructor). 'Id' denotes the identity function.-data Constructor = P Text | M Text | Id-                   deriving (Eq,Show)-instance IsString Constructor where-    fromString = P . T.pack--data FExpr next = Apply Constructor next-                | LambdaConvert Text next-                | MapC Map Constructor next-                | Literal Constructor next-                  deriving (Show, Functor)--type Converter = Free FExpr ()---- Different available maps.-data Map = Map | MapFirst | MapSecond-         deriving (Show)---- Naming for the maps.-mapName :: Map -> Text-mapName Map = "map"-mapName MapFirst = "mapFirst"-mapName MapSecond = "mapSecond"---- Naming for the monadic versions of the maps that we use-monadicMapName :: Map -> Text-monadicMapName Map = "mapM"-monadicMapName MapFirst = "mapFirstA"-monadicMapName MapSecond = "mapSecondA"--apply :: Constructor -> Converter-apply f = liftF $ Apply f ()--mapC :: Constructor -> Converter-mapC f = liftF $ MapC Map f ()--mapFirst :: Constructor -> Converter-mapFirst f = liftF $ MapC MapFirst f ()--mapSecond :: Constructor -> Converter-mapSecond f = liftF $ MapC MapSecond f ()--literal :: Constructor -> Converter-literal f = liftF $ Literal f ()--lambdaConvert :: Text -> Converter-lambdaConvert c = liftF $ LambdaConvert c ()--genConversion :: Text -> Converter -> CodeGen Text-genConversion l (Pure ()) = return l-genConversion l (Free k) = do-  let l' = prime l-  case k of-    Apply (P f) next ->-        do line $ "let " <> l' <> " = " <> f <> " " <> l-           genConversion l' next-    Apply (M f) next ->-        do line $ l' <> " <- " <> f <> " " <> l-           genConversion l' next-    Apply Id next -> genConversion l next--    MapC m (P f) next ->-        do line $ "let " <> l' <> " = " <> mapName m <> " " <> f <> " " <> l-           genConversion l' next-    MapC m (M f) next ->-        do line $ l' <> " <- " <> monadicMapName m <> " " <> f <> " " <> l-           genConversion l' next-    MapC _ Id next -> genConversion l next--    LambdaConvert conv next ->-        do line $ conv <> " " <> l <> " $ \\" <> l' <> " -> do"-           increaseIndent-           genConversion l' next--    Literal (P f) next ->-        do line $ "let " <> l <> " = " <> f-           genConversion l next-    Literal (M f) next ->-        do line $ l <> " <- " <> f-           genConversion l next-    Literal Id next -> genConversion l next---- | Given an array, together with its type, return the code for reading--- its length.-computeArrayLength :: Text -> Type -> ExcCodeGen Text-computeArrayLength array (TCArray _ _ _ t) = do-  reader <- findReader-  return $ "fromIntegral $ " <> reader <> " " <> array-    where findReader = case t of-                     TBasicType TUInt8 -> return "B.length"-                     TBasicType _      -> return "length"-                     TInterface _      -> return "length"-                     TCArray{}         -> return "length"-                     _ -> notImplementedError $-                          "Don't know how to compute length of " <> tshow t-computeArrayLength _ t =-    notImplementedError $ "computeArrayLength called on non-CArray type "-                            <> tshow t--convert :: Text -> BaseCodeGen e Converter -> BaseCodeGen e Text-convert l c = do-  c' <- c-  genConversion l c'--hObjectToF :: Type -> Transfer -> ExcCodeGen Constructor-hObjectToF t transfer =-  if transfer == TransferEverything-  then do-    isGO <- isGObject t-    if isGO-    then return $ M "B.ManagedPtr.disownObject"-    else badIntroError "Transferring a non-GObject object"-  -- castPtr since we accept any instance of the class associated with-  -- the GObject, not just the precise type of the GObject, while the-  -- foreign function declaration requires a pointer of the precise-  -- type.-  else return $ M "unsafeManagedPtrCastPtr"--hVariantToF :: Transfer -> CodeGen Constructor-hVariantToF transfer =-  if transfer == TransferEverything-  then return $ M "B.GVariant.disownGVariant"-  else return $ M "unsafeManagedPtrGetPtr"--hParamSpecToF :: Transfer -> CodeGen Constructor-hParamSpecToF transfer =-  if transfer == TransferEverything-  then return $ M "B.GParamSpec.disownGParamSpec"-  else return $ M "unsafeManagedPtrGetPtr"--hClosureToF :: Transfer -> Maybe Type -> CodeGen Constructor--- Untyped closures-hClosureToF transfer Nothing =-  if transfer == TransferEverything-  then return $ M "B.GClosure.disownGClosure"-  -- We cast the point here because the foreign type for untyped-  -- closures is always represented as Ptr (GClosure ()), while the-  -- corresponding Haskell type is the parametric "GClosure a".-  else return $ M "unsafeManagedPtrCastPtr"--- Typed closures-hClosureToF transfer (Just _) =-  if transfer == TransferEverything-  then return $ M "B.GClosure.disownGClosure"-  else return $ M "unsafeManagedPtrGetPtr"--hBoxedToF :: Transfer -> CodeGen Constructor-hBoxedToF transfer =-  if transfer == TransferEverything-  then return $ M "B.ManagedPtr.disownBoxed"-  else return $ M "unsafeManagedPtrGetPtr"--hStructToF :: Struct -> Transfer -> ExcCodeGen Constructor-hStructToF s transfer =-    if transfer /= TransferEverything || structIsBoxed s then-        hBoxedToF transfer-    else do-        when (structSize s == 0) $-             badIntroError "Transferring a non-boxed struct with unknown size!"-        return $ M "unsafeManagedPtrGetPtr"--hUnionToF :: Union -> Transfer -> ExcCodeGen Constructor-hUnionToF u transfer =-    if transfer /= TransferEverything || unionIsBoxed u then-        hBoxedToF transfer-    else do-        when (unionSize u == 0) $-             badIntroError "Transferring a non-boxed union with unknown size!"-        return $ M "unsafeManagedPtrGetPtr"---- Given the Haskell and Foreign types, returns the name of the--- function marshalling between both.-hToF' :: Type -> Maybe API -> TypeRep -> TypeRep -> Transfer-            -> ExcCodeGen Constructor-hToF' t a hType fType transfer-    | ( hType == fType ) = return Id-    | TError <- t = hBoxedToF transfer-    | TVariant <- t = hVariantToF transfer-    | TParamSpec <- t = hParamSpecToF transfer-    | TGClosure c <- t = hClosureToF transfer c-    | Just (APIEnum _) <- a = return "(fromIntegral . fromEnum)"-    | Just (APIFlags _) <- a = return "gflagsToWord"-    | Just (APIObject _) <- a = hObjectToF t transfer-    | Just (APIInterface _) <- a = hObjectToF t transfer-    | Just (APIStruct s) <- a = hStructToF s transfer-    | Just (APIUnion u) <- a = hUnionToF u transfer-    -- Converting callback types requires more context, we leave that-    -- as a special case to be implemented by the caller.-    | Just (APICallback _) <- a = error "Cannot handle callback type here!! "-    | TByteArray <- t = return $ M "packGByteArray"-    | TCArray True _ _ (TBasicType TUTF8) <- t =-        return $ M "packZeroTerminatedUTF8CArray"-    | TCArray True _ _ (TBasicType TFileName) <- t =-        return $ M "packZeroTerminatedFileNameArray"-    | TCArray True _ _ (TBasicType TPtr) <- t =-        return $ M "packZeroTerminatedPtrArray"-    | TCArray True _ _ (TBasicType TUInt8) <- t =-        return $ M "packZeroTerminatedByteString"-    | TCArray True _ _ (TBasicType TBoolean) <- t =-        return $ M "(packMapZeroTerminatedStorableArray (fromIntegral . fromEnum))"-    | TCArray True _ _ (TBasicType TGType) <- t =-        return $ M "(packMapZeroTerminatedStorableArray gtypeToCGtype)"-    | TCArray True _ _ (TBasicType _) <- t =-        return $ M "packZeroTerminatedStorableArray"-    | TCArray False _ _ (TBasicType TUTF8) <- t =-        return $ M "packUTF8CArray"-    | TCArray False _ _ (TBasicType TFileName) <- t =-        return $ M "packFileNameArray"-    | TCArray False _ _ (TBasicType TPtr) <- t =-        return $ M "packPtrArray"-    | TCArray False _ _ (TBasicType TUInt8) <- t =-        return $ M "packByteString"-    | TCArray False _ _ (TBasicType TBoolean) <- t =-        return $ M "(packMapStorableArray (fromIntegral . fromEnum))"-    | TCArray False _ _ (TBasicType TGType) <- t =-        return $ M "(packMapStorableArray gtypeToCGType)"-    | TCArray False _ _ (TBasicType TFloat) <- t =-        return $ M "(packMapStorableArray realToFrac)"-    | TCArray False _ _ (TBasicType TDouble) <- t =-        return $ M "(packMapStorableArray realToFrac)"-    | TCArray False _ _ (TBasicType _) <- t =-        return $ M "packStorableArray"-    | TCArray{}  <- t = notImplementedError $-                   "Don't know how to pack C array of type " <> tshow t-    | otherwise = case (typeShow hType, typeShow fType) of-               ("T.Text", "CString") -> return $ M "textToCString"-               ("[Char]", "CString") -> return $ M "stringToCString"-               ("Char", "CInt")      -> return "(fromIntegral . ord)"-               ("Bool", "CInt")      -> return "(fromIntegral . fromEnum)"-               ("Float", "CFloat")   -> return "realToFrac"-               ("Double", "CDouble") -> return "realToFrac"-               ("GType", "CGType")   -> return "gtypeToCGType"-               _                     -> notImplementedError $-                                        "Don't know how to convert "-                                        <> typeShow hType <> " into "-                                        <> typeShow fType <> ".\n"-                                        <> "Internal type: "-                                        <> tshow t--getForeignConstructor :: Type -> Transfer -> ExcCodeGen Constructor-getForeignConstructor t transfer = do-  a <- findAPI t-  hType <- haskellType t-  fType <- foreignType t-  hToF' t a hType fType transfer--hToF_PackedType :: Type -> Text -> Transfer -> ExcCodeGen Converter-hToF_PackedType t packer transfer = do-  innerConstructor <- getForeignConstructor t transfer-  return $ do-    mapC innerConstructor-    apply (M packer)---- | Try to find the `hash` and `equal` functions appropriate for the--- given type, when used as a key in a GHashTable.-hashTableKeyMappings :: Type -> ExcCodeGen (Text, Text)-hashTableKeyMappings (TBasicType TPtr) = return ("gDirectHash", "gDirectEqual")-hashTableKeyMappings (TBasicType TUTF8) = return ("gStrHash", "gStrEqual")-hashTableKeyMappings t =-    notImplementedError $ "GHashTable key of type " <> tshow t <> " unsupported."---- | `GHashTable` tries to fit every type into a pointer, the--- following function tries to find the appropriate--- (destroy,packer,unpacker) for the given type.-hashTablePtrPackers :: Type -> ExcCodeGen (Text, Text, Text)-hashTablePtrPackers (TBasicType TPtr) =-    return ("Nothing", "ptrPackPtr", "ptrUnpackPtr")-hashTablePtrPackers (TBasicType TUTF8) =-    return ("(Just ptr_to_g_free)", "cstringPackPtr", "cstringUnpackPtr")-hashTablePtrPackers t =-    notImplementedError $ "GHashTable element of type " <> tshow t <> " unsupported."--hToF_PackGHashTable :: Type -> Type -> ExcCodeGen Converter-hToF_PackGHashTable keys elems = do-  -- We will be adding elements to the Hash list with appropriate-  -- destructors, so we always want a fresh copy.-  keysConstructor <- getForeignConstructor keys TransferEverything-  elemsConstructor <- getForeignConstructor elems TransferEverything-  (keyHash, keyEqual) <- hashTableKeyMappings keys-  (keyDestroy, keyPack, _) <- hashTablePtrPackers keys-  (elemDestroy, elemPack, _) <- hashTablePtrPackers elems-  return $ do-    apply (P "Map.toList")-    mapFirst keysConstructor-    mapSecond elemsConstructor-    mapFirst (P keyPack)-    mapSecond (P elemPack)-    apply (M (T.intercalate " " ["packGHashTable", keyHash, keyEqual,-                                 keyDestroy, elemDestroy]))--hToF :: Type -> Transfer -> ExcCodeGen Converter-hToF (TGList t) transfer = do-  isPtr <- typeIsPtr t-  when (not isPtr) $-       badIntroError ("'" <> tshow t <>-                      "' is not a pointer type, cannot pack into a GList.")-  hToF_PackedType t "packGList" transfer-hToF (TGSList t) transfer = do-  isPtr <- typeIsPtr t-  when (not isPtr) $-       badIntroError ("'" <> tshow t <>-                      "' is not a pointer type, cannot pack into a GSList.")-  hToF_PackedType t "packGSList" transfer-hToF (TGArray t) transfer = hToF_PackedType t "packGArray" transfer-hToF (TPtrArray t) transfer = hToF_PackedType t "packGPtrArray" transfer-hToF (TGHash ta tb) _ = hToF_PackGHashTable ta tb-hToF (TCArray zt _ _ t@(TCArray{})) transfer = do-  let packer = if zt-               then "packZeroTerminated"-               else "pack"-  hToF_PackedType t (packer <> "PtrArray") transfer--hToF (TCArray zt _ _ t@(TInterface _)) transfer = do-  isScalar <- typeIsEnumOrFlag t-  let packer = if zt-               then "packZeroTerminated"-               else "pack"-  if isScalar-  then hToF_PackedType t (packer <> "StorableArray") transfer-  else do-    api <- findAPI t-    let size = case api of-                 Just (APIStruct s) -> structSize s-                 Just (APIUnion u) -> unionSize u-                 _ -> 0-    if size == 0 || zt-    then hToF_PackedType t (packer <> "PtrArray") transfer-    else hToF_PackedType t (packer <> "BlockArray " <> tshow size) transfer--hToF t transfer = do-  a <- findAPI t-  hType <- haskellType t-  fType <- foreignType t-  constructor <- hToF' t a hType fType transfer-  return $ apply constructor--boxedForeignPtr :: Text -> Transfer -> CodeGen Constructor-boxedForeignPtr constructor transfer = return $-   case transfer of-     TransferEverything -> M $ parenthesize $ "wrapBoxed " <> constructor-     _ -> M $ parenthesize $ "newBoxed " <> constructor--suForeignPtr :: Bool -> TypeRep -> Transfer -> CodeGen Constructor-suForeignPtr isBoxed hType transfer = do-  let constructor = typeConName hType-  if isBoxed then-      boxedForeignPtr constructor transfer-  else return $ M $ parenthesize $-       case transfer of-         TransferEverything -> "wrapPtr " <> constructor-         _ -> "newPtr " <> constructor--structForeignPtr :: Struct -> TypeRep -> Transfer -> CodeGen Constructor-structForeignPtr s =-    suForeignPtr (structIsBoxed s)--unionForeignPtr :: Union -> TypeRep -> Transfer -> CodeGen Constructor-unionForeignPtr u =-    suForeignPtr (unionIsBoxed u)--fObjectToH :: Type -> TypeRep -> Transfer -> ExcCodeGen Constructor-fObjectToH t hType transfer = do-  let constructor = typeConName hType-  isGO <- isGObject t-  return $ M $ parenthesize $-    case transfer of-    TransferEverything ->-        if isGO-        then "wrapObject " <> constructor-        else "wrapPtr " <> constructor-    _ ->-        if isGO-        then "newObject " <> constructor-        else "newPtr " <> constructor--fCallbackToH :: TypeRep -> Transfer -> ExcCodeGen Constructor-fCallbackToH hType TransferNothing = do-  let constructor = typeConName hType-  return (P (callbackDynamicWrapper constructor))-fCallbackToH _ transfer =-  notImplementedError ("ForeignCallback with unsupported transfer type `"-                       <> tshow transfer <> "'")--fVariantToH :: Transfer -> CodeGen Constructor-fVariantToH transfer =-  return $ M $ case transfer of-                  TransferEverything -> "B.GVariant.wrapGVariantPtr"-                  _ -> "B.GVariant.newGVariantFromPtr"--fParamSpecToH :: Transfer -> CodeGen Constructor-fParamSpecToH transfer =-  return $ M $ case transfer of-                  TransferEverything -> "B.GParamSpec.wrapGParamSpecPtr"-                  _ -> "B.GParamSpec.newGParamSpecFromPtr"--fClosureToH :: Transfer -> Maybe Type -> CodeGen Constructor--- Untyped closures-fClosureToH transfer Nothing =-  return $ M $ case transfer of-                  TransferEverything ->-                    parenthesize $ "B.GClosure.wrapGClosurePtr . FP.castPtr"-                  _ -> parenthesize $ "B.GClosure.newGClosureFromPtr . FP.castPtr"--- Typed closures-fClosureToH transfer (Just _) =-  return $ M $ case transfer of-                  TransferEverything -> "B.GClosure.wrapGClosurePtr"-                  _ -> "B.GClosure.newGClosureFromPtr"--fToH' :: Type -> Maybe API -> TypeRep -> TypeRep -> Transfer-         -> ExcCodeGen Constructor-fToH' t a hType fType transfer-    | ( hType == fType ) = return Id-    | Just (APIEnum _) <- a = return "(toEnum . fromIntegral)"-    | Just (APIFlags _) <- a = return "wordToGFlags"-    | TError <- t = boxedForeignPtr "GError" transfer-    | TVariant <- t = fVariantToH transfer-    | TParamSpec <- t = fParamSpecToH transfer-    | TGClosure c <- t = fClosureToH transfer c-    | Just (APIStruct s) <- a = structForeignPtr s hType transfer-    | Just (APIUnion u) <- a = unionForeignPtr u hType transfer-    | Just (APIObject _) <- a = fObjectToH t hType transfer-    | Just (APIInterface _) <- a = fObjectToH t hType transfer-    | Just (APICallback _) <- a = fCallbackToH hType transfer-    | TCArray True _ _ (TBasicType TUTF8) <- t =-        return $ M "unpackZeroTerminatedUTF8CArray"-    | TCArray True _ _ (TBasicType TFileName) <- t =-        return $ M "unpackZeroTerminatedFileNameArray"-    | TCArray True _ _ (TBasicType TUInt8) <- t =-        return $ M "unpackZeroTerminatedByteString"-    | TCArray True _ _ (TBasicType TPtr) <- t =-        return $ M "unpackZeroTerminatedPtrArray"-    | TCArray True _ _ (TBasicType TBoolean) <- t =-        return $ M "(unpackMapZeroTerminatedStorableArray (/= 0))"-    | TCArray True _ _ (TBasicType TGType) <- t =-        return $ M "(unpackMapZeroTerminatedStorableArray GType)"-    | TCArray True _ _ (TBasicType TFloat) <- t =-        return $ M "(unpackMapZeroTerminatedStorableArray realToFrac)"-    | TCArray True _ _ (TBasicType TDouble) <- t =-        return $ M "(unpackMapZeroTerminatedStorableArray realToFrac)"-    | TCArray True _ _ (TBasicType _) <- t =-        return $ M "unpackZeroTerminatedStorableArray"-    | TCArray{}  <- t = notImplementedError $-                   "Don't know how to unpack C array of type " <> tshow t-    | TByteArray <- t = return $ M "unpackGByteArray"-    | TGHash _ _ <- t = notImplementedError "Foreign Hashes not supported yet"-    | otherwise = case (typeShow fType, typeShow hType) of-               ("CString", "T.Text") -> return $ M "cstringToText"-               ("CString", "[Char]") -> return $ M "cstringToString"-               ("CInt", "Char")      -> return "(chr . fromIntegral)"-               ("CInt", "Bool")      -> return "(/= 0)"-               ("CFloat", "Float")   -> return "realToFrac"-               ("CDouble", "Double") -> return "realToFrac"-               ("CGType", "GType")   -> return "GType"-               _                     ->-                   notImplementedError $ "Don't know how to convert "-                                           <> typeShow fType <> " into "-                                           <> typeShow hType <> ".\n"-                                           <> "Internal type: "-                                           <> tshow t--getHaskellConstructor :: Type -> Transfer -> ExcCodeGen Constructor-getHaskellConstructor t transfer = do-  a <- findAPI t-  hType <- haskellType t-  fType <- foreignType t-  fToH' t a hType fType transfer--fToH_PackedType :: Type -> Text -> Transfer -> ExcCodeGen Converter-fToH_PackedType t unpacker transfer = do-  innerConstructor <- getHaskellConstructor t transfer-  return $ do-    apply (M unpacker)-    mapC innerConstructor--fToH_UnpackGHashTable :: Type -> Type -> Transfer -> ExcCodeGen Converter-fToH_UnpackGHashTable keys elems transfer = do-  keysConstructor <- getHaskellConstructor keys transfer-  (_,_,keysUnpack) <- hashTablePtrPackers keys-  elemsConstructor <- getHaskellConstructor elems transfer-  (_,_,elemsUnpack) <- hashTablePtrPackers elems-  return $ do-    apply (M "unpackGHashTable")-    mapFirst (P keysUnpack)-    mapFirst keysConstructor-    mapSecond (P elemsUnpack)-    mapSecond elemsConstructor-    apply (P "Map.fromList")--fToH :: Type -> Transfer -> ExcCodeGen Converter-fToH (TGList t) transfer = do-  isPtr <- typeIsPtr t-  when (not isPtr) $-       badIntroError ("`" <> tshow t <>-                      "' is not a pointer type, cannot unpack from a GList.")-  fToH_PackedType t "unpackGList" transfer-fToH (TGSList t) transfer = do-  isPtr <- typeIsPtr t-  when (not isPtr) $-       badIntroError ("`" <> tshow t <>-                      "' is not a pointer type, cannot unpack from a GSList.")-  fToH_PackedType t "unpackGSList" transfer-fToH (TGArray t) transfer = fToH_PackedType t "unpackGArray" transfer-fToH (TPtrArray t) transfer = fToH_PackedType t "unpackGPtrArray" transfer-fToH (TGHash a b) transfer = fToH_UnpackGHashTable a b transfer--- We cannot unpack arrays without any kind of length info.-fToH t@(TCArray False (-1) (-1) _) _ =-  badIntroError ("`" <> tshow t <>-                  "' is an array type, but contains no length information.")-fToH (TCArray True _ _ t@(TCArray{})) transfer =-  fToH_PackedType t "unpackZeroTerminatedPtrArray" transfer-fToH (TCArray True _ _ t@(TInterface _)) transfer = do-  isScalar <- typeIsEnumOrFlag t-  if isScalar-  then fToH_PackedType t "unpackZeroTerminatedStorableArray" transfer-  else fToH_PackedType t "unpackZeroTerminatedPtrArray" transfer--fToH t transfer = do-  a <- findAPI t-  hType <- haskellType t-  fType <- foreignType t-  constructor <- fToH' t a hType fType transfer-  return $ apply constructor---- | Somewhat like `fToH`, but with slightly different borrowing--- semantics: in the case of `TransferNothing` we wrap incoming--- pointers to boxed structs into transient `ManagedPtr`s (every other--- case behaves as `fToH`). These are `ManagedPtr`s for which we do--- not make a copy, and which will be disowned when the function--- exists, instead of making a copy that the GC will collect--- eventually.------ This is necessary in order to get the semantics of callbacks and--- signals right: in some cases making a copy of the object does not--- simply increase the refcount, but rather makes a full copy. In this--- cases modification of the original object is not possible, but this--- is sometimes useful, see for example------ https://github.com/haskell-gi/haskell-gi/issues/97------ Another situation where making a copy of incoming arguments is--- problematic is when the underlying library is not thread-safe. When--- running under the threaded GHC runtime it can happen that the GC--- runs on a different OS thread than the thread where the object was--- created, and this leads to rather mysterious bugs, see for example------ https://github.com/haskell-gi/haskell-gi/issues/96------ This case is particularly nasty, since it affects `onWidgetDraw`,--- which is very common.-transientToH :: Type -> Transfer -> ExcCodeGen Converter-transientToH t@(TInterface _) TransferNothing = do-  a <- findAPI t-  case a of-    Just (APIStruct s) -> if structIsBoxed s-                          then wrapTransient t-                          else fToH t TransferNothing-    Just (APIUnion u) -> if unionIsBoxed u-                         then wrapTransient t-                         else fToH t TransferNothing-    _ -> fToH t TransferNothing-transientToH t transfer = fToH t transfer---- | Wrap the given transient.-wrapTransient :: Type -> CodeGen Converter-wrapTransient t = do-  hCon <- typeConName <$> haskellType t-  return $ lambdaConvert $ "B.ManagedPtr.withTransient " <> hCon--unpackCArray :: Text -> Type -> Transfer -> ExcCodeGen Converter-unpackCArray length (TCArray False _ _ t) transfer =-  case t of-    TBasicType TUTF8 -> return $ apply $ M $ parenthesize $-                        "unpackUTF8CArrayWithLength " <> length-    TBasicType TFileName -> return $ apply $ M $ parenthesize $-                            "unpackFileNameArrayWithLength " <> length-    TBasicType TUInt8 -> return $ apply $ M $ parenthesize $-                         "unpackByteStringWithLength " <> length-    TBasicType TPtr -> return $ apply $ M $ parenthesize $-                         "unpackPtrArrayWithLength " <> length-    TBasicType TBoolean -> return $ apply $ M $ parenthesize $-                         "unpackMapStorableArrayWithLength (/= 0) " <> length-    TBasicType TGType -> return $ apply $ M $ parenthesize $-                         "unpackMapStorableArrayWithLength GType " <> length-    TBasicType TFloat -> return $ apply $ M $ parenthesize $-                         "unpackMapStorableArrayWithLength realToFrac " <> length-    TBasicType TDouble -> return $ apply $ M $ parenthesize $-                         "unpackMapStorableArrayWithLength realToFrac " <> length-    TBasicType _ -> return $ apply $ M $ parenthesize $-                         "unpackStorableArrayWithLength " <> length-    TInterface _ -> do-           a <- findAPI t-           isScalar <- typeIsEnumOrFlag t-           hType <- haskellType t-           fType <- foreignType t-           innerConstructor <- fToH' t a hType fType transfer-           let (boxed, size) = case a of-                        Just (APIStruct s) -> (structIsBoxed s, structSize s)-                        Just (APIUnion u) -> (unionIsBoxed u, unionSize u)-                        _ -> (False, 0)-           let unpacker | isScalar    = "unpackStorableArrayWithLength"-                        | (size == 0) = "unpackPtrArrayWithLength"-                        | boxed       = "unpackBoxedArrayWithLength " <> tshow size-                        | otherwise   = "unpackBlockArrayWithLength " <> tshow size-           return $ do-             apply $ M $ parenthesize $ unpacker <> " " <> length-             mapC innerConstructor-    _ -> notImplementedError $-         "unpackCArray : Don't know how to unpack C Array of type " <> tshow t--unpackCArray _ _ _ = notImplementedError "unpackCArray : unexpected array type."---- | Whether to expose closures and the associated destroy notify--- handlers in the Haskell wrapper.-data ExposeClosures = WithClosures-                    | WithoutClosures-  deriving (Eq)---- | Given a type find the typeclasses the type belongs to, and return--- the representation of the type in the function signature and the--- list of typeclass constraints for the type.-argumentType :: Type -> ExposeClosures -> CodeGen (Text, [Text])-argumentType (TGList a) expose = do-  (name, constraints) <- argumentType a expose-  return ("[" <> name <> "]", constraints)-argumentType (TGSList a) expose = do-  (name, constraints) <- argumentType a expose-  return ("[" <> name <> "]", constraints)-argumentType t expose = do-  api <- findAPI t-  s <- typeShow <$> haskellType t-  case api of-    -- Instead of restricting to the actual class,-    -- we allow for any object descending from it.-    Just (APIInterface _) -> do-      cls <- typeConstraint t-      l <- getFreshTypeVariable-      return (l, [cls <> " " <> l])-    Just (APIObject _) -> do-      isGO <- isGObject t-      if isGO-        then do cls <- typeConstraint t-                l <- getFreshTypeVariable-                return (l, [cls <> " " <> l])-        else return (s, [])-    Just (APICallback cb) ->-      -- See [Note: Callables that throw]-      if callableThrows (cbCallable cb)-      then do-        ft <- typeShow <$> foreignType t-        return (ft, [])-      else-        case expose of-          WithClosures -> do-            s_withClosures <- typeShow <$> isoHaskellType t-            return (s_withClosures, [])-          WithoutClosures ->-            return (s, [])-    _ -> return (s, [])--haskellBasicType :: BasicType -> TypeRep-haskellBasicType TPtr      = ptr $ con0 "()"-haskellBasicType TBoolean  = con0 "Bool"--- For all the platforms that we support (and those supported by glib)--- we have gint == gint32. Encoding this assumption in the types saves--- conversions.-haskellBasicType TInt      = case sizeOf (0 :: CInt) of-                               4 -> con0 "Int32"-                               n -> error ("Unsupported `gint' length: " ++-                                           show n)-haskellBasicType TUInt     = case sizeOf (0 :: CUInt) of-                               4 -> con0 "Word32"-                               n -> error ("Unsupported `guint' length: " ++-                                           show n)-haskellBasicType TLong     = con0 "CLong"-haskellBasicType TULong    = con0 "CULong"-haskellBasicType TInt8     = con0 "Int8"-haskellBasicType TUInt8    = con0 "Word8"-haskellBasicType TInt16    = con0 "Int16"-haskellBasicType TUInt16   = con0 "Word16"-haskellBasicType TInt32    = con0 "Int32"-haskellBasicType TUInt32   = con0 "Word32"-haskellBasicType TInt64    = con0 "Int64"-haskellBasicType TUInt64   = con0 "Word64"-haskellBasicType TGType    = con0 "GType"-haskellBasicType TUTF8     = con0 "T.Text"-haskellBasicType TFloat    = con0 "Float"-haskellBasicType TDouble   = con0 "Double"-haskellBasicType TUniChar  = con0 "Char"-haskellBasicType TFileName = con0 "[Char]"-haskellBasicType TIntPtr   = con0 "CIntPtr"-haskellBasicType TUIntPtr  = con0 "CUIntPtr"---- | This translates GI types to the types used for generated Haskell code.-haskellType :: Type -> CodeGen TypeRep-haskellType (TBasicType bt) = return $ haskellBasicType bt--- There is no great choice in this case, so we simply pass the--- pointer along. This is useful for GdkPixbufNotify, for example.-haskellType t@(TCArray False (-1) (-1) (TBasicType TUInt8)) =-  foreignType t-haskellType (TCArray _ _ _ (TBasicType TUInt8)) =-  return $ "ByteString" `con` []-haskellType (TCArray _ _ _ a) = do-  inner <- haskellType a-  return $ "[]" `con` [inner]-haskellType (TGArray a) = do-  inner <- haskellType a-  return $ "[]" `con` [inner]-haskellType (TPtrArray a) = do-  inner <- haskellType a-  return $ "[]" `con` [inner]-haskellType (TByteArray) = return $ "ByteString" `con` []-haskellType (TGList a) = do-  inner <- haskellType a-  return $ "[]" `con` [inner]-haskellType (TGSList a) = do-  inner <- haskellType a-  return $ "[]" `con` [inner]-haskellType (TGHash a b) = do-  innerA <- haskellType a-  innerB <- haskellType b-  return $ "Map.Map" `con` [innerA, innerB]-haskellType TError = return $ "GError" `con` []-haskellType TVariant = return $ "GVariant" `con` []-haskellType TParamSpec = return $ "GParamSpec" `con` []-haskellType (TGClosure (Just inner@(TInterface n))) = do-  innerAPI <- getAPI inner-  case innerAPI of-    APICallback _ -> do-      tname <- qualifiedSymbol (callbackCType $ name n) n-      return $ "GClosure" `con` [con0 tname]-    -- The given inner type does not make sense, so we treat it as an-    -- untyped closure.-    _ -> haskellType (TGClosure Nothing)-haskellType (TGClosure _) = do-  tyvar <- getFreshTypeVariable-  return $ "GClosure" `con` [con0 tyvar]-haskellType (TInterface (Name "GObject" "Value")) = return $ "GValue" `con` []-haskellType t@(TInterface n) = do-  api <- getAPI t-  tname <- qualifiedAPI n-  return $ case api of-             (APIFlags _) -> "[]" `con` [tname `con` []]-             _ -> tname `con` []---- | Whether the callable has closure arguments (i.e. "user_data"--- style arguments).-callableHasClosures :: Callable -> Bool-callableHasClosures = any (/= -1) . map argClosure . args---- | Check whether the given type corresponds to a callback.-typeIsCallback :: Type -> CodeGen Bool-typeIsCallback t@(TInterface _) = do-  api <- findAPI t-  case api of-    Just (APICallback _) -> return True-    _ -> return False-typeIsCallback _ = return False---- | Basically like `haskellType`, but for types which admit a--- "isomorphic" version of the Haskell type distinct from the usual--- Haskell type.  Generally the Haskell type we expose is isomorphic--- to the foreign type, but in some cases, such as callbacks with--- closure arguments, this does not hold, as we omit the closure--- arguments. This function returns a type which is actually--- isomorphic. There is another case this function deals with: for--- convenience untyped `TGClosure` types have a type variable on the--- Haskell side when they are arguments to functions, but we do not--- want this when they appear as arguments to callbacks/signals, or--- return types of properties, as it would force the type synonym/type--- family to depend on the type variable.-isoHaskellType :: Type -> CodeGen TypeRep-isoHaskellType (TGClosure Nothing) =-  return $ "GClosure" `con` [con0 "()"]-isoHaskellType t@(TInterface n) = do-  api <- findAPI t-  case api of-    Just (APICallback cb) -> do-        tname <- qualifiedAPI n-        if callableHasClosures (cbCallable cb)-        then return ((callbackHTypeWithClosures tname) `con` [])-        else return (tname `con` [])-    _ -> haskellType t-isoHaskellType t = haskellType t---- | Foreign (C) type associated to one of the basic types.-foreignBasicType :: BasicType -> TypeRep-foreignBasicType TBoolean  = "CInt" `con` []-foreignBasicType TUTF8     = "CString" `con` []-foreignBasicType TFileName = "CString" `con` []-foreignBasicType TUniChar  = "CInt" `con` []-foreignBasicType TFloat    = "CFloat" `con` []-foreignBasicType TDouble   = "CDouble" `con` []-foreignBasicType TGType    = "CGType" `con` []-foreignBasicType t         = haskellBasicType t---- This translates GI types to the types used in foreign function calls.-foreignType :: Type -> CodeGen TypeRep-foreignType (TBasicType t) = return $ foreignBasicType t-foreignType (TCArray zt _ _ t) = do-  api <- findAPI t-  let size = case api of-               Just (APIStruct s) -> structSize s-               Just (APIUnion u) -> unionSize u-               _ -> 0-  if size == 0 || zt-  then ptr <$> foreignType t-  else foreignType t-foreignType (TGArray a) = do-  inner <- foreignType a-  return $ ptr ("GArray" `con` [inner])-foreignType (TPtrArray a) = do-  inner <- foreignType a-  return $ ptr ("GPtrArray" `con` [inner])-foreignType (TByteArray) = return $ ptr ("GByteArray" `con` [])-foreignType (TGList a) = do-  inner <- foreignType a-  return $ ptr ("GList" `con` [inner])-foreignType (TGSList a) = do-  inner <- foreignType a-  return $ ptr ("GSList" `con` [inner])-foreignType (TGHash a b) = do-  innerA <- foreignType a-  innerB <- foreignType b-  return $ ptr ("GHashTable" `con` [innerA, innerB])-foreignType t@TError = ptr <$> haskellType t-foreignType t@TVariant = ptr <$> haskellType t-foreignType t@TParamSpec = ptr <$> haskellType t-foreignType (TGClosure Nothing) = return $ ptr ("GClosure" `con` [con0 "()"])-foreignType t@(TGClosure (Just _)) = ptr <$> haskellType t-foreignType (TInterface (Name "GObject" "Value")) =-  return $ ptr $ "GValue" `con` []-foreignType t@(TInterface n) = do-  api <- getAPI t-  let enumIsSigned e = any (< 0) (map enumMemberValue (enumMembers e))-      ctypeForEnum e = if enumIsSigned e-                       then "CInt"-                       else "CUInt"-  case api of-    APIEnum e -> return $ (ctypeForEnum e) `con` []-    APIFlags (Flags e) -> return $ (ctypeForEnum e) `con` []-    APICallback _ -> do-      tname <- qualifiedSymbol (callbackCType $ name n) n-      return (funptr $ tname `con` [])-    _ -> do-      tname <- qualifiedAPI n-      return (ptr $ tname `con` [])---- | Whether the give type corresponds to an enum or flag.-typeIsEnumOrFlag :: Type -> CodeGen Bool-typeIsEnumOrFlag t = do-  a <- findAPI t-  case a of-    Nothing -> return False-    (Just (APIEnum _)) -> return True-    (Just (APIFlags _)) -> return True-    _ -> return False---- | Information on how to allocate a type.-data TypeAllocInfo = TypeAllocInfo {-      typeAllocInfoIsBoxed :: Bool-    , typeAllocInfoSize    :: Int -- ^ In bytes.-    }---- | Information on how to allocate the given type, if known.-typeAllocInfo :: Type -> CodeGen (Maybe TypeAllocInfo)-typeAllocInfo t = do-  api <- findAPI t-  case api of-    Just (APIStruct s) -> case structSize s of-                            0 -> return Nothing-                            n -> let info = TypeAllocInfo {-                                              typeAllocInfoIsBoxed = structIsBoxed s-                                            , typeAllocInfoSize = n-                                            }-                                 in return (Just info)-    _ -> return Nothing---- | Returns whether the given type corresponds to a `ManagedPtr`--- instance (a thin wrapper over a `ForeignPtr`).-isManaged   :: Type -> CodeGen Bool-isManaged TError = return True-isManaged TVariant = return True-isManaged TParamSpec = return True-isManaged (TGClosure _) = return True-isManaged t@(TInterface _) = do-  a <- findAPI t-  case a of-    Just (APIObject _)    -> return True-    Just (APIInterface _) -> return True-    Just (APIStruct _)    -> return True-    Just (APIUnion _)     -> return True-    _                     -> return False-isManaged _ = return False---- | Returns whether the given type is represented by a pointer on the--- C side.-typeIsPtr :: Type -> CodeGen Bool-typeIsPtr t = isJust <$> typePtrType t---- | Distinct types of foreign pointers.-data FFIPtrType = FFIPtr    -- ^ Ordinary `Ptr`.-                | FFIFunPtr -- ^ `FunPtr`.---- | For those types represented by pointers on the C side, return the--- type of pointer which represents them on the Haskell FFI.-typePtrType :: Type -> CodeGen (Maybe FFIPtrType)-typePtrType (TBasicType TPtr) = return (Just FFIPtr)-typePtrType (TBasicType TUTF8) = return (Just FFIPtr)-typePtrType (TBasicType TFileName) = return (Just FFIPtr)-typePtrType t = do-  ft <- foreignType t-  case typeConName ft of-    "Ptr"    -> return (Just FFIPtr)-    "FunPtr" -> return (Just FFIFunPtr)-    _        -> return Nothing---- | If the passed in type is nullable, return the conversion function--- between the FFI pointer type (may be a `Ptr` or a `FunPtr`) and the--- corresponding `Maybe` type.-maybeNullConvert :: Type -> CodeGen (Maybe Text)-maybeNullConvert (TBasicType TPtr) = return Nothing-maybeNullConvert (TGList _) = return Nothing-maybeNullConvert (TGSList _) = return Nothing-maybeNullConvert t = do-  pt <- typePtrType t-  case pt of-    Just FFIPtr -> return (Just "SP.convertIfNonNull")-    Just FFIFunPtr -> return (Just "SP.convertFunPtrIfNonNull")-    Nothing -> return Nothing---- | An appropriate NULL value for the given type, for types which are--- represented by pointers on the C side.-nullPtrForType :: Type -> CodeGen (Maybe Text)-nullPtrForType t = do-  pt <- typePtrType t-  case pt of-    Just FFIPtr -> return (Just "FP.nullPtr")-    Just FFIFunPtr -> return (Just "FP.nullFunPtr")-    Nothing -> return Nothing---- | Returns whether the given type should be represented by a--- `Maybe` type on the Haskell side. This applies to all properties--- which have a C representation in terms of pointers, except for--- G(S)Lists, for which NULL is a valid G(S)List, and raw pointers,--- which we just pass through to the Haskell side. Notice that--- introspection annotations can override this.-typeIsNullable :: Type -> CodeGen Bool-typeIsNullable t = isJust <$> maybeNullConvert t---- | If the given type maps to a list in Haskell, return the type of the--- elements, and the function that maps over them.-elementTypeAndMap :: Type -> Text -> Maybe (Type, Text)--- ByteString-elementTypeAndMap (TCArray _ _ _ (TBasicType TUInt8)) _ = Nothing-elementTypeAndMap (TCArray True _ _ t) _ = Just (t, "mapZeroTerminatedCArray")-elementTypeAndMap (TCArray False (-1) _ t) len =-    Just (t, parenthesize $ "mapCArrayWithLength " <> len)-elementTypeAndMap (TCArray False fixed _ t) _ =-    Just (t, parenthesize $ "mapCArrayWithLength " <> tshow fixed)-elementTypeAndMap (TGArray t) _ = Just (t, "mapGArray")-elementTypeAndMap (TPtrArray t) _ = Just (t, "mapPtrArray")-elementTypeAndMap (TGList t) _ = Just (t, "mapGList")-elementTypeAndMap (TGSList t) _ = Just (t, "mapGSList")--- GHashTable is treated separately, see Transfer.hs-elementTypeAndMap _ _ = Nothing---- Return just the element type.-elementType :: Type -> Maybe Type-elementType t = fst <$> elementTypeAndMap t undefined---- Return just the map.-elementMap :: Type -> Text -> Maybe Text-elementMap t len = snd <$> elementTypeAndMap t len
+ lib/Data/GI/CodeGen/Conversions.hsc view
@@ -0,0 +1,1077 @@+{-# LANGUAGE PatternGuards, DeriveFunctor #-}++module Data.GI.CodeGen.Conversions+    ( convert+    , genConversion+    , unpackCArray+    , computeArrayLength++    , callableHasClosures++    , hToF+    , fToH+    , transientToH+    , haskellType+    , isoHaskellType+    , foreignType++    , argumentType+    , ExposeClosures(..)+    , elementType+    , elementMap+    , elementTypeAndMap++    , isManaged+    , typeIsNullable+    , typeIsPtr+    , typeIsCallback+    , maybeNullConvert+    , nullPtrForType++    , typeAllocInfo+    , TypeAllocInfo(..)++    , apply+    , mapC+    , literal+    , Constructor(..)+    ) where++#include <glib-object.h>++import Control.Monad (when)+import Data.Maybe (isJust)+import Data.Text (Text)+import qualified Data.Text as T+import GHC.Exts (IsString(..))++import Foreign.C.Types (CInt, CUInt)+import Foreign.Storable (sizeOf)++import Data.GI.CodeGen.API+import Data.GI.CodeGen.Code+import Data.GI.CodeGen.GObject+import Data.GI.CodeGen.SymbolNaming+import Data.GI.CodeGen.Type+import Data.GI.CodeGen.Util++-- | The free monad.+data Free f r = Free (f (Free f r)) | Pure r++instance Functor f => Functor (Free f) where+  fmap f = go where+    go (Pure a)  = Pure (f a)+    go (Free fa) = Free (go <$> fa)++instance (Functor f) => Applicative (Free f) where+    pure = Pure+    Pure a <*> Pure b = Pure $ a b+    Pure a <*> Free mb = Free $ fmap a <$> mb+    Free ma <*> b = Free $ (<*> b) <$> ma++instance (Functor f) => Monad (Free f) where+    return = Pure+    (Free x) >>= f = Free (fmap (>>= f) x)+    (Pure r) >>= f = f r++-- | Lift some command to the Free monad.+liftF :: (Functor f) => f r -> Free f r+liftF command = Free (fmap Pure command)++-- String identifying a constructor in the generated code, which is+-- either (by default) a pure function (indicated by the P+-- constructor) or a function returning values on a monad (M+-- constructor). 'Id' denotes the identity function.+data Constructor = P Text | M Text | Id+                   deriving (Eq,Show)+instance IsString Constructor where+    fromString = P . T.pack++data FExpr next = Apply Constructor next+                | LambdaConvert Text next+                | MapC Map Constructor next+                | Literal Constructor next+                  deriving (Show, Functor)++type Converter = Free FExpr ()++-- Different available maps.+data Map = Map | MapFirst | MapSecond+         deriving (Show)++-- Naming for the maps.+mapName :: Map -> Text+mapName Map = "map"+mapName MapFirst = "mapFirst"+mapName MapSecond = "mapSecond"++-- Naming for the monadic versions of the maps that we use+monadicMapName :: Map -> Text+monadicMapName Map = "mapM"+monadicMapName MapFirst = "mapFirstA"+monadicMapName MapSecond = "mapSecondA"++apply :: Constructor -> Converter+apply f = liftF $ Apply f ()++mapC :: Constructor -> Converter+mapC f = liftF $ MapC Map f ()++mapFirst :: Constructor -> Converter+mapFirst f = liftF $ MapC MapFirst f ()++mapSecond :: Constructor -> Converter+mapSecond f = liftF $ MapC MapSecond f ()++literal :: Constructor -> Converter+literal f = liftF $ Literal f ()++lambdaConvert :: Text -> Converter+lambdaConvert c = liftF $ LambdaConvert c ()++genConversion :: Text -> Converter -> CodeGen Text+genConversion l (Pure ()) = return l+genConversion l (Free k) = do+  let l' = prime l+  case k of+    Apply (P f) next ->+        do line $ "let " <> l' <> " = " <> f <> " " <> l+           genConversion l' next+    Apply (M f) next ->+        do line $ l' <> " <- " <> f <> " " <> l+           genConversion l' next+    Apply Id next -> genConversion l next++    MapC m (P f) next ->+        do line $ "let " <> l' <> " = " <> mapName m <> " " <> f <> " " <> l+           genConversion l' next+    MapC m (M f) next ->+        do line $ l' <> " <- " <> monadicMapName m <> " " <> f <> " " <> l+           genConversion l' next+    MapC _ Id next -> genConversion l next++    LambdaConvert conv next ->+        do line $ conv <> " " <> l <> " $ \\" <> l' <> " -> do"+           increaseIndent+           genConversion l' next++    Literal (P f) next ->+        do line $ "let " <> l <> " = " <> f+           genConversion l next+    Literal (M f) next ->+        do line $ l <> " <- " <> f+           genConversion l next+    Literal Id next -> genConversion l next++-- | Given an array, together with its type, return the code for reading+-- its length.+computeArrayLength :: Text -> Type -> ExcCodeGen Text+computeArrayLength array (TCArray _ _ _ t) = do+  reader <- findReader+  return $ "fromIntegral $ " <> reader <> " " <> array+    where findReader = case t of+                     TBasicType TUInt8 -> return "B.length"+                     _ -> return "P.length"+computeArrayLength _ t =+    notImplementedError $ "computeArrayLength called on non-CArray type "+                            <> tshow t++convert :: Text -> BaseCodeGen e Converter -> BaseCodeGen e Text+convert l c = do+  c' <- c+  genConversion l c'++hObjectToF :: Type -> Transfer -> ExcCodeGen Constructor+hObjectToF t transfer =+  if transfer == TransferEverything+  then do+    isGO <- isGObject t+    if isGO+    then return $ M "B.ManagedPtr.disownObject"+    else return $ M "B.ManagedPtr.disownManagedPtr"+  -- castPtr since we accept any instance of the class associated with+  -- the GObject, not just the precise type of the GObject, while the+  -- foreign function declaration requires a pointer of the precise+  -- type.+  else return $ M "unsafeManagedPtrCastPtr"++hVariantToF :: Transfer -> CodeGen Constructor+hVariantToF transfer =+  if transfer == TransferEverything+  then return $ M "B.GVariant.disownGVariant"+  else return $ M "unsafeManagedPtrGetPtr"++hValueToF :: Transfer -> CodeGen Constructor+hValueToF transfer =+  if transfer == TransferEverything+  then return $ M "B.GValue.disownGValue"+  else return $ M "unsafeManagedPtrGetPtr"++hParamSpecToF :: Transfer -> CodeGen Constructor+hParamSpecToF transfer =+  if transfer == TransferEverything+  then return $ M "B.GParamSpec.disownGParamSpec"+  else return $ M "unsafeManagedPtrGetPtr"++hClosureToF :: Transfer -> Maybe Type -> CodeGen Constructor+-- Untyped closures+hClosureToF transfer Nothing =+  if transfer == TransferEverything+  then return $ M "B.GClosure.disownGClosure"+  -- We cast the point here because the foreign type for untyped+  -- closures is always represented as Ptr (GClosure ()), while the+  -- corresponding Haskell type is the parametric "GClosure a".+  else return $ M "unsafeManagedPtrCastPtr"+-- Typed closures+hClosureToF transfer (Just _) =+  if transfer == TransferEverything+  then return $ M "B.GClosure.disownGClosure"+  else return $ M "unsafeManagedPtrGetPtr"++hBoxedToF :: Transfer -> CodeGen Constructor+hBoxedToF transfer =+  if transfer == TransferEverything+  then return $ M "B.ManagedPtr.disownBoxed"+  else return $ M "unsafeManagedPtrGetPtr"++hStructToF :: Struct -> Transfer -> ExcCodeGen Constructor+hStructToF s transfer =+    if transfer /= TransferEverything || structIsBoxed s then+        hBoxedToF transfer+    else do+        when (structSize s == 0) $+             badIntroError "Transferring a non-boxed struct with unknown size!"+        return $ M "unsafeManagedPtrGetPtr"++hUnionToF :: Union -> Transfer -> ExcCodeGen Constructor+hUnionToF u transfer =+    if transfer /= TransferEverything || unionIsBoxed u then+        hBoxedToF transfer+    else do+        when (unionSize u == 0) $+             badIntroError "Transferring a non-boxed union with unknown size!"+        return $ M "unsafeManagedPtrGetPtr"++-- Given the Haskell and Foreign types, returns the name of the+-- function marshalling between both.+hToF' :: Type -> Maybe API -> TypeRep -> TypeRep -> Transfer+            -> ExcCodeGen Constructor+hToF' t a hType fType transfer+    | ( hType == fType ) = return Id+    | TError <- t = hBoxedToF transfer+    | TVariant <- t = hVariantToF transfer+    | TGValue <- t = hValueToF transfer+    | TParamSpec <- t = hParamSpecToF transfer+    | TGClosure c <- t = hClosureToF transfer c+    | Just (APIEnum _) <- a = return "(fromIntegral . fromEnum)"+    | Just (APIFlags _) <- a = return "gflagsToWord"+    | Just (APIObject _) <- a = hObjectToF t transfer+    | Just (APIInterface _) <- a = hObjectToF t transfer+    | Just (APIStruct s) <- a = hStructToF s transfer+    | Just (APIUnion u) <- a = hUnionToF u transfer+    -- Converting callback types requires more context, we leave that+    -- as a special case to be implemented by the caller.+    | Just (APICallback _) <- a = error "Cannot handle callback type here!! "+    | TByteArray <- t = return $ M "packGByteArray"+    | TCArray True _ _ (TBasicType TUTF8) <- t =+        return $ M "packZeroTerminatedUTF8CArray"+    | TCArray True _ _ (TBasicType TFileName) <- t =+        return $ M "packZeroTerminatedFileNameArray"+    | TCArray True _ _ (TBasicType TPtr) <- t =+        return $ M "packZeroTerminatedPtrArray"+    | TCArray True _ _ (TBasicType TUInt8) <- t =+        return $ M "packZeroTerminatedByteString"+    | TCArray True _ _ (TBasicType TBoolean) <- t =+        return $ M "(packMapZeroTerminatedStorableArray (fromIntegral . fromEnum))"+    | TCArray True _ _ (TBasicType TGType) <- t =+        return $ M "(packMapZeroTerminatedStorableArray gtypeToCGtype)"+    | TCArray True _ _ (TBasicType _) <- t =+        return $ M "packZeroTerminatedStorableArray"+    | TCArray False _ _ (TBasicType TUTF8) <- t =+        return $ M "packUTF8CArray"+    | TCArray False _ _ (TBasicType TFileName) <- t =+        return $ M "packFileNameArray"+    | TCArray False _ _ (TBasicType TPtr) <- t =+        return $ M "packPtrArray"+    | TCArray False _ _ (TBasicType TUInt8) <- t =+        return $ M "packByteString"+    | TCArray False _ _ (TBasicType TBoolean) <- t =+        return $ M "(packMapStorableArray (fromIntegral . fromEnum))"+    | TCArray False _ _ (TBasicType TGType) <- t =+        return $ M "(packMapStorableArray gtypeToCGType)"+    | TCArray False _ _ (TBasicType TFloat) <- t =+        return $ M "(packMapStorableArray realToFrac)"+    | TCArray False _ _ (TBasicType TDouble) <- t =+        return $ M "(packMapStorableArray realToFrac)"+    | TCArray False _ _ (TBasicType _) <- t =+        return $ M "packStorableArray"+    | TCArray False _ _ TGValue <- t =+        return $ M "B.GValue.packGValueArray"+    | TCArray{}  <- t = notImplementedError $+                   "Don't know how to pack C array of type " <> tshow t+    | otherwise = case (typeShow hType, typeShow fType) of+               ("T.Text", "CString") -> return $ M "textToCString"+               ("[Char]", "CString") -> return $ M "stringToCString"+               ("Char", "CInt")      -> return "(fromIntegral . ord)"+               ("Bool", "CInt")      -> return "(fromIntegral . fromEnum)"+               ("Float", "CFloat")   -> return "realToFrac"+               ("Double", "CDouble") -> return "realToFrac"+               ("GType", "CGType")   -> return "gtypeToCGType"+               _                     -> notImplementedError $+                                        "Don't know how to convert "+                                        <> typeShow hType <> " into "+                                        <> typeShow fType <> ".\n"+                                        <> "Internal type: "+                                        <> tshow t++getForeignConstructor :: Type -> Transfer -> ExcCodeGen Constructor+getForeignConstructor t transfer = do+  a <- findAPI t+  hType <- haskellType t+  fType <- foreignType t+  hToF' t a hType fType transfer++hToF_PackedType :: Type -> Text -> Transfer -> ExcCodeGen Converter+hToF_PackedType t packer transfer = do+  innerConstructor <- getForeignConstructor t transfer+  return $ do+    mapC innerConstructor+    apply (M packer)++-- | Try to find the `hash` and `equal` functions appropriate for the+-- given type, when used as a key in a GHashTable.+hashTableKeyMappings :: Type -> ExcCodeGen (Text, Text)+hashTableKeyMappings (TBasicType TPtr) = return ("gDirectHash", "gDirectEqual")+hashTableKeyMappings (TBasicType TUTF8) = return ("gStrHash", "gStrEqual")+hashTableKeyMappings t =+    notImplementedError $ "GHashTable key of type " <> tshow t <> " unsupported."++-- | `GHashTable` tries to fit every type into a pointer, the+-- following function tries to find the appropriate+-- (destroy,packer,unpacker) for the given type.+hashTablePtrPackers :: Type -> ExcCodeGen (Text, Text, Text)+hashTablePtrPackers (TBasicType TPtr) =+    return ("Nothing", "ptrPackPtr", "ptrUnpackPtr")+hashTablePtrPackers (TBasicType TUTF8) =+    return ("(Just ptr_to_g_free)", "cstringPackPtr", "cstringUnpackPtr")+hashTablePtrPackers t =+    notImplementedError $ "GHashTable element of type " <> tshow t <> " unsupported."++hToF_PackGHashTable :: Type -> Type -> ExcCodeGen Converter+hToF_PackGHashTable keys elems = do+  -- We will be adding elements to the Hash list with appropriate+  -- destructors, so we always want a fresh copy.+  keysConstructor <- getForeignConstructor keys TransferEverything+  elemsConstructor <- getForeignConstructor elems TransferEverything+  (keyHash, keyEqual) <- hashTableKeyMappings keys+  (keyDestroy, keyPack, _) <- hashTablePtrPackers keys+  (elemDestroy, elemPack, _) <- hashTablePtrPackers elems+  return $ do+    apply (P "Map.toList")+    mapFirst keysConstructor+    mapSecond elemsConstructor+    mapFirst (P keyPack)+    mapSecond (P elemPack)+    apply (M (T.intercalate " " ["packGHashTable", keyHash, keyEqual,+                                 keyDestroy, elemDestroy]))++hToF :: Type -> Transfer -> ExcCodeGen Converter+hToF (TGList t) transfer = do+  isPtr <- typeIsPtr t+  when (not isPtr) $+       badIntroError ("'" <> tshow t <>+                      "' is not a pointer type, cannot pack into a GList.")+  hToF_PackedType t "packGList" transfer+hToF (TGSList t) transfer = do+  isPtr <- typeIsPtr t+  when (not isPtr) $+       badIntroError ("'" <> tshow t <>+                      "' is not a pointer type, cannot pack into a GSList.")+  hToF_PackedType t "packGSList" transfer+hToF (TGArray t) transfer = hToF_PackedType t "packGArray" transfer+hToF (TPtrArray t) transfer = hToF_PackedType t "packGPtrArray" transfer+hToF (TGHash ta tb) _ = hToF_PackGHashTable ta tb+hToF (TCArray zt _ _ t@(TCArray{})) transfer = do+  let packer = if zt+               then "packZeroTerminated"+               else "pack"+  hToF_PackedType t (packer <> "PtrArray") transfer+hToF (TCArray zt _ _ t@(TInterface _)) transfer = do+  isScalar <- typeIsEnumOrFlag t+  let packer = if zt+               then "packZeroTerminated"+               else "pack"+  if isScalar+  then hToF_PackedType t (packer <> "StorableArray") transfer+  else do+    api <- findAPI t+    let size = case api of+                 Just (APIStruct s) -> structSize s+                 Just (APIUnion u) -> unionSize u+                 _ -> 0+    if size == 0 || zt+    then hToF_PackedType t (packer <> "PtrArray") transfer+    else hToF_PackedType t (packer <> "BlockArray " <> tshow size) transfer++hToF t transfer = do+  a <- findAPI t+  hType <- haskellType t+  fType <- foreignType t+  constructor <- hToF' t a hType fType transfer+  return $ apply constructor++boxedForeignPtr :: Text -> Transfer -> CodeGen Constructor+boxedForeignPtr constructor transfer = return $+   case transfer of+     TransferEverything -> M $ parenthesize $ "wrapBoxed " <> constructor+     _ -> M $ parenthesize $ "newBoxed " <> constructor++suForeignPtr :: Bool -> TypeRep -> Transfer -> CodeGen Constructor+suForeignPtr isBoxed hType transfer = do+  let constructor = typeConName hType+  if isBoxed then+      boxedForeignPtr constructor transfer+  else return $ M $ parenthesize $+       case transfer of+         TransferEverything -> "wrapPtr " <> constructor+         _ -> "newPtr " <> constructor++structForeignPtr :: Struct -> TypeRep -> Transfer -> CodeGen Constructor+structForeignPtr s =+    suForeignPtr (structIsBoxed s)++unionForeignPtr :: Union -> TypeRep -> Transfer -> CodeGen Constructor+unionForeignPtr u =+    suForeignPtr (unionIsBoxed u)++fObjectToH :: Type -> TypeRep -> Transfer -> ExcCodeGen Constructor+fObjectToH t hType transfer = do+  let constructor = typeConName hType+  isGO <- isGObject t+  return $ M $ parenthesize $+    case transfer of+    TransferEverything ->+        if isGO+        then "wrapObject " <> constructor+        else "wrapPtr " <> constructor+    _ ->+        if isGO+        then "newObject " <> constructor+        else "newPtr " <> constructor++fCallbackToH :: TypeRep -> Transfer -> ExcCodeGen Constructor+fCallbackToH hType TransferNothing = do+  let constructor = typeConName hType+  return (P (callbackDynamicWrapper constructor))+fCallbackToH _ transfer =+  notImplementedError ("ForeignCallback with unsupported transfer type `"+                       <> tshow transfer <> "'")++fVariantToH :: Transfer -> CodeGen Constructor+fVariantToH transfer =+  return $ M $ case transfer of+                  TransferEverything -> "B.GVariant.wrapGVariantPtr"+                  _ -> "B.GVariant.newGVariantFromPtr"++fValueToH :: Transfer -> CodeGen Constructor+fValueToH transfer =+  return $ M $ case transfer of+                  TransferEverything -> "B.GValue.wrapGValuePtr"+                  _ -> "B.GValue.newGValueFromPtr"++fParamSpecToH :: Transfer -> CodeGen Constructor+fParamSpecToH transfer =+  return $ M $ case transfer of+                  TransferEverything -> "B.GParamSpec.wrapGParamSpecPtr"+                  _ -> "B.GParamSpec.newGParamSpecFromPtr"++fClosureToH :: Transfer -> Maybe Type -> CodeGen Constructor+-- Untyped closures+fClosureToH transfer Nothing =+  return $ M $ case transfer of+                  TransferEverything ->+                    parenthesize $ "B.GClosure.wrapGClosurePtr . FP.castPtr"+                  _ -> parenthesize $ "B.GClosure.newGClosureFromPtr . FP.castPtr"+-- Typed closures+fClosureToH transfer (Just _) =+  return $ M $ case transfer of+                  TransferEverything -> "B.GClosure.wrapGClosurePtr"+                  _ -> "B.GClosure.newGClosureFromPtr"++fToH' :: Type -> Maybe API -> TypeRep -> TypeRep -> Transfer+         -> ExcCodeGen Constructor+fToH' t a hType fType transfer+    | ( hType == fType ) = return Id+    | Just (APIEnum _) <- a = return "(toEnum . fromIntegral)"+    | Just (APIFlags _) <- a = return "wordToGFlags"+    | TError <- t = boxedForeignPtr "GError" transfer+    | TVariant <- t = fVariantToH transfer+    | TGValue <- t = fValueToH transfer+    | TParamSpec <- t = fParamSpecToH transfer+    | TGClosure c <- t = fClosureToH transfer c+    | Just (APIStruct s) <- a = structForeignPtr s hType transfer+    | Just (APIUnion u) <- a = unionForeignPtr u hType transfer+    | Just (APIObject _) <- a = fObjectToH t hType transfer+    | Just (APIInterface _) <- a = fObjectToH t hType transfer+    | Just (APICallback _) <- a = fCallbackToH hType transfer+    | TCArray True _ _ (TBasicType TUTF8) <- t =+        return $ M "unpackZeroTerminatedUTF8CArray"+    | TCArray True _ _ (TBasicType TFileName) <- t =+        return $ M "unpackZeroTerminatedFileNameArray"+    | TCArray True _ _ (TBasicType TUInt8) <- t =+        return $ M "unpackZeroTerminatedByteString"+    | TCArray True _ _ (TBasicType TPtr) <- t =+        return $ M "unpackZeroTerminatedPtrArray"+    | TCArray True _ _ (TBasicType TBoolean) <- t =+        return $ M "(unpackMapZeroTerminatedStorableArray (/= 0))"+    | TCArray True _ _ (TBasicType TGType) <- t =+        return $ M "(unpackMapZeroTerminatedStorableArray GType)"+    | TCArray True _ _ (TBasicType TFloat) <- t =+        return $ M "(unpackMapZeroTerminatedStorableArray realToFrac)"+    | TCArray True _ _ (TBasicType TDouble) <- t =+        return $ M "(unpackMapZeroTerminatedStorableArray realToFrac)"+    | TCArray True _ _ (TBasicType _) <- t =+        return $ M "unpackZeroTerminatedStorableArray"+    | TCArray{}  <- t = notImplementedError $+                   "Don't know how to unpack C array of type " <> tshow t+    | TByteArray <- t = return $ M "unpackGByteArray"+    | TGHash _ _ <- t = notImplementedError "Foreign Hashes not supported yet"+    | otherwise = case (typeShow fType, typeShow hType) of+               ("CString", "T.Text") -> return $ M "cstringToText"+               ("CString", "[Char]") -> return $ M "cstringToString"+               ("CInt", "Char")      -> return "(chr . fromIntegral)"+               ("CInt", "Bool")      -> return "(/= 0)"+               ("CFloat", "Float")   -> return "realToFrac"+               ("CDouble", "Double") -> return "realToFrac"+               ("CGType", "GType")   -> return "GType"+               _                     ->+                   notImplementedError $ "Don't know how to convert "+                                           <> typeShow fType <> " into "+                                           <> typeShow hType <> ".\n"+                                           <> "Internal type: "+                                           <> tshow t++getHaskellConstructor :: Type -> Transfer -> ExcCodeGen Constructor+getHaskellConstructor t transfer = do+  a <- findAPI t+  hType <- haskellType t+  fType <- foreignType t+  fToH' t a hType fType transfer++fToH_PackedType :: Type -> Text -> Transfer -> ExcCodeGen Converter+fToH_PackedType t unpacker transfer = do+  innerConstructor <- getHaskellConstructor t transfer+  return $ do+    apply (M unpacker)+    mapC innerConstructor++fToH_UnpackGHashTable :: Type -> Type -> Transfer -> ExcCodeGen Converter+fToH_UnpackGHashTable keys elems transfer = do+  keysConstructor <- getHaskellConstructor keys transfer+  (_,_,keysUnpack) <- hashTablePtrPackers keys+  elemsConstructor <- getHaskellConstructor elems transfer+  (_,_,elemsUnpack) <- hashTablePtrPackers elems+  return $ do+    apply (M "unpackGHashTable")+    mapFirst (P keysUnpack)+    mapFirst keysConstructor+    mapSecond (P elemsUnpack)+    mapSecond elemsConstructor+    apply (P "Map.fromList")++fToH :: Type -> Transfer -> ExcCodeGen Converter+fToH (TGList t) transfer = do+  isPtr <- typeIsPtr t+  when (not isPtr) $+       badIntroError ("`" <> tshow t <>+                      "' is not a pointer type, cannot unpack from a GList.")+  fToH_PackedType t "unpackGList" transfer+fToH (TGSList t) transfer = do+  isPtr <- typeIsPtr t+  when (not isPtr) $+       badIntroError ("`" <> tshow t <>+                      "' is not a pointer type, cannot unpack from a GSList.")+  fToH_PackedType t "unpackGSList" transfer+fToH (TGArray t) transfer = fToH_PackedType t "unpackGArray" transfer+fToH (TPtrArray t) transfer = fToH_PackedType t "unpackGPtrArray" transfer+fToH (TGHash a b) transfer = fToH_UnpackGHashTable a b transfer+-- We cannot unpack arrays without any kind of length info.+fToH t@(TCArray False (-1) (-1) _) _ =+  badIntroError ("`" <> tshow t <>+                  "' is an array type, but contains no length information.")+fToH (TCArray True _ _ t@(TCArray{})) transfer =+  fToH_PackedType t "unpackZeroTerminatedPtrArray" transfer+fToH (TCArray True _ _ t@(TInterface _)) transfer = do+  isScalar <- typeIsEnumOrFlag t+  if isScalar+  then fToH_PackedType t "unpackZeroTerminatedStorableArray" transfer+  else fToH_PackedType t "unpackZeroTerminatedPtrArray" transfer++fToH t transfer = do+  a <- findAPI t+  hType <- haskellType t+  fType <- foreignType t+  constructor <- fToH' t a hType fType transfer+  return $ apply constructor++-- | Somewhat like `fToH`, but with slightly different borrowing+-- semantics: in the case of `TransferNothing` we wrap incoming+-- pointers to boxed structs into transient `ManagedPtr`s (every other+-- case behaves as `fToH`). These are `ManagedPtr`s for which we do+-- not make a copy, and which will be disowned when the function+-- exists, instead of making a copy that the GC will collect+-- eventually.+--+-- This is necessary in order to get the semantics of callbacks and+-- signals right: in some cases making a copy of the object does not+-- simply increase the refcount, but rather makes a full copy. In this+-- cases modification of the original object is not possible, but this+-- is sometimes useful, see for example+--+-- https://github.com/haskell-gi/haskell-gi/issues/97+--+-- Another situation where making a copy of incoming arguments is+-- problematic is when the underlying library is not thread-safe. When+-- running under the threaded GHC runtime it can happen that the GC+-- runs on a different OS thread than the thread where the object was+-- created, and this leads to rather mysterious bugs, see for example+--+-- https://github.com/haskell-gi/haskell-gi/issues/96+--+-- This case is particularly nasty, since it affects `onWidgetDraw`,+-- which is very common.+transientToH :: Type -> Transfer -> ExcCodeGen Converter+transientToH t@(TInterface _) TransferNothing = do+  a <- findAPI t+  case a of+    Just (APIStruct s) -> if structIsBoxed s+                          then wrapTransient t+                          else fToH t TransferNothing+    Just (APIUnion u) -> if unionIsBoxed u+                         then wrapTransient t+                         else fToH t TransferNothing+    _ -> fToH t TransferNothing+transientToH t transfer = fToH t transfer++-- | Wrap the given transient.+wrapTransient :: Type -> CodeGen Converter+wrapTransient t = do+  hCon <- typeConName <$> haskellType t+  return $ lambdaConvert $ "B.ManagedPtr.withTransient " <> hCon++unpackCArray :: Text -> Type -> Transfer -> ExcCodeGen Converter+unpackCArray length (TCArray False _ _ t) transfer =+  case t of+    TBasicType TUTF8 -> return $ apply $ M $ parenthesize $+                        "unpackUTF8CArrayWithLength " <> length+    TBasicType TFileName -> return $ apply $ M $ parenthesize $+                            "unpackFileNameArrayWithLength " <> length+    TBasicType TUInt8 -> return $ apply $ M $ parenthesize $+                         "unpackByteStringWithLength " <> length+    TBasicType TPtr -> return $ apply $ M $ parenthesize $+                         "unpackPtrArrayWithLength " <> length+    TBasicType TBoolean -> return $ apply $ M $ parenthesize $+                         "unpackMapStorableArrayWithLength (/= 0) " <> length+    TBasicType TGType -> return $ apply $ M $ parenthesize $+                         "unpackMapStorableArrayWithLength GType " <> length+    TBasicType TFloat -> return $ apply $ M $ parenthesize $+                         "unpackMapStorableArrayWithLength realToFrac " <> length+    TBasicType TDouble -> return $ apply $ M $ parenthesize $+                         "unpackMapStorableArrayWithLength realToFrac " <> length+    TBasicType _ -> return $ apply $ M $ parenthesize $+                         "unpackStorableArrayWithLength " <> length+    TGValue -> return $ apply $ M $ parenthesize $+               "B.GValue.unpackGValueArrayWithLength " <> length+    TInterface _ -> do+           a <- findAPI t+           isScalar <- typeIsEnumOrFlag t+           hType <- haskellType t+           fType <- foreignType t+           let (boxed, size) = case a of+                        Just (APIStruct s) -> (structIsBoxed s, structSize s)+                        Just (APIUnion u) -> (unionIsBoxed u, unionSize u)+                        _ -> (False, 0)+           let unpacker | isScalar    = "unpackStorableArrayWithLength"+                        | (size == 0) = "unpackPtrArrayWithLength"+                        | boxed       = "unpackBoxedArrayWithLength " <> tshow size+                        | otherwise   = "unpackBlockArrayWithLength " <> tshow size+               -- We always make a copy of the elements when unpacking+               -- boxed types.+           let transfer' | boxed      = if transfer == TransferContainer+                                        then TransferEverything+                                        else transfer+                         | otherwise  = transfer+           innerConstructor <- fToH' t a hType fType transfer'+           return $ do+             apply $ M $ parenthesize $ unpacker <> " " <> length+             mapC innerConstructor+    _ -> notImplementedError $+         "unpackCArray : Don't know how to unpack C Array of type " <> tshow t++unpackCArray _ _ _ = notImplementedError "unpackCArray : unexpected array type."++-- | Whether to expose closures and the associated destroy notify+-- handlers in the Haskell wrapper.+data ExposeClosures = WithClosures+                    | WithoutClosures+  deriving (Eq)++-- | Given a type find the typeclasses the type belongs to, and return+-- the representation of the type in the function signature and the+-- list of typeclass constraints for the type.+argumentType :: Type -> ExposeClosures -> CodeGen (Text, [Text])+argumentType (TGList a) expose = do+  (name, constraints) <- argumentType a expose+  return ("[" <> name <> "]", constraints)+argumentType (TGSList a) expose = do+  (name, constraints) <- argumentType a expose+  return ("[" <> name <> "]", constraints)+argumentType t expose = do+  api <- findAPI t+  s <- typeShow <$> haskellType t+  case api of+    -- Instead of restricting to the actual class,+    -- we allow for any object descending from it.+    Just (APIInterface _) -> do+      cls <- typeConstraint t+      l <- getFreshTypeVariable+      return (l, [cls <> " " <> l])+    Just (APIObject _) -> do+      cls <- typeConstraint t+      l <- getFreshTypeVariable+      return (l, [cls <> " " <> l])+    Just (APICallback cb) ->+      -- See [Note: Callables that throw]+      if callableThrows (cbCallable cb)+      then do+        ft <- typeShow <$> foreignType t+        return (ft, [])+      else+        case expose of+          WithClosures -> do+            s_withClosures <- typeShow <$> isoHaskellType t+            return (s_withClosures, [])+          WithoutClosures ->+            return (s, [])+    _ -> return (s, [])++haskellBasicType :: BasicType -> TypeRep+haskellBasicType TPtr      = ptr $ con0 "()"+haskellBasicType TBoolean  = con0 "Bool"+-- For all the platforms that we support (and those supported by glib)+-- we have gint == gint32. Encoding this assumption in the types saves+-- conversions.+haskellBasicType TInt      = case sizeOf (0 :: CInt) of+                               4 -> con0 "Int32"+                               n -> error ("Unsupported `gint' length: " +++                                           show n)+haskellBasicType TUInt     = case sizeOf (0 :: CUInt) of+                               4 -> con0 "Word32"+                               n -> error ("Unsupported `guint' length: " +++                                           show n)+haskellBasicType TLong     = con0 "CLong"+haskellBasicType TULong    = con0 "CULong"+haskellBasicType TInt8     = con0 "Int8"+haskellBasicType TUInt8    = con0 "Word8"+haskellBasicType TInt16    = con0 "Int16"+haskellBasicType TUInt16   = con0 "Word16"+haskellBasicType TInt32    = con0 "Int32"+haskellBasicType TUInt32   = con0 "Word32"+haskellBasicType TInt64    = con0 "Int64"+haskellBasicType TUInt64   = con0 "Word64"+haskellBasicType TGType    = con0 "GType"+haskellBasicType TUTF8     = con0 "T.Text"+haskellBasicType TFloat    = con0 "Float"+haskellBasicType TDouble   = con0 "Double"+haskellBasicType TUniChar  = con0 "Char"+haskellBasicType TFileName = con0 "[Char]"+haskellBasicType TIntPtr   = con0 "CIntPtr"+haskellBasicType TUIntPtr  = con0 "CUIntPtr"++-- | This translates GI types to the types used for generated Haskell code.+haskellType :: Type -> CodeGen TypeRep+haskellType (TBasicType bt) = return $ haskellBasicType bt+-- There is no great choice in this case, so we simply pass the+-- pointer along. This is useful for GdkPixbufNotify, for example.+haskellType t@(TCArray False (-1) (-1) (TBasicType TUInt8)) =+  foreignType t+haskellType (TCArray _ _ _ (TBasicType TUInt8)) =+  return $ "ByteString" `con` []+haskellType (TCArray _ _ _ a) = do+  inner <- haskellType a+  return $ "[]" `con` [inner]+haskellType (TGArray a) = do+  inner <- haskellType a+  return $ "[]" `con` [inner]+haskellType (TPtrArray a) = do+  inner <- haskellType a+  return $ "[]" `con` [inner]+haskellType (TByteArray) = return $ "ByteString" `con` []+haskellType (TGList a) = do+  inner <- haskellType a+  return $ "[]" `con` [inner]+haskellType (TGSList a) = do+  inner <- haskellType a+  return $ "[]" `con` [inner]+haskellType (TGHash a b) = do+  innerA <- haskellType a+  innerB <- haskellType b+  return $ "Map.Map" `con` [innerA, innerB]+haskellType TError = return $ "GError" `con` []+haskellType TVariant = return $ "GVariant" `con` []+haskellType TParamSpec = return $ "GParamSpec" `con` []+haskellType (TGClosure (Just inner@(TInterface n))) = do+  innerAPI <- getAPI inner+  case innerAPI of+    APICallback _ -> do+      let n' = normalizedAPIName innerAPI n+      tname <- qualifiedSymbol (callbackCType $ name n') n+      return $ "GClosure" `con` [con0 tname]+    -- The given inner type does not make sense, so we treat it as an+    -- untyped closure.+    _ -> haskellType (TGClosure Nothing)+haskellType (TGClosure _) = do+  tyvar <- getFreshTypeVariable+  return $ "GClosure" `con` [con0 tyvar]+haskellType TGValue = return $ "GValue" `con` []+haskellType t@(TInterface n) = do+  api <- getAPI t+  tname <- qualifiedAPI api n+  return $ case api of+             (APIFlags _) -> "[]" `con` [tname `con` []]+             _ -> tname `con` []++-- | Whether the callable has closure arguments (i.e. "user_data"+-- style arguments).+callableHasClosures :: Callable -> Bool+callableHasClosures = any (/= -1) . map argClosure . args++-- | Check whether the given type corresponds to a callback.+typeIsCallback :: Type -> CodeGen Bool+typeIsCallback t@(TInterface _) = do+  api <- findAPI t+  case api of+    Just (APICallback _) -> return True+    _ -> return False+typeIsCallback _ = return False++-- | Basically like `haskellType`, but for types which admit a+-- "isomorphic" version of the Haskell type distinct from the usual+-- Haskell type.  Generally the Haskell type we expose is isomorphic+-- to the foreign type, but in some cases, such as callbacks with+-- closure arguments, this does not hold, as we omit the closure+-- arguments. This function returns a type which is actually+-- isomorphic. There is another case this function deals with: for+-- convenience untyped `TGClosure` types have a type variable on the+-- Haskell side when they are arguments to functions, but we do not+-- want this when they appear as arguments to callbacks/signals, or+-- return types of properties, as it would force the type synonym/type+-- family to depend on the type variable.+isoHaskellType :: Type -> CodeGen TypeRep+isoHaskellType (TGClosure Nothing) =+  return $ "GClosure" `con` [con0 "()"]+isoHaskellType t@(TInterface n) = do+  api <- findAPI t+  case api of+    Just apiCB@(APICallback cb) -> do+        tname <- qualifiedAPI apiCB n+        if callableHasClosures (cbCallable cb)+        then return ((callbackHTypeWithClosures tname) `con` [])+        else return (tname `con` [])+    _ -> haskellType t+isoHaskellType t = haskellType t++-- | Foreign (C) type associated to one of the basic types.+foreignBasicType :: BasicType -> TypeRep+foreignBasicType TBoolean  = "CInt" `con` []+foreignBasicType TUTF8     = "CString" `con` []+foreignBasicType TFileName = "CString" `con` []+foreignBasicType TUniChar  = "CInt" `con` []+foreignBasicType TFloat    = "CFloat" `con` []+foreignBasicType TDouble   = "CDouble" `con` []+foreignBasicType TGType    = "CGType" `con` []+foreignBasicType t         = haskellBasicType t++-- This translates GI types to the types used in foreign function calls.+foreignType :: Type -> CodeGen TypeRep+foreignType (TBasicType t) = return $ foreignBasicType t+foreignType (TCArray _ _ _ TGValue) = return $ ptr ("B.GValue.GValue" `con` [])+foreignType (TCArray zt _ _ t) = do+  api <- findAPI t+  let size = case api of+               Just (APIStruct s) -> structSize s+               Just (APIUnion u) -> unionSize u+               _ -> 0+  if size == 0 || zt+  then ptr <$> foreignType t+  else foreignType t+foreignType (TGArray a) = do+  inner <- foreignType a+  return $ ptr ("GArray" `con` [inner])+foreignType (TPtrArray a) = do+  inner <- foreignType a+  return $ ptr ("GPtrArray" `con` [inner])+foreignType (TByteArray) = return $ ptr ("GByteArray" `con` [])+foreignType (TGList a) = do+  inner <- foreignType a+  return $ ptr ("GList" `con` [inner])+foreignType (TGSList a) = do+  inner <- foreignType a+  return $ ptr ("GSList" `con` [inner])+foreignType (TGHash a b) = do+  innerA <- foreignType a+  innerB <- foreignType b+  return $ ptr ("GHashTable" `con` [innerA, innerB])+foreignType t@TError = ptr <$> haskellType t+foreignType t@TVariant = ptr <$> haskellType t+foreignType t@TParamSpec = ptr <$> haskellType t+foreignType (TGClosure Nothing) = return $ ptr ("GClosure" `con` [con0 "()"])+foreignType t@(TGClosure (Just _)) = ptr <$> haskellType t+foreignType t@(TGValue) = ptr <$> haskellType t+foreignType t@(TInterface n) = do+  api <- getAPI t+  let enumIsSigned e = any (< 0) (map enumMemberValue (enumMembers e))+      ctypeForEnum e = if enumIsSigned e+                       then "CInt"+                       else "CUInt"+  case api of+    APIEnum e -> return $ (ctypeForEnum e) `con` []+    APIFlags (Flags e) -> return $ (ctypeForEnum e) `con` []+    APICallback _ -> do+      let n' = normalizedAPIName api n+      tname <- qualifiedSymbol (callbackCType $ name n') n+      return (funptr $ tname `con` [])+    _ -> do+      tname <- qualifiedAPI api n+      return (ptr $ tname `con` [])++-- | Whether the give type corresponds to an enum or flag.+typeIsEnumOrFlag :: Type -> CodeGen Bool+typeIsEnumOrFlag t = do+  a <- findAPI t+  case a of+    Nothing -> return False+    (Just (APIEnum _)) -> return True+    (Just (APIFlags _)) -> return True+    _ -> return False++-- | Information on how to allocate a type: allocator function and+-- size of the struct.+data TypeAllocInfo = TypeAlloc Text Int++-- | Information on how to allocate the given type, if known.+typeAllocInfo :: Type -> CodeGen (Maybe TypeAllocInfo)+typeAllocInfo TGValue =+  let n = #{size GValue}+  in return $ Just $ TypeAlloc ("SP.callocBytes " <> tshow n) n+typeAllocInfo t = do+  api <- findAPI t+  case api of+    Just (APIStruct s) ->+      case structSize s of+        0 -> return Nothing+        n -> let allocator = if structIsBoxed s+                             then "SP.callocBoxedBytes"+                             else "SP.callocBytes"+             in return $ Just $ TypeAlloc (allocator <> " " <> tshow n) n+    _ -> return Nothing++-- | Returns whether the given type corresponds to a `ManagedPtr`+-- instance (a thin wrapper over a `ForeignPtr`).+isManaged   :: Type -> CodeGen Bool+isManaged TError = return True+isManaged TVariant = return True+isManaged TGValue = return True+isManaged TParamSpec = return True+isManaged (TGClosure _) = return True+isManaged t@(TInterface _) = do+  a <- findAPI t+  case a of+    Just (APIObject _)    -> return True+    Just (APIInterface _) -> return True+    Just (APIStruct _)    -> return True+    Just (APIUnion _)     -> return True+    _                     -> return False+isManaged _ = return False++-- | Returns whether the given type is represented by a pointer on the+-- C side.+typeIsPtr :: Type -> CodeGen Bool+typeIsPtr t = isJust <$> typePtrType t++-- | Distinct types of foreign pointers.+data FFIPtrType = FFIPtr    -- ^ Ordinary `Ptr`.+                | FFIFunPtr -- ^ `FunPtr`.++-- | For those types represented by pointers on the C side, return the+-- type of pointer which represents them on the Haskell FFI.+typePtrType :: Type -> CodeGen (Maybe FFIPtrType)+typePtrType (TBasicType TPtr) = return (Just FFIPtr)+typePtrType (TBasicType TUTF8) = return (Just FFIPtr)+typePtrType (TBasicType TFileName) = return (Just FFIPtr)+typePtrType t = do+  ft <- foreignType t+  case typeConName ft of+    "Ptr"    -> return (Just FFIPtr)+    "FunPtr" -> return (Just FFIFunPtr)+    _        -> return Nothing++-- | If the passed in type is nullable, return the conversion function+-- between the FFI pointer type (may be a `Ptr` or a `FunPtr`) and the+-- corresponding `Maybe` type.+maybeNullConvert :: Type -> CodeGen (Maybe Text)+maybeNullConvert (TBasicType TPtr) = return Nothing+maybeNullConvert (TGList _) = return Nothing+maybeNullConvert (TGSList _) = return Nothing+maybeNullConvert t = do+  pt <- typePtrType t+  case pt of+    Just FFIPtr -> return (Just "SP.convertIfNonNull")+    Just FFIFunPtr -> return (Just "SP.convertFunPtrIfNonNull")+    Nothing -> return Nothing++-- | An appropriate NULL value for the given type, for types which are+-- represented by pointers on the C side.+nullPtrForType :: Type -> CodeGen (Maybe Text)+nullPtrForType t = do+  pt <- typePtrType t+  case pt of+    Just FFIPtr -> return (Just "FP.nullPtr")+    Just FFIFunPtr -> return (Just "FP.nullFunPtr")+    Nothing -> return Nothing++-- | Returns whether the given type should be represented by a+-- `Maybe` type on the Haskell side. This applies to all properties+-- which have a C representation in terms of pointers, except for+-- G(S)Lists, for which NULL is a valid G(S)List, and raw pointers,+-- which we just pass through to the Haskell side. Notice that+-- introspection annotations can override this.+typeIsNullable :: Type -> CodeGen Bool+typeIsNullable t = isJust <$> maybeNullConvert t++-- | If the given type maps to a list in Haskell, return the type of the+-- elements, and the function that maps over them.+elementTypeAndMap :: Type -> Text -> Maybe (Type, Text)+-- ByteString+elementTypeAndMap (TCArray _ _ _ (TBasicType TUInt8)) _ = Nothing+elementTypeAndMap (TCArray True _ _ t) _ = Just (t, "mapZeroTerminatedCArray")+elementTypeAndMap (TCArray _ _ _ TGValue) len =+  Just (TGValue, parenthesize $ "B.GValue.mapGValueArrayWithLength " <> len)+elementTypeAndMap (TCArray False (-1) _ t) len =+  Just (t, parenthesize $ "mapCArrayWithLength " <> len)+elementTypeAndMap (TCArray False fixed _ t) _ =+  Just (t, parenthesize $ "mapCArrayWithLength " <> tshow fixed)+elementTypeAndMap (TGArray t) _ = Just (t, "mapGArray")+elementTypeAndMap (TPtrArray t) _ = Just (t, "mapPtrArray")+elementTypeAndMap (TGList t) _ = Just (t, "mapGList")+elementTypeAndMap (TGSList t) _ = Just (t, "mapGSList")+-- GHashTable is treated separately, see Transfer.hs+elementTypeAndMap _ _ = Nothing++-- Return just the element type.+elementType :: Type -> Maybe Type+elementType t = fst <$> elementTypeAndMap t undefined++-- Return just the map.+elementMap :: Type -> Text -> Maybe Text+elementMap t len = snd <$> elementTypeAndMap t len
lib/Data/GI/CodeGen/CtoHaskellMap.hs view
@@ -125,7 +125,7 @@                 Nothing -> let Name ns owner = n                            in ucFirst ns <> owner           in (SignalRef ownerCName sn,-              ModuleLinkWithAnchor (Just sn') mod ("signal:" <> sn'))+              ModuleLinkWithAnchor (Just sn') mod ("g:signal:" <> sn'))  -- | Given an optional C type and the API constructor construct the -- list of associated refs.
lib/Data/GI/CodeGen/EnumFlags.hs view
@@ -92,13 +92,20 @@   let name' = upperName n    group $ do+    line $ "type instance O.ParentTypes " <> name' <> " = '[]"+    bline $ "instance O.HasParentTypes " <> name'++  group $ do     line $ "foreign import ccall \"" <> typeInit <> "\" c_" <>             typeInit <> " :: "     indent $ line "IO GType"   group $ do-       bline $ "instance BoxedEnum " <> name' <> " where"-       indent $ line $ "boxedEnumType _ = c_" <> typeInit+       bline $ "instance B.Types.TypedObject " <> name' <> " where"+       indent $ line $ "glibType = c_" <> typeInit +  group $ do+    bline $ "instance B.Types.BoxedEnum " <> name'+ genEnum :: Name -> Enumeration -> CodeGen () genEnum n@(Name _ name) enum = do   line $ "-- Enum " <> name@@ -117,12 +124,19 @@   let name' = upperName n    group $ do+    line $ "type instance O.ParentTypes " <> name' <> " = '[]"+    bline $ "instance O.HasParentTypes " <> name'++  group $ do     line $ "foreign import ccall \"" <> typeInit <> "\" c_" <>             typeInit <> " :: "     indent $ line "IO GType"   group $ do-       bline $ "instance BoxedFlags " <> name' <> " where"-       indent $ line $ "boxedFlagsType _ = c_" <> typeInit+       bline $ "instance B.Types.TypedObject " <> name' <> " where"+       indent $ line $ "glibType = c_" <> typeInit++  group $ do+    bline $ "instance B.Types.BoxedFlags " <> name'  -- | Very similar to enums, but we also declare ourselves as members of -- the IsGFlag typeclass.
lib/Data/GI/CodeGen/Fixups.hs view
@@ -5,8 +5,10 @@     , detectGObject     , dropDuplicatedFields     , checkClosureDestructors+    , fixSymbolNaming     ) where +import Data.Char (generalCategory, GeneralCategory(UppercaseLetter)) import Data.Maybe (isNothing, isJust) #if !MIN_VERSION_base(4,13,0) import Data.Monoid ((<>))@@ -185,3 +187,27 @@         checkArg arg = if argDestroy arg >= 0 && argClosure arg == -1                        then arg {argDestroy = -1}                        else arg++-- | Some symbols have names that are not valid Haskell identifiers,+-- fix that here.+fixSymbolNaming :: (Name, API) -> (Name, API)+fixSymbolNaming (n, APIConst c) = (fixConstantName n, APIConst c)+fixSymbolNaming (n, api) = (n, api)++-- | Make sure that the given name is a valid Haskell identifier in+-- patterns.+--+-- === __Examples__+-- >>> fixConstantName (Name "IBus" "0")+-- Name {namespace = "IBus", name = "C'0"}+--+-- >>> fixConstantName (Name "IBus" "a")+-- Name {namespace = "IBus", name = "C'a"}+--+-- >>> fixConstantName (Name "IBus" "A")+-- Name {namespace = "IBus", name = "A"}+fixConstantName :: Name -> Name+fixConstantName (Name ns n)+  | not (T.null n) && generalCategory (T.head n) /= UppercaseLetter+  = Name ns ("C'" <> n)+  | otherwise = Name ns n
lib/Data/GI/CodeGen/GObject.hs view
@@ -32,6 +32,7 @@            or <$> mapM (uncurry (apiDoParentSearch parent)) prereqs       _ -> return False +-- | Check whether the given type descends from GObject. isGObject :: Type -> CodeGen Bool isGObject = typeDoParentSearch $ Name "GObject" "Object" @@ -39,5 +40,6 @@ nameIsGObject :: Name -> CodeGen Bool nameIsGObject n = findAPIByName n >>= apiIsGObject n +-- | Check whether the given API descends from GObject. apiIsGObject :: Name -> API -> CodeGen Bool apiIsGObject = apiDoParentSearch $ Name "GObject" "Object"
lib/Data/GI/CodeGen/Haddock.hs view
@@ -81,7 +81,7 @@ formatUnknownCRef _ (ParamRef p) = "/@" <> lowerSymbol p <> "@/" formatUnknownCRef _ (LocalSignalRef s) =   let sn = signalHaskellName s-  in "[" <> sn <> "](#signal:" <> sn <> ")"+  in "[" <> sn <> "](#g:signal:" <> sn <> ")" formatUnknownCRef c2h (SignalRef owner signal) =   case M.lookup (TypeRef owner) c2h of     Nothing -> formatCRef $ owner <> "::" <> signal
lib/Data/GI/CodeGen/LibGIRepository.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies, DataKinds #-} -- | A minimal wrapper for libgirepository. module Data.GI.CodeGen.LibGIRepository     ( girRequire@@ -29,9 +30,11 @@ import System.FilePath (searchPathSeparator)  import Data.GI.Base.BasicConversions (withTextCString, cstringToText)-import Data.GI.Base.BasicTypes (BoxedObject(..), GType(..), CGType, ManagedPtr)+import Data.GI.Base.BasicTypes (TypedObject(..), GBoxed,+                                GType(..), CGType, ManagedPtr) import Data.GI.Base.GError (GError, checkGError) import Data.GI.Base.ManagedPtr (wrapBoxed, withManagedPtr)+import Data.GI.Base.Overloading (HasParentTypes, ParentTypes) import Data.GI.Base.Utils (allocMem, freeMem) import Data.GI.CodeGen.Util (splitOn) @@ -55,10 +58,18 @@       fieldInfoOffset    :: Int     } +-- | The (empty) set of parent types for `BaseInfo` visible to the+-- Haskell type system.+instance HasParentTypes BaseInfo+type instance ParentTypes BaseInfo = '[]+ foreign import ccall "g_base_info_gtype_get_type" c_g_base_info_gtype_get_type :: IO GType -instance BoxedObject BaseInfo where-    boxedType _ = c_g_base_info_gtype_get_type+instance TypedObject BaseInfo where+  glibType = c_g_base_info_gtype_get_type++-- | `BaseInfo`s are registered as boxed in the GLib type system.+instance GBoxed BaseInfo  foreign import ccall "g_irepository_prepend_search_path" g_irepository_prepend_search_path :: CString -> IO () 
lib/Data/GI/CodeGen/Properties.hs view
@@ -44,6 +44,7 @@    TParamSpec -> return "ParamSpec"    TGClosure _ -> return "Closure"    TError -> return "GError"+   TGValue -> return "GValue"    TBasicType TInt -> case sizeOf (0 :: CInt) of                         4 -> return "Int32"                         n -> error ("Unsupported `gint' type length: " ++
lib/Data/GI/CodeGen/Signal.hs view
@@ -331,8 +331,8 @@                line $ "return " <> result'  genCallback :: Name -> Callback -> CodeGen ()-genCallback n (Callback {cbCallable = cb, cbDocumentation = cbDoc }) = do-  let name' = upperName n+genCallback n callback@(Callback {cbCallable = cb, cbDocumentation = cbDoc }) = do+  let Name _ name' = normalizedAPIName (APICallback callback) n       cb' = fixupCallerAllocates cb    line $ "-- callback " <> name'
lib/Data/GI/CodeGen/Struct.hs view
@@ -5,6 +5,7 @@                               , extractCallbacksInStruct                               , fixAPIStructs                               , ignoreStruct+                              , genBoxed                               , genWrappedPtr                               ) where @@ -455,7 +456,7 @@       line $ builder <> " = liftIO $ " <>            if isBoxed            then "callocBoxedBytes " <> tsize <> " >>= wrapBoxed " <> name-           else "wrappedPtrCalloc >>= wrapPtr " <> name+           else "boxedPtrCalloc >>= wrapPtr " <> name       exportDecl builder        blank@@ -491,57 +492,102 @@            <> " :: " <> prototype   return (prefix <> symbol) --- | Same as `prefixedForeignImport`, but import a `FunPtr` to the symbol.-prefixedFunPtrImport :: Text -> Text -> Text -> CodeGen Text-prefixedFunPtrImport prefix symbol prototype = group $ do-  line $ "foreign import ccall \"&" <> symbol <> "\" " <> prefix <> symbol-           <> " :: FunPtr (" <> prototype <> ")"-  return (prefix <> symbol)+-- | Generate a GValue instance for @GBoxed@ objects.+genBoxedGValueInstance :: Name -> Text -> CodeGen ()+genBoxedGValueInstance n get_type_fn = do+  let name' = upperName n+      doc = "Convert '" <> name' <> "' to and from 'Data.GI.Base.GValue.GValue' with 'Data.GI.Base.GValue.toGValue' and 'Data.GI.Base.GValue.fromGValue'." +  writeHaddock DocBeforeSymbol doc++  group $ do+    bline $ "instance B.GValue.IsGValue " <> name' <> " where"+    indent $ group $ do+      line $ "toGValue o = do"+      indent $ group $ do+        line $ "gtype <- " <> get_type_fn+        line $ "B.ManagedPtr.withManagedPtr o (B.GValue.buildGValue gtype B.GValue.set_boxed)"+      line $ "fromGValue gv = do"+      indent $ group $ do+        line $ "ptr <- B.GValue.get_boxed gv :: IO (Ptr " <> name' <> ")"+        line $ "B.ManagedPtr.newBoxed " <> name' <> " ptr"++-- | Allocation and deallocation for types registered as `GBoxed` in+-- the GLib type system.+genBoxed :: Name -> Text -> CodeGen ()+genBoxed n typeInit = do+  let name' = upperName n+      get_type_fn = "c_" <> typeInit++  group $ do+    line $ "foreign import ccall \"" <> typeInit <> "\" " <>+            get_type_fn <> " :: "+    indent $ line "IO GType"++  group $ do+    line $ "type instance O.ParentTypes " <> name' <> " = '[]"+    bline $ "instance O.HasParentTypes " <> name'++  group $ do+    bline $ "instance B.Types.TypedObject " <> name' <> " where"+    indent $ line $ "glibType = " <> get_type_fn++  group $ do+    bline $ "instance B.Types.GBoxed " <> name'++  genBoxedGValueInstance n get_type_fn+ -- | Generate the typeclass with information for how to--- allocate/deallocate a given type.+-- allocate/deallocate a given type which is not a `GBoxed`. genWrappedPtr :: Name -> AllocationInfo -> Int -> CodeGen () genWrappedPtr n info size = group $ do-  let name' = upperName n-   let prefix = \op -> "_" <> name' <> "_" <> op <> "_"    when (size == 0 && allocFree info == AllocationOpUnknown) $        line $ "-- XXX Wrapping a foreign struct/union with no known destructor or size, leak?" -  calloc <- case allocCalloc info of-              AllocationOp "none" ->-                  return ("error \"calloc not permitted for " <> name' <> "\"")-              AllocationOp op ->-                  prefixedForeignImport (prefix "calloc") op "IO (Ptr a)"-              AllocationOpUnknown ->-                  if size > 0-                  then return ("callocBytes " <> tshow size)-                  else return "return nullPtr"-   copy <- case allocCopy info of             AllocationOp op -> do                 copy <- prefixedForeignImport (prefix "copy") op "Ptr a -> IO (Ptr a)"-                return ("\\p -> withManagedPtr p (" <> copy <>-                        " >=> wrapPtr " <> name' <> ")")+                return ("\\p -> B.ManagedPtr.withManagedPtr p (" <> copy <>+                        " >=> B.ManagedPtr.wrapPtr " <> name' <> ")")             AllocationOpUnknown ->                 if size > 0-                then return ("\\p -> withManagedPtr p (copyBytes "-                              <> tshow size <> " >=> wrapPtr " <> name' <> ")")+                then return ("\\p -> B.ManagedPtr.withManagedPtr p (copyBytes "+                              <> tshow size <>+                              " >=> B.ManagedPtr.wrapPtr " <> name' <> ")")                 else return "return"    free <- case allocFree info of-            AllocationOp op -> ("Just " <>) <$>-                prefixedFunPtrImport (prefix "free") op "Ptr a -> IO ()"+            AllocationOp op -> do+              free <- prefixedForeignImport (prefix "free") op "Ptr a -> IO ()"+              return $ "\\p -> B.ManagedPtr.withManagedPtr p " <> free             AllocationOpUnknown ->                 if size > 0-                then return "Just ptr_to_g_free"-                else return "Nothing"+                then return "\\x -> SP.withManagedPtr x SP.freeMem"+                else return "\\_x -> return ()" -  line $ "instance WrappedPtr " <> name' <> " where"+  bline $ "instance BoxedPtr " <> name' <> " where"   indent $ do-      line $ "wrappedPtrCalloc = " <> calloc-      line $ "wrappedPtrCopy = " <> copy-      line $ "wrappedPtrFree = " <> free+      line $ "boxedPtrCopy = " <> copy+      line $ "boxedPtrFree = " <> free -  hsBoot $ line $ "instance WrappedPtr " <> name' <> " where"+  case allocCalloc info of+    AllocationOp "none" -> return ()+    AllocationOp op -> do+      calloc <- prefixedForeignImport (prefix "calloc") op "IO (Ptr a)"+      callocInstance calloc+    AllocationOpUnknown ->+      if size > 0+      then do+        let calloc = "callocBytes " <> tshow size+        callocInstance calloc+      else return ()++  where name' = upperName n++        callocInstance :: Text -> CodeGen()+        callocInstance calloc = group $ do+          bline $ "instance CallocPtr " <> name' <> " where"+          indent $ do+            line $ "boxedPtrCalloc = " <> calloc
lib/Data/GI/CodeGen/SymbolNaming.hs view
@@ -3,7 +3,6 @@     ( lowerName     , lowerSymbol     , upperName-    , noName     , escapedArgName      , classConstraint@@ -27,6 +26,7 @@     , submoduleLocation     , qualifiedAPI     , qualifiedSymbol+    , normalizedAPIName     ) where  #if !MIN_VERSION_base(4,11,0)@@ -36,8 +36,7 @@ import qualified Data.Text as T  import Data.GI.CodeGen.API-import Data.GI.CodeGen.Code (CodeGen, group, line, exportDecl,-                             qualified, getAPI)+import Data.GI.CodeGen.Code (CodeGen, qualified, getAPI) import Data.GI.CodeGen.ModulePath (ModulePath, (/.), toModulePath) import Data.GI.CodeGen.Type (Type(TInterface)) import Data.GI.CodeGen.Util (lcFirst, ucFirst, modifyQualified)@@ -147,29 +146,31 @@ submoduleLocation n (APIStruct _) = "Structs" /. upperName n submoduleLocation n (APIUnion _) = "Unions" /. upperName n +-- | Construct the Haskell version of the name associated to the given+-- API.+normalizedAPIName :: API -> Name -> Name+normalizedAPIName (APIConst _) (Name ns name) = Name ns (ucFirst name)+normalizedAPIName (APIFunction _) n = n+normalizedAPIName (APICallback _) n@(Name ns _) = Name ns (upperName n)+normalizedAPIName (APIEnum _) n@(Name ns _) = Name ns (upperName n)+normalizedAPIName (APIFlags _) n@(Name ns _) = Name ns (upperName n)+normalizedAPIName (APIInterface _) n@(Name ns _) = Name ns (upperName n)+normalizedAPIName (APIObject _) n@(Name ns _) = Name ns (upperName n)+normalizedAPIName (APIStruct _) n@(Name ns _) = Name ns (upperName n)+normalizedAPIName (APIUnion _) n@(Name ns _) = Name ns (upperName n)+ -- | Return an identifier for the given interface type valid in the current -- module.-qualifiedAPI :: Name -> CodeGen Text-qualifiedAPI n@(Name ns _) = do-  api <- getAPI (TInterface n)-  qualified (toModulePath (ucFirst ns) <> submoduleLocation n api) n+qualifiedAPI :: API -> Name -> CodeGen Text+qualifiedAPI api n@(Name ns _) =+  let normalized = normalizedAPIName api n+  in qualified (toModulePath (ucFirst ns) <> submoduleLocation n api) normalized  -- | Construct an identifier for the given symbol in the given API. qualifiedSymbol :: Text -> Name -> CodeGen Text qualifiedSymbol s n@(Name ns _) = do   api <- getAPI (TInterface n)   qualified (toModulePath (ucFirst ns) <> submoduleLocation n api) (Name ns s)---- | Save a bit of typing for optional arguments in the case that we--- want to pass Nothing.-noName :: Text -> CodeGen ()-noName name' = group $ do-  -- We should use `writeHaddock` here, but it would give rise to a-  -- cyclic import.-  line $ "-- | A convenience alias for `Nothing` :: `Maybe` `" <> name' <> "`."-  line $ "no" <> name' <> " :: Maybe " <> name'-  line $ "no" <> name' <> " = Nothing"-  exportDecl ("no" <> name')  -- | Turn a hyphen-separated identifier into camel case. --
lib/Data/GI/CodeGen/Transfer.hs view
@@ -43,6 +43,7 @@ basicFreeFn (TGHash _ _) = Just "unrefGHashTable" basicFreeFn (TError) = Nothing basicFreeFn (TVariant) = Nothing+basicFreeFn (TGValue) = Just "B.GValue.unsetGValue" basicFreeFn (TParamSpec) = Nothing basicFreeFn (TGClosure _) = Nothing @@ -61,6 +62,10 @@ basicFreeFnOnError TParamSpec transfer =     return $ if transfer == TransferEverything              then Just "unrefGParamSpec"+             else Nothing+basicFreeFnOnError TGValue transfer =+    return $ if transfer == TransferEverything+             then Just "SP.freeMem"              else Nothing basicFreeFnOnError (TGClosure _) transfer =     return $ if transfer == TransferEverything
lib/Data/GI/GIR/BasicTypes.hs view
@@ -54,6 +54,7 @@     = TBasicType BasicType     | TError           -- ^ GError     | TVariant         -- ^ GVariant+    | TGValue          -- ^ GValue     | TParamSpec       -- ^ GParamSpec     | TCArray Bool Int Int Type  -- ^ Zero terminated, Array Fixed                                  -- Size, Array Length, Element Type
lib/Data/GI/GIR/Object.hs view
@@ -17,6 +17,8 @@     objTypeInit :: Text,     objTypeName :: Text,     objCType :: Maybe Text,+    objRefFunc :: Maybe Text,+    objUnrefFunc :: Maybe Text,     objInterfaces :: [Name],     objDeprecated :: Maybe DeprecationInfo,     objDocumentation :: Documentation,@@ -39,12 +41,17 @@   typeInit <- getAttrWithNamespace GLibGIRNS "get-type"   typeName <- getAttrWithNamespace GLibGIRNS "type-name"   signals <- parseChildrenWithNSName GLibGIRNS "signal" parseSignal+  refFunc <- queryAttrWithNamespace GLibGIRNS "ref-func"+  unrefFunc <- queryAttrWithNamespace GLibGIRNS "unref-func"+   ctype <- queryCType   return (name,          Object {             objParent = parent           , objTypeInit = typeInit           , objCType = ctype+          , objRefFunc = refFunc+          , objUnrefFunc = unrefFunc           , objTypeName = typeName           , objInterfaces = interfaces           , objDeprecated = deprecated
lib/Data/GI/GIR/Type.hs view
@@ -120,6 +120,7 @@ parseFundamentalType "GLib" "Error" = return TError parseFundamentalType "GLib" "Variant" = return TVariant parseFundamentalType "GObject" "ParamSpec" = return TParamSpec+parseFundamentalType "GObject" "Value" = return TGValue parseFundamentalType "GObject" "Closure" = parseClosure -- A TInterface type (basically, everything that is not of a known type). parseFundamentalType ns n = resolveQualifiedTypeName (Name ns n)