packages feed

haskell-gi 0.20.2 → 0.20.3

raw patch · 13 files changed

+379/−312 lines, 13 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.GI.CodeGen.Code: Group :: Code -> Code
- Data.GI.CodeGen.Code: Indent :: Code -> Code
- Data.GI.CodeGen.Code: Line :: Text -> Code
- Data.GI.CodeGen.Code: ModuleInfo :: ModulePath -> Code -> Code -> Map Text ModuleInfo -> Deps -> Seq Export -> Set ModulePath -> Set Text -> Set Text -> Set ModuleFlag -> Maybe Text -> BaseVersion -> ModuleInfo
- Data.GI.CodeGen.Code: NoCode :: Code
- Data.GI.CodeGen.Code: Sequence :: (Seq Code) -> Code
- Data.GI.CodeGen.Code: [bootCode] :: ModuleInfo -> Code
- Data.GI.CodeGen.Code: [moduleCode] :: ModuleInfo -> Code
- Data.GI.CodeGen.Code: [moduleDeps] :: ModuleInfo -> Deps
- Data.GI.CodeGen.Code: [moduleDoc] :: ModuleInfo -> Maybe Text
- Data.GI.CodeGen.Code: [moduleExports] :: ModuleInfo -> Seq Export
- Data.GI.CodeGen.Code: [moduleFlags] :: ModuleInfo -> Set ModuleFlag
- Data.GI.CodeGen.Code: [moduleGHCOpts] :: ModuleInfo -> Set Text
- Data.GI.CodeGen.Code: [moduleMinBase] :: ModuleInfo -> BaseVersion
- Data.GI.CodeGen.Code: [modulePath] :: ModuleInfo -> ModulePath
- Data.GI.CodeGen.Code: [modulePragmas] :: ModuleInfo -> Set Text
- Data.GI.CodeGen.Code: [qualifiedImports] :: ModuleInfo -> Set ModulePath
- Data.GI.CodeGen.Code: [submodules] :: ModuleInfo -> Map Text ModuleInfo
- Data.GI.CodeGen.Config: CodeGenFlags :: Bool -> Bool -> Bool -> CodeGenFlags
- Data.GI.CodeGen.Config: [cgFlags] :: Config -> CodeGenFlags
- Data.GI.CodeGen.Config: [cgOverloadedMethods] :: CodeGenFlags -> Bool
- Data.GI.CodeGen.Config: [cgOverloadedProperties] :: CodeGenFlags -> Bool
- Data.GI.CodeGen.Config: [cgOverloadedSignals] :: CodeGenFlags -> Bool
- Data.GI.CodeGen.Config: data CodeGenFlags
- Data.GI.CodeGen.Config: instance GHC.Show.Show Data.GI.CodeGen.Config.CodeGenFlags
+ Data.GI.CodeGen.Cabal: tryPkgConfig :: GIRInfo -> Bool -> Map Text Text -> IO (Either Text PkgInfo)
+ Data.GI.CodeGen.Code: CPPOverloading :: CPPGuard
+ Data.GI.CodeGen.Code: cppIf :: CPPGuard -> BaseCodeGen e a -> BaseCodeGen e a
+ Data.GI.CodeGen.Code: data CPPGuard
+ Data.GI.CodeGen.Code: increaseIndent :: CodeGen ()
+ Data.GI.CodeGen.Code: instance GHC.Classes.Eq Data.GI.CodeGen.Code.CPPConditional
+ Data.GI.CodeGen.Code: instance GHC.Classes.Eq Data.GI.CodeGen.Code.CodeToken
+ Data.GI.CodeGen.Code: instance GHC.Classes.Ord Data.GI.CodeGen.Code.CPPConditional
+ Data.GI.CodeGen.Code: instance GHC.Classes.Ord Data.GI.CodeGen.Code.Code
+ Data.GI.CodeGen.Code: instance GHC.Classes.Ord Data.GI.CodeGen.Code.CodeToken
+ Data.GI.CodeGen.Code: instance GHC.Show.Show Data.GI.CodeGen.Code.CPPConditional
+ Data.GI.CodeGen.Code: instance GHC.Show.Show Data.GI.CodeGen.Code.CodeToken
+ Data.GI.CodeGen.Conversions: transientToH :: Type -> Transfer -> ExcCodeGen Converter
- Data.GI.CodeGen.Cabal: genCabalProject :: GIRInfo -> [GIRInfo] -> [Text] -> BaseVersion -> CodeGen (Maybe Text)
+ Data.GI.CodeGen.Cabal: genCabalProject :: (GIRInfo, PkgInfo) -> [(GIRInfo, PkgInfo)] -> [Text] -> BaseVersion -> CodeGen ()
- Data.GI.CodeGen.Code: evalCodeGen :: Config -> Map Name API -> ModulePath -> CodeGen a -> IO (a, ModuleInfo)
+ Data.GI.CodeGen.Code: evalCodeGen :: Config -> Map Name API -> ModulePath -> CodeGen a -> (a, ModuleInfo)
- Data.GI.CodeGen.Code: genCode :: Config -> Map Name API -> ModulePath -> CodeGen () -> IO ModuleInfo
+ Data.GI.CodeGen.Code: genCode :: Config -> Map Name API -> ModulePath -> CodeGen () -> ModuleInfo
- Data.GI.CodeGen.Code: type BaseCodeGen excType a = ReaderT CodeGenConfig (StateT ModuleInfo (ExceptT excType IO)) a
+ Data.GI.CodeGen.Code: type BaseCodeGen excType a = ReaderT CodeGenConfig (StateT (CGState, ModuleInfo) (Except excType)) a
- Data.GI.CodeGen.Config: Config :: Text -> Bool -> Overrides -> CodeGenFlags -> Config
+ Data.GI.CodeGen.Config: Config :: Text -> Bool -> Overrides -> Config

Files

ChangeLog.md view
@@ -1,3 +1,9 @@+### 0.20.3+++ Make the overloading code protected by a CPP conditional, depending on ENABLE_OVERLOADING being defined. See [issue 107](https://github.com/haskell-gi/haskell-gi/issues/107).+++ Wrap boxed structs/unions as transient [ManagedPtr](https://hackage.haskell.org/package/haskell-gi-base/docs/Data-GI-Base-BasicTypes.html#t:ManagedPtr)s in callbacks. This is needed to fix a number of issues, including [issue 96](https://github.com/haskell-gi/haskell-gi/issues/96) and [issue 97](https://github.com/haskell-gi/haskell-gi/issues/97).+ ### 0.20.2  + Fixes for GHC 8.2.1.
cmdline/haskell-gi.hs view
@@ -3,7 +3,7 @@ #if !MIN_VERSION_base(4,8,0) import Data.Traversable (traverse) #endif-import Control.Monad (forM_, when, (>=>))+import Control.Monad (forM_, forM, when, (>=>)) import Control.Exception (handle) import Control.Applicative ((<|>)) @@ -28,17 +28,17 @@ import Text.Show.Pretty (ppShow)  import Data.GI.CodeGen.API (loadGIRInfo, loadRawGIRInfo, GIRInfo(girAPIs, girNSName), Name, API)-import Data.GI.CodeGen.Cabal (cabalConfig, setupHs, genCabalProject)-import Data.GI.CodeGen.Code (genCode, evalCodeGen, transitiveModuleDeps, writeModuleTree, moduleCode, codeToText, minBaseVersion)-import Data.GI.CodeGen.Config (Config(..), CodeGenFlags(..))+import Data.GI.CodeGen.Cabal (cabalConfig, setupHs, genCabalProject, tryPkgConfig)+import Data.GI.CodeGen.Code (genCode, transitiveModuleDeps, writeModuleTree, moduleCode, codeToText, minBaseVersion)+import Data.GI.CodeGen.Config (Config(..)) import Data.GI.CodeGen.CodeGen (genModule) import Data.GI.CodeGen.LibGIRepository (setupTypelibSearchPath) import Data.GI.CodeGen.ModulePath (toModulePath) import Data.GI.CodeGen.OverloadedLabels (genOverloadedLabels) import Data.GI.CodeGen.OverloadedSignals (genOverloadedSignalConnectors)-import Data.GI.CodeGen.Overrides (Overrides, parseOverridesFile, nsChooseVersion, filterAPIsAndDeps, girFixups)+import Data.GI.CodeGen.Overrides (Overrides, parseOverridesFile, nsChooseVersion, filterAPIsAndDeps, girFixups, pkgConfigMap) import Data.GI.CodeGen.ProjectInfo (licenseText)-import Data.GI.CodeGen.Util (ucFirst, utf8ReadFile, utf8WriteFile)+import Data.GI.CodeGen.Util (ucFirst, utf8ReadFile, utf8WriteFile, terror)  data Mode = GenerateCode | Dump | Labels | Signals | Help @@ -134,14 +134,6 @@   gir <- loadRawGIRInfo verbose nameWithoutVersion version extraPaths   return (girAPIs gir) --- | Set up the flags for the code generator.-genFlags :: Options -> CodeGenFlags-genFlags opts = CodeGenFlags {-                  cgOverloadedProperties = optOvProperties opts-                , cgOverloadedSignals = optOvSignals opts-                , cgOverloadedMethods = optOvMethods opts-                }- -- | Generate overloaded labels ("_label", for example). genLabels :: Options -> Overrides -> [Text] -> [FilePath] -> IO () genLabels options ovs modules extraPaths = do@@ -149,12 +141,11 @@   let allAPIs = M.unions (map M.fromList apis)       cfg = Config {modName = "<<GI autogenerated labels>>",                     verbose = optVerbose options,-                    overrides = ovs,-                    cgFlags = genFlags options+                    overrides = ovs                    }   putStrLn $ "\t* Generating GI.OverloadedLabels"-  m <- genCode cfg allAPIs  "OverloadedLabels"-       (genOverloadedLabels (M.toList allAPIs))+  let m = genCode cfg allAPIs  "OverloadedLabels"+        (genOverloadedLabels (M.toList allAPIs))   _ <- writeModuleTree (optVerbose options) (optOutputDir options) m   return () @@ -165,11 +156,9 @@   let allAPIs = M.unions (map M.fromList apis)       cfg = Config {modName = "<<GI autogenerated connectors>>",                     verbose = optVerbose options,-                    overrides = ovs,-                    cgFlags = genFlags options-                   }+                    overrides = ovs}   putStrLn $ "\t* Generating GI.Signals"-  m <- genCode cfg allAPIs "Signals" (genOverloadedSignalConnectors (M.toList allAPIs))+  let m = genCode cfg allAPIs "Signals" (genOverloadedSignalConnectors (M.toList allAPIs))   _ <- writeModuleTree (optVerbose options) (optOutputDir options) m   return () @@ -180,9 +169,7 @@   let (nameWithoutVersion, version) = solveNameVersion ovs name       cfg = Config {modName = nameWithoutVersion,                     verbose = optVerbose options,-                    overrides = ovs,-                    cgFlags = genFlags options-                   }+                    overrides = ovs}       nm = ucFirst nameWithoutVersion       mp = T.unpack . ("GI." <>) @@ -192,9 +179,9 @@                     (girFixups ovs)   let (apis, deps) = filterAPIsAndDeps ovs gir girDeps       allAPIs = M.union apis deps+      m = genCode cfg allAPIs (toModulePath nm) (genModule apis)+      modDeps = transitiveModuleDeps m -  m <- genCode cfg allAPIs (toModulePath nm) (genModule apis)-  let modDeps = transitiveModuleDeps m   moduleList <- writeModuleTree (optVerbose options) (optOutputDir options) m    when (optCabal options) $ do@@ -204,6 +191,13 @@                   (putStrLn (cabal ++ " exists, writing "                              ++ cabal ++ ".new instead") >>                    return (cabal ++ ".new"))++    let pkMap = pkgConfigMap (overrides cfg)++    pkgInfo <- tryPkgConfig gir (verbose cfg) pkMap >>= \case+        Left err -> terror err+        Right info -> return info+     -- The module is not a dep of itself     let usedDeps = S.delete nameWithoutVersion modDeps         -- We only list as dependencies in the cabal file the@@ -211,20 +205,23 @@         actualDeps = filter ((`S.member` usedDeps) . girNSName) girDeps         baseVersion = minBaseVersion m         p = \n -> joinPath [fromMaybe "" (optOutputDir options), n]-    (err, m) <- evalCodeGen cfg allAPIs (error "undefined module path")-                (genCabalProject gir actualDeps moduleList baseVersion)-    case err of-      Nothing -> do-               putStrLn $ "\t\t+ " ++ fname-               utf8WriteFile (p fname) (codeToText (moduleCode m))-               putStrLn "\t\t+ cabal.config"-               utf8WriteFile (p "cabal.config") cabalConfig-               putStrLn "\t\t+ Setup.hs"-               utf8WriteFile (p "Setup.hs") setupHs-               putStrLn "\t\t+ LICENSE"-               utf8WriteFile (p "LICENSE") licenseText-      Just msg -> putStrLn $ "ERROR: could not generate " ++ fname-                  ++ "\nError was: " ++ T.unpack msg++    resolvedDeps <- forM actualDeps $ \dep -> do+      tryPkgConfig dep (verbose cfg) pkMap >>= \case+        Left err -> terror err+        Right info -> return (dep, info)++    let m = genCode cfg allAPIs (error "undefined module path")+            (genCabalProject (gir, pkgInfo) resolvedDeps moduleList baseVersion)++    putStrLn $ "\t\t+ " ++ fname+    utf8WriteFile (p fname) (codeToText (moduleCode m))+    putStrLn "\t\t+ cabal.config"+    utf8WriteFile (p "cabal.config") cabalConfig+    putStrLn "\t\t+ Setup.hs"+    utf8WriteFile (p "Setup.hs") setupHs+    putStrLn "\t\t+ LICENSE"+    utf8WriteFile (p "LICENSE") licenseText  dump :: Options -> Overrides -> Text -> IO () dump options ovs name = do
haskell-gi.cabal view
@@ -1,5 +1,5 @@ name:                haskell-gi-version:             0.20.2+version:             0.20.3 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.
lib/Data/GI/CodeGen/Cabal.hs view
@@ -2,27 +2,25 @@     ( genCabalProject     , cabalConfig     , setupHs+    , tryPkgConfig     ) where  #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>), (<*>)) #endif import Control.Monad (forM_)-import Control.Monad.IO.Class (liftIO) import Data.Maybe (fromMaybe) import Data.Monoid ((<>)) import Data.Version (Version(..)) import qualified Data.Map as M import qualified Data.Text as T-import qualified Data.Text.IO as TIO import Data.Text (Text) import Text.Read-import System.IO (stderr)  import Data.GI.CodeGen.API (GIRInfo(..)) import Data.GI.CodeGen.Code import Data.GI.CodeGen.Config (Config(..))-import Data.GI.CodeGen.Overrides (pkgConfigMap, cabalPkgVersion)+import Data.GI.CodeGen.Overrides (cabalPkgVersion) import Data.GI.CodeGen.PkgConfig (pkgConfigGetVersion) import qualified Data.GI.CodeGen.ProjectInfo as PI import Data.GI.CodeGen.Util (padTo, tshow)@@ -99,11 +97,13 @@  -- | Determine the pkg-config name and installed version (major.minor -- only) for a given module, or throw an exception if that fails.-tryPkgConfig :: Text -> Text -> [Text] -> Bool-             -> M.Map Text Text-             -> CodeGen (Either Text PkgInfo)-tryPkgConfig name version packages verbose overridenNames =-    liftIO (pkgConfigGetVersion name version packages verbose overridenNames) >>= \case+tryPkgConfig :: GIRInfo -> Bool -> M.Map Text Text -> IO (Either Text PkgInfo)+tryPkgConfig gir verbose overridenNames = do+  let name = girNSName gir+      version = girNSVersion gir+      packages = girPCPackages gir++  pkgConfigGetVersion name version packages verbose overridenNames >>= \case            Just (n,v) ->                case readMajorMinor v of                  Just (major, minor) ->@@ -126,27 +126,20 @@       (a:b:_) -> (,) <$> readMaybe (T.unpack a) <*> readMaybe (T.unpack b)       _ -> Nothing --- | Try to generate the cabal project. In case of error return the--- corresponding error string.-genCabalProject :: GIRInfo -> [GIRInfo] -> [Text] -> BaseVersion ->-                   CodeGen (Maybe Text)-genCabalProject gir deps exposedModules minBaseVersion = do+-- | Generate the cabal project.+genCabalProject :: (GIRInfo, PkgInfo) -> [(GIRInfo, PkgInfo)] ->+                   [Text] -> BaseVersion -> CodeGen ()+genCabalProject (gir, PkgInfo {pkgName = pcName, pkgMajor = major,+                               pkgMinor = minor})+  deps exposedModules minBaseVersion = do       cfg <- config-      let pkMap = pkgConfigMap (overrides cfg)-          name = girNSName gir-          pkgVersion = girNSVersion gir-          packages = girPCPackages gir+      let name = girNSName gir        line $ "-- Autogenerated, do not edit."       line $ padTo 20 "name:" <> "gi-" <> T.toLower name-      eitherPkgInfo <- tryPkgConfig name pkgVersion packages (verbose cfg) pkMap-      cabalVersion <- case eitherPkgInfo of-                        Left err -> do-                          liftIO $ TIO.hPutStrLn stderr $ "Warning: " <> err-                          return "0.0.1"-                        Right (PkgInfo _ major minor) ->-                          return $ fromMaybe (giModuleVersion major minor)-                                             (cabalPkgVersion $ overrides cfg)++      let cabalVersion = fromMaybe (giModuleVersion major minor)+                                    (cabalPkgVersion $ overrides cfg)       line $ padTo 20 "version:" <> cabalVersion       line $ padTo 20 "synopsis:" <> name                <> " bindings"@@ -172,35 +165,19 @@         line $ padTo 20 "exposed-modules:" <> head exposedModules         forM_ (tail exposedModules) $ \mod ->               line $ padTo 20 "" <> mod-        case eitherPkgInfo of-          Left _ -> do-            line $ padTo 20 "-- pkg-config info for the module not found:"-            line $ padTo 20 "-- pkgconfig-depends: XXX"-          Right (PkgInfo pcName major minor) ->-            line $ padTo 20 "pkgconfig-depends:" <> pcName <> " >= " <>-                   tshow major <> "." <> tshow minor+        line $ padTo 20 "pkgconfig-depends:" <> pcName <> " >= " <>+          tshow major <> "." <> tshow minor         line $ "build-depends:"         indent $ do           line $ "haskell-gi-base >= "                    <> tshow haskellGIAPIVersion <> "." <> tshow haskellGIMinor                    <> " && < " <> tshow (haskellGIAPIVersion + 1) <> ","-          forM_ deps $ \dep -> do+          forM_ deps $ \(dep, PkgInfo _ depMajor depMinor) -> do               let depName = girNSName dep-                  depVersion = girNSVersion dep-                  depPackages = girPCPackages dep-              eitherDepInfo <- tryPkgConfig depName depVersion-                                         depPackages (verbose cfg) pkMap-              case eitherDepInfo of-                Left err -> do-                  liftIO $ TIO.hPutStrLn stderr $ "Warning: " <> err-                  line $ "-- gi-" <> T.toLower depName <> " >= XXX & < YYY"-                Right (PkgInfo _ depMajor depMinor) ->-                  line $ "gi-" <> T.toLower depName <> " >= "-                       <> giModuleVersion depMajor depMinor-                       <> " && < "-                       <> giNextMinor depMajor depMinor-                       <> ","+              line $ "gi-" <> T.toLower depName <> " >= "+                <> giModuleVersion depMajor depMinor+                <> " && < "+                <> giNextMinor depMajor depMinor+                <> ","           forM_ PI.standardDeps (line . (<> ","))           line $ "base >= " <> showBaseVersion minBaseVersion <> " && <5"--      return Nothing -- successful generation, no error
lib/Data/GI/CodeGen/CabalHooks.hs view
@@ -20,7 +20,7 @@ import Data.GI.CodeGen.API (loadGIRInfo) import Data.GI.CodeGen.Code (genCode, writeModuleTree, listModuleTree) import Data.GI.CodeGen.CodeGen (genModule)-import Data.GI.CodeGen.Config (Config(..), CodeGenFlags(..))+import Data.GI.CodeGen.Config (Config(..)) import Data.GI.CodeGen.LibGIRepository (setupTypelibSearchPath) import Data.GI.CodeGen.ModulePath (toModulePath) import Data.GI.CodeGen.Overrides (parseOverridesFile, girFixups,@@ -28,7 +28,7 @@ import Data.GI.CodeGen.PkgConfig (tryPkgConfig) import Data.GI.CodeGen.Util (ucFirst, tshow, utf8ReadFile, utf8WriteFile) -import Control.Monad (when)+import Control.Monad (when, void)  import Data.Maybe (fromJust, fromMaybe) import qualified Data.Map as M@@ -79,23 +79,6 @@           flags' :: [(String, Bool)]           flags' = map (\(f, v) -> (unFlagName f, v)) flags --- | Parse the set of flags given to configure into flags for the code--- generator.-parseFlags :: [(FlagName, Bool)] -> CodeGenFlags-parseFlags fs = parsed-    where parsed :: CodeGenFlags-          parsed = CodeGenFlags {-                    cgOverloadedProperties = check "overloaded-properties"-                  , cgOverloadedSignals = check "overloaded-signals"-                  , cgOverloadedMethods = check "overloaded-methods"-                  }--          check :: String -> Bool-          check s = fromMaybe True (M.lookup s flags)--          flags :: M.Map String Bool-          flags = M.fromList (map (\(f, v) -> (unFlagName f, v)) fs)- -- | A convenience helper for `confHook`, such that bindings for the -- given module are generated in the @configure@ step of @cabal@. confCodeGenHook :: Text -- ^ name@@ -122,29 +105,26 @@       allAPIs = M.union apis deps       cfg = Config {modName = name,                     verbose = verbosity,-                    overrides = ovs,-                    cgFlags = parseFlags (configConfigurationsFlags flags)}+                    overrides = ovs} -  m <- genCode cfg allAPIs (toModulePath name) (genModule apis)-  alreadyDone <- doesFileExist (fromMaybe "" outputDir-                                </> "GI" </> T.unpack (ucFirst name) <.> "hs")-  moduleList <- if not alreadyDone-                then writeModuleTree verbosity outputDir m-                else return (listModuleTree m)+  let m = genCode cfg allAPIs (toModulePath name) (genModule apis)    let pkgInfoMod = "GI." <> ucFirst name <> ".PkgInfo"-      em' = map (MN.fromString . T.unpack) (pkgInfoMod : moduleList)+      em' = map (MN.fromString . T.unpack) (pkgInfoMod : listModuleTree m)       ctd' = ((condTreeData . fromJust . condLibrary) gpd) {exposedModules = em'}       cL' = ((fromJust . condLibrary) gpd) {condTreeData = ctd'}       gpd' = gpd {condLibrary = Just cL'} -  when (not alreadyDone) $-       genPkgInfo ((pkgconfigDepends . libBuildInfo . condTreeData .-                    fromJust . condLibrary) gpd)-                  (configConfigurationsFlags flags)-                  (fromMaybe "" outputDir+  alreadyDone <- doesFileExist (fromMaybe "" outputDir+                                </> "GI" </> T.unpack (ucFirst name) <.> "hs")+  when (not alreadyDone) $ do+    void $ writeModuleTree verbosity outputDir m+    genPkgInfo ((pkgconfigDepends . libBuildInfo . condTreeData .+                  fromJust . condLibrary) gpd)+               (configConfigurationsFlags flags)+               (fromMaybe "" outputDir                    </> "GI" </> T.unpack (ucFirst name) </> "PkgInfo.hs")-                  pkgInfoMod+               pkgInfoMod    lbi <- defaultConfHook (gpd', hbi) flags 
lib/Data/GI/CodeGen/Code.hs view
@@ -1,6 +1,7 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Data.GI.CodeGen.Code-    ( Code(..)-    , ModuleInfo(..)+    ( Code+    , ModuleInfo(moduleCode, moduleDoc)     , ModuleFlag(..)     , BaseCodeGen     , CodeGen@@ -29,10 +30,13 @@     , missingInfoError      , indent+    , increaseIndent     , bline     , line     , blank     , group+    , cppIf+    , CPPGuard(..)     , hsBoot     , submodule     , setLanguagePragmas@@ -66,13 +70,15 @@ import Control.Monad.Except import qualified Data.Foldable as F import Data.Maybe (fromMaybe, catMaybes)-import Data.Monoid ((<>))-import Data.Sequence (Seq, ViewL ((:<)), (><), (|>), (<|))+import Data.Monoid ((<>), mempty) import qualified Data.Map.Strict as M-import qualified Data.Sequence as S+import Data.Sequence (ViewL ((:<)), viewl, (|>))+import qualified Data.Sequence as Seq import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T+import qualified Data.Text.Lazy.Builder as B+import qualified Data.Text.Lazy as LT  import System.Directory (createDirectoryIfMissing) import System.FilePath (joinPath, takeDirectory)@@ -87,25 +93,37 @@ import Data.GI.CodeGen.Util (tshow, terror, padTo, utf8WriteFile) import Data.GI.CodeGen.ProjectInfo (authors, license, maintainers) -data Code-    = NoCode              -- ^ No code-    | Line Text           -- ^ A single line, indented to current indentation-    | Indent Code         -- ^ Indented region-    | Sequence (Seq Code) -- ^ The basic sequence of code-    | Group Code          -- ^ A grouped set of lines-    deriving (Eq, Show)+-- | Set of CPP conditionals understood by the code generator.+data CPPConditional = CPPIfdef Text -- ^ #ifdef Foo+  deriving (Eq, Show, Ord) -instance Monoid Code where-    mempty = NoCode+-- | The generated `Code` is a sequence of `CodeToken`s.+newtype Code = Code (Seq.Seq CodeToken)+  deriving (Monoid, Eq, Show, Ord) -    NoCode `mappend` NoCode = NoCode-    x `mappend` NoCode = x-    NoCode `mappend` x = x-    (Sequence a) `mappend` (Sequence b) = Sequence (a >< b)-    (Sequence a) `mappend` b = Sequence (a |> b)-    a `mappend` (Sequence b) = Sequence (a <| b)-    a `mappend` b = Sequence (a <| b <| S.empty)+-- | Initializes a code block to the empty sequence.+emptyCode :: Code+emptyCode = Code Seq.empty +-- | Checks whether the given code block is empty.+isCodeEmpty :: Code -> Bool+isCodeEmpty (Code seq) = Seq.null seq++-- | A block of code consisting of a single token.+codeSingleton :: CodeToken -> Code+codeSingleton t = Code (Seq.singleton t)++-- | Possible code tokens.+data CodeToken+    = Line Text           -- ^ A single line, indented to current indentation.+    | Indent Code         -- ^ Indented region.+    | Group Code          -- ^ A grouped set of lines+    | IncreaseIndent      -- ^ Increase the indentation for the rest+                          -- of the lines in the group.+    | CPPBlock CPPConditional Code -- ^ A block of code guarded by the+                                   -- given CPP conditional+    deriving (Eq, Ord, Show)+ type Deps = Set.Set Text  -- | Subsection of the haddock documentation where the export should@@ -122,6 +140,8 @@ data Export = Export {       exportType    :: ExportType       -- ^ Which kind of export.     , exportSymbol  :: SymbolName       -- ^ Actual symbol to export.+    , exportGuards  :: [CPPConditional] -- ^ Protect the export by the+                                        -- given CPP export guards.     } deriving (Show, Eq, Ord)  -- | Possible types of exports.@@ -137,12 +157,12 @@ data ModuleInfo = ModuleInfo {       modulePath :: ModulePath -- ^ Full module name: ["Gtk", "Label"].     , moduleCode :: Code       -- ^ Generated code for the module.-    , bootCode   :: Code       -- ^ Interface going into the .hs-boot file.+    , bootCode   :: Code       -- ^ Interfaces going into the .hs-boot file.     , submodules :: M.Map Text ModuleInfo -- ^ Indexed by the relative                                           -- module name.     , moduleDeps :: Deps -- ^ Set of dependencies for this module.-    , moduleExports :: Seq Export -- ^ Exports for the module.-    , qualifiedImports :: Set.Set ModulePath -- ^ Qualified (source) imports+    , moduleExports :: Seq.Seq Export -- ^ Exports for the module.+    , qualifiedImports :: Set.Set ModulePath -- ^ Qualified (source) imports.     , modulePragmas :: Set.Set Text -- ^ Set of language pragmas for the module.     , moduleGHCOpts :: Set.Set Text -- ^ GHC options for compiling the module.     , moduleFlags   :: Set.Set ModuleFlag -- ^ Flags for the module.@@ -169,11 +189,11 @@ -- | Generate the empty module. emptyModule :: ModulePath -> ModuleInfo emptyModule m = ModuleInfo { modulePath = m-                           , moduleCode = NoCode-                           , bootCode = NoCode+                           , moduleCode = emptyCode+                           , bootCode = emptyCode                            , submodules = M.empty                            , moduleDeps = Set.empty-                           , moduleExports = S.empty+                           , moduleExports = Seq.empty                            , qualifiedImports = Set.empty                            , modulePragmas = Set.empty                            , moduleGHCOpts = Set.empty@@ -190,13 +210,26 @@                                           -- to Haskell symbols.     } +-- | Set of errors for the code generator. data CGError = CGErrorNotImplemented Text              | CGErrorBadIntrospectionInfo Text              | CGErrorMissingInfo Text                deriving (Show) +-- | Temporaty state for the code generator.+data CGState = CGState {+  cgsCPPConditionals :: [CPPConditional] -- ^ Active CPP conditionals,+                                         -- outermost condition first.+  }++-- | Clean slate for `CGState`.+emptyCGState = CGState {+  cgsCPPConditionals = []+  }++-- | The base type for the code generator monad. type BaseCodeGen excType a =-    ReaderT CodeGenConfig (StateT ModuleInfo (ExceptT excType IO)) a+  ReaderT CodeGenConfig (StateT (CGState, ModuleInfo) (Except excType)) a  -- | The code generator monad, for generators that cannot throw -- errors. The fact that they cannot throw errors is encoded in the@@ -210,18 +243,20 @@ -- | Code generators that can throw errors. type ExcCodeGen a = BaseCodeGen CGError a --- | Run a `CodeGen` with given `Config` and initial `ModuleInfo`,--- returning either the resulting exception, or the result and final--- state of the codegen.-runCodeGen :: BaseCodeGen e a -> CodeGenConfig -> ModuleInfo ->-              IO (Either e (a, ModuleInfo))-runCodeGen cg cfg state = runExceptT (runStateT (runReaderT cg cfg) state)+-- | Run a `CodeGen` with given `Config` and initial state, returning+-- either the resulting exception, or the result and final module info.+runCodeGen :: BaseCodeGen e a -> CodeGenConfig -> (CGState, ModuleInfo) ->+              (Either e (a, ModuleInfo))+runCodeGen cg cfg state =+  dropCGState <$> runExcept (runStateT (runReaderT cg cfg) state)+  where dropCGState :: (a, (CGState, ModuleInfo)) -> (a, ModuleInfo)+        dropCGState (x, (_, m)) = (x, m)  -- | This is useful when we plan run a subgenerator, and `mconcat` the -- result to the original structure later. cleanInfo :: ModuleInfo -> ModuleInfo-cleanInfo info = info { moduleCode = NoCode, submodules = M.empty,-                        bootCode = NoCode, moduleExports = S.empty,+cleanInfo info = info { moduleCode = emptyCode, submodules = M.empty,+                        bootCode = emptyCode, moduleExports = Seq.empty,                         qualifiedImports = Set.empty,                         moduleDoc = Nothing, moduleMinBase = Base47 } @@ -229,29 +264,35 @@ -- ambient CodeGen, but without adding the generated code to -- `moduleCode`, instead returning it explicitly. recurseCG :: BaseCodeGen e a -> BaseCodeGen e (a, Code)-recurseCG cg = do+recurseCG = recurseWithState id++-- | Like `recurseCG`, but we allow for explicitly setting the state+-- of the inner code generator.+recurseWithState :: (CGState -> CGState) -> BaseCodeGen e a+                 -> BaseCodeGen e (a, Code)+recurseWithState cgsSet cg = do   cfg <- ask-  oldInfo <- get+  (cgs, oldInfo) <- get   -- Start the subgenerator with no code and no submodules.   let info = cleanInfo oldInfo-  liftIO (runCodeGen cg cfg info) >>= \case+  case runCodeGen cg cfg (cgsSet cgs, info) of      Left e -> throwError e-     Right (r, new) -> put (mergeInfoState oldInfo new) >>+     Right (r, new) -> put (cgs, mergeInfoState oldInfo new) >>                        return (r, moduleCode new) --- | Like `recurse`, giving explicitly the set of loaded APIs and C to+-- | Like `recurseCG`, giving explicitly the set of loaded APIs and C to -- Haskell map for the subgenerator. recurseWithAPIs :: M.Map Name API -> CodeGen () -> CodeGen () recurseWithAPIs apis cg = do   cfg <- ask-  oldInfo <- get+  (cgs, oldInfo) <- get   -- Start the subgenerator with no code and no submodules.   let info = cleanInfo oldInfo       cfg' = cfg {loadedAPIs = apis,                   c2hMap = cToHaskellMap (M.toList apis)}-  liftIO (runCodeGen cg cfg' info) >>= \case-     Left e -> throwError e-     Right (_, new) -> put (mergeInfo oldInfo new)+  case runCodeGen cg cfg' (cgs, info) of+    Left e -> throwError e+    Right (_, new) -> put (cgs, mergeInfo oldInfo new)  -- | Merge everything but the generated code for the two given `ModuleInfo`. mergeInfoState :: ModuleInfo -> ModuleInfo -> ModuleInfo@@ -281,8 +322,10 @@  -- | Add the given submodule to the list of submodules of the current -- module.-addSubmodule :: Text -> ModuleInfo -> ModuleInfo -> ModuleInfo-addSubmodule modName submodule current = current { submodules = M.insertWith mergeInfo modName submodule (submodules current)}+addSubmodule :: Text -> ModuleInfo -> (CGState, ModuleInfo)+             -> (CGState, ModuleInfo)+addSubmodule modName submodule (cgs, current) =+  (cgs, current { submodules = M.insertWith mergeInfo modName submodule (submodules current)})  -- | Run the given CodeGen in order to generate a single submodule of the -- current module. Note that we do not generate the submodule if the@@ -291,14 +334,14 @@ submodule' :: Text -> BaseCodeGen e () -> BaseCodeGen e () submodule' modName cg = do   cfg <- ask-  oldInfo <- get+  (_, oldInfo) <- get   let info = emptyModule (modulePath oldInfo /. modName)-  liftIO (runCodeGen cg cfg info) >>= \case-         Left e -> throwError e-         Right (_, smInfo) -> if moduleCode smInfo == NoCode &&-                                 M.null (submodules smInfo)-                              then return ()-                              else modify' (addSubmodule modName smInfo)+  case runCodeGen cg cfg (emptyCGState, info) of+    Left e -> throwError e+    Right (_, smInfo) -> if isCodeEmpty (moduleCode smInfo) &&+                            M.null (submodules smInfo)+                         then return ()+                         else modify' (addSubmodule modName smInfo)  -- | Run the given CodeGen in order to generate a submodule (specified -- an an ordered list) of the current module.@@ -312,17 +355,17 @@ handleCGExc fallback  action = do     cfg <- ask-    oldInfo <- get+    (cgs, oldInfo) <- get     let info = cleanInfo oldInfo-    liftIO (runCodeGen action cfg info) >>= \case-        Left e -> fallback e-        Right (r, newInfo) -> do-            put (mergeInfo oldInfo newInfo)-            return r+    case runCodeGen action cfg (cgs, info) of+      Left e -> fallback e+      Right (r, newInfo) -> do+        put (cgs, mergeInfo oldInfo newInfo)+        return r  -- | Return the currently loaded set of dependencies. getDeps :: CodeGen Deps-getDeps = moduleDeps <$> get+getDeps = moduleDeps . snd <$> get  -- | Return the ambient configuration for the code generator. config :: CodeGen Config@@ -331,7 +374,7 @@ -- | Return the name of the current module. currentModule :: CodeGen Text currentModule = do-  s <- get+  (_, s) <- get   return (dotWithPrefix (modulePath s))  -- | Return the list of APIs available to the generator.@@ -343,40 +386,40 @@ getC2HMap = c2hMap <$> ask  -- | Due to the `forall` in the definition of `CodeGen`, if we want to--- run the monad transformer stack until we get an `IO` action, our--- only option is ignoring the possible error code from--- `runExceptT`. This is perfectly safe, since there is no way to--- construct a computation in the `CodeGen` monad that throws an--- exception, due to the higher rank type.-unwrapCodeGen :: CodeGen a -> CodeGenConfig -> ModuleInfo ->-                 IO (a, ModuleInfo)+-- run the monad transformer stack until we get a result, our only+-- option is ignoring the possible error code from `runExcept`. This+-- is perfectly safe, since there is no way to construct a computation+-- in the `CodeGen` monad that throws an exception, due to the higher+-- rank type.+unwrapCodeGen :: CodeGen a -> CodeGenConfig -> (CGState, ModuleInfo)+              -> (a, ModuleInfo) unwrapCodeGen cg cfg info =-    runCodeGen cg cfg info >>= \case-        Left _ -> error "unwrapCodeGen:: The impossible happened!"-        Right (r, newInfo) -> return (r, newInfo)---- | Like `evalCodeGen`, but discard the resulting output value.-genCode :: Config -> M.Map Name API ->-           ModulePath -> CodeGen () -> IO ModuleInfo-genCode cfg apis mPath cg = snd <$> evalCodeGen cfg apis mPath cg+    case runCodeGen cg cfg info of+      Left _ -> error "unwrapCodeGen:: The impossible happened!"+      Right (r, newInfo) -> (r, newInfo)  -- | Run a code generator, and return the information for the -- generated module together with the return value of the generator. evalCodeGen :: Config -> M.Map Name API ->-               ModulePath -> CodeGen a -> IO (a, ModuleInfo)-evalCodeGen cfg apis mPath cg = do+               ModulePath -> CodeGen a -> (a, ModuleInfo)+evalCodeGen cfg apis mPath cg =   let initialInfo = emptyModule mPath       cfg' = CodeGenConfig {hConfig = cfg, loadedAPIs = apis,                             c2hMap = cToHaskellMap (M.toList apis)}-  unwrapCodeGen cg cfg' initialInfo+  in unwrapCodeGen cg cfg' (emptyCGState, initialInfo) +-- | Like `evalCodeGen`, but discard the resulting output value.+genCode :: Config -> M.Map Name API ->+           ModulePath -> CodeGen () -> ModuleInfo+genCode cfg apis mPath cg = snd $ evalCodeGen cfg apis mPath cg+ -- | Mark the given dependency as used by the module. registerNSDependency :: Text -> CodeGen () registerNSDependency name = do     deps <- getDeps     unless (Set.member name deps) $ do         let newDeps = Set.insert name deps-        modify' $ \s -> s {moduleDeps = newDeps}+        modify' $ \(cgs, s) -> (cgs, s {moduleDeps = newDeps})  -- | Return the transitive set of dependencies, i.e. the union of -- those of the module and (transitively) its submodules.@@ -393,7 +436,7 @@   -- Make sure the module is listed as a dependency.   when (modName cfg /= ns) $     registerNSDependency ns-  minfo <- get+  (_, minfo) <- get   if mp == modulePath minfo   then return s   else do@@ -405,7 +448,7 @@ -- under which the module was imported. qualifiedImport :: ModulePath -> CodeGen Text qualifiedImport mp = do-  modify' $ \s -> s {qualifiedImports = Set.insert mp (qualifiedImports s)}+  modify' $ \(cgs, s) -> (cgs, s {qualifiedImports = Set.insert mp (qualifiedImports s)})   return (qualifiedModuleName mp)  -- | Construct a simplified version of the module name, suitable for a@@ -461,8 +504,9 @@             terror $ "couldn't find API description for " <> ns <> "." <> name n  -- | Add some code to the current generator.-tellCode :: Code -> CodeGen ()-tellCode c = modify' (\s -> s {moduleCode = moduleCode s <> c})+tellCode :: CodeToken -> CodeGen ()+tellCode c = modify' (\(cgs, s) -> (cgs, s {moduleCode = moduleCode s <>+                                                         codeSingleton c}))  -- | Print out a (newline-terminated) line. line :: Text -> CodeGen ()@@ -484,6 +528,11 @@   tellCode (Indent code)   return x +-- | Increase the indentation level for the rest of the lines in the+-- current group.+increaseIndent :: CodeGen ()+increaseIndent = tellCode IncreaseIndent+ -- | Group a set of related code. group :: BaseCodeGen e a -> BaseCodeGen e a group cg = do@@ -492,17 +541,42 @@   blank   return x +-- | Guard a block of code with @#ifdef@.+cppIfdef :: Text -> BaseCodeGen e a -> BaseCodeGen e a+cppIfdef cond cg = do+  (x, code) <- recurseWithState addConditional cg+  tellCode (CPPBlock (CPPIfdef cond) code)+  blank+  return x+    where addConditional :: CGState -> CGState+          addConditional cgs = CGState {cgsCPPConditionals = CPPIfdef cond :+                                         cgsCPPConditionals cgs}++-- | Possible features to test via CPP.+data CPPGuard = CPPOverloading -- ^ Enable overloading++-- | Guard a code block with CPP code, such that it is included only+-- if the specified feature is enabled.+cppIf :: CPPGuard -> BaseCodeGen e a -> BaseCodeGen e a+cppIf CPPOverloading = cppIfdef "ENABLE_OVERLOADING"+ -- | Write the given code into the .hs-boot file for the current module. hsBoot :: BaseCodeGen e a -> BaseCodeGen e a hsBoot cg = do   (x, code) <- recurseCG cg-  modify' (\s -> s{bootCode = bootCode s <> code})+  modify' (\(cgs, s) -> (cgs, s{bootCode = bootCode s <>+                               addGuards (cgsCPPConditionals cgs) code}))   return x+  where addGuards :: [CPPConditional] -> Code -> Code+        addGuards [] c = c+        addGuards (cond : conds) c = codeSingleton $ CPPBlock cond (addGuards conds c)  -- | Add a export to the current module.-export :: Export -> CodeGen ()-export e =-    modify' $ \s -> s{moduleExports = moduleExports s |> e}+export :: ([CPPConditional] -> Export) -> CodeGen ()+export partial =+    modify' $ \(cgs, s) -> (cgs,+                            let e = partial $ cgsCPPConditionals cgs+                            in s{moduleExports = moduleExports s |> e})  -- | Reexport a whole module. exportModule :: SymbolName -> CodeGen ()@@ -531,36 +605,43 @@ -- | Set the language pragmas for the current module. setLanguagePragmas :: [Text] -> CodeGen () setLanguagePragmas ps =-    modify' $ \s -> s{modulePragmas = Set.fromList ps}+    modify' $ \(cgs, s) -> (cgs, s{modulePragmas = Set.fromList ps})  -- | Set the GHC options for compiling this module (in a OPTIONS_GHC pragma). setGHCOptions :: [Text] -> CodeGen () setGHCOptions opts =-    modify' $ \s -> s{moduleGHCOpts = Set.fromList opts}+    modify' $ \(cgs, s) -> (cgs, s{moduleGHCOpts = Set.fromList opts})  -- | Set the given flags for the module. setModuleFlags :: [ModuleFlag] -> CodeGen () setModuleFlags flags =-    modify' $ \s -> s{moduleFlags = Set.fromList flags}+    modify' $ \(cgs, s) -> (cgs, s{moduleFlags = Set.fromList flags})  -- | Set the minimum base version supported by the current module. setModuleMinBase :: BaseVersion -> CodeGen () setModuleMinBase v =-    modify' $ \s -> s{moduleMinBase = max v (moduleMinBase s)}+    modify' $ \(cgs, s) -> (cgs, s{moduleMinBase = max v (moduleMinBase s)}) +-- | Format a CPP conditional.+cppCondFormat :: CPPConditional -> (Text, Text)+cppCondFormat (CPPIfdef c) = ("#ifdef " <> c <> "\n", "#endif\n")+ -- | Return a text representation of the `Code`. codeToText :: Code -> Text-codeToText c = T.concat $ str 0 c []-    where-      str :: Int -> Code -> [Text] -> [Text]-      str _ NoCode cont = cont-      str n (Line s) cont =  paddedLine n s : cont-      str n (Indent c) cont = str (n + 1) c cont-      str n (Sequence s) cont = deseq n (S.viewl s) cont-      str n (Group c) cont = str n c cont--      deseq _ S.EmptyL cont = cont-      deseq n (c :< cs) cont = str n c (deseq n (S.viewl cs) cont)+codeToText (Code seq) = LT.toStrict . B.toLazyText $ genCode 0 (viewl seq)+  where genCode :: Int -> ViewL CodeToken -> B.Builder+        genCode _ Seq.EmptyL = mempty+        genCode n (Line s :< rest) = B.fromText (paddedLine n s) <>+                                      genCode n (viewl rest)+        genCode n (Indent (Code seq) :< rest) = genCode (n+1) (viewl seq) <>+                                      genCode n (viewl rest)+        genCode n (Group (Code seq) :< rest) = genCode n (viewl seq) <>+                                               genCode n (viewl rest)+        genCode n (CPPBlock cond (Code seq) :< rest) =+          let (condBegin, condEnd) = cppCondFormat cond+          in B.fromText condBegin <> genCode n (viewl seq) <>+             B.fromText condEnd <> genCode n (viewl rest)+        genCode n (IncreaseIndent :< rest) = genCode (n+1) (viewl rest)  -- | Pad a line to the given number of leading spaces, and add a -- newline at the end.@@ -571,21 +652,26 @@ comma :: Text -> Text comma s = padTo 40 s <> "," +-- | Format the given export symbol.+formatExport :: (Export -> Text) -> Export -> Text+formatExport formatName export = go (exportGuards export)+  where go :: [CPPConditional] -> Text+        go [] = (paddedLine 1 . comma . formatName) export+        go (c:cs) = let (begin, end) = cppCondFormat c+                    in begin <> go cs <> end+ -- | Format the list of exported modules. formatExportedModules :: [Export] -> Maybe Text formatExportedModules [] = Nothing formatExportedModules exports =-    Just . T.concat . map ( paddedLine 1-                           . comma-                           . ("module " <>)-                           . exportSymbol)+    Just . T.concat . map (formatExport (("module " <>) . exportSymbol))           . filter ((== ExportModule) . exportType) $ exports  -- | Format the toplevel exported symbols. formatToplevel :: [Export] -> Maybe Text formatToplevel [] = Nothing formatToplevel exports =-    Just . T.concat . map (paddedLine 1 . comma . exportSymbol)+    Just . T.concat . map (formatExport exportSymbol)          . filter ((== ExportToplevel) . exportType) $ exports  -- | Format the type declarations section.@@ -595,9 +681,7 @@     in if exportedTypes == []        then Nothing        else Just . T.unlines $ [ "-- * Exported types"-                               , T.concat . map ( paddedLine 1-                                                . comma-                                                . exportSymbol )+                               , T.concat . map ( formatExport exportSymbol )                                       $ exportedTypes ]  -- | A subsection name, with an optional anchor name.@@ -611,7 +695,7 @@              , subsectionAnchor = Just (prefix <> ":" <> title) }  -- | Format a given section made of subsections.-formatSection :: Text -> (Export -> Maybe (Subsection, SymbolName)) ->+formatSection :: Text -> (Export -> Maybe (Subsection, Export)) ->                  [Export] -> Maybe Text formatSection section filter exports =     if M.null exportedSubsections@@ -622,49 +706,49 @@                               . M.toList ) exportedSubsections]      where-      filteredExports :: [(Subsection, SymbolName)]+      filteredExports :: [(Subsection, Export)]       filteredExports = catMaybes (map filter exports) -      exportedSubsections :: M.Map Subsection (Set.Set SymbolName)+      exportedSubsections :: M.Map Subsection (Set.Set Export)       exportedSubsections = foldr extract M.empty filteredExports -      extract :: (Subsection, SymbolName) -> M.Map Subsection (Set.Set Text)-              -> M.Map Subsection (Set.Set Text)+      extract :: (Subsection, Export) -> M.Map Subsection (Set.Set Export)+              -> M.Map Subsection (Set.Set Export)       extract (subsec, m) secs =           M.insertWith Set.union subsec (Set.singleton m) secs -      formatSubsection :: (Subsection, Set.Set SymbolName) -> Text+      formatSubsection :: (Subsection, Set.Set Export) -> Text       formatSubsection (subsec, symbols) =           T.unlines [ "-- ** " <> case subsectionAnchor subsec of                                     Just anchor -> subsectionTitle subsec <>                                                    " #" <> anchor <> "#"                                     Nothing -> subsectionTitle subsec                     , ( T.concat-                      . map (paddedLine 1 . comma)+                      . map (formatExport exportSymbol)                       . Set.toList ) symbols]  -- | Format the list of methods. formatMethods :: [Export] -> Maybe Text formatMethods = formatSection "Methods" toMethod-    where toMethod :: Export -> Maybe (Subsection, SymbolName)-          toMethod (Export (ExportMethod s) m) =-            Just (subsecWithPrefix "method" s, m)+    where toMethod :: Export -> Maybe (Subsection, Export)+          toMethod e@(Export (ExportMethod s) _ _) =+            Just (subsecWithPrefix "method" s, e)           toMethod _ = Nothing  -- | Format the list of properties. formatProperties :: [Export] -> Maybe Text formatProperties = formatSection "Properties" toProperty-    where toProperty :: Export -> Maybe (Subsection, SymbolName)-          toProperty (Export (ExportProperty s) m) =-            Just (subsecWithPrefix "attr" s, m)+    where toProperty :: Export -> Maybe (Subsection, Export)+          toProperty e@(Export (ExportProperty s) _ _) =+            Just (subsecWithPrefix "attr" s, e)           toProperty _ = Nothing  -- | Format the list of signals. formatSignals :: [Export] -> Maybe Text formatSignals = formatSection "Signals" toSignal-    where toSignal :: Export -> Maybe (Subsection, SymbolName)-          toSignal (Export (ExportSignal s) m) =-            Just (subsecWithPrefix "signal" s, m)+    where toSignal :: Export -> Maybe (Subsection, Export)+          toSignal e@(Export (ExportSignal s) _ _) =+            Just (subsecWithPrefix "signal" s, e)           toSignal _ = Nothing  -- | Format the given export list. This is just the inside of the@@ -709,12 +793,12 @@     <> "    ) where\n" modulePrelude name [] reexportedModules =     "module " <> name <> "\n    ( "-    <> formatExportList (map (Export ExportModule) reexportedModules)+    <> formatExportList (map (\m -> Export ExportModule m []) reexportedModules)     <> "    ) where\n\n"     <> T.unlines (map ("import " <>) reexportedModules) modulePrelude name exports reexportedModules =     "module " <> name <> "\n    ( "-    <> formatExportList (map (Export ExportModule) reexportedModules)+    <> formatExportList (map (\m -> Export ExportModule m []) reexportedModules)     <> "\n"     <> formatExportList exports     <> "    ) where\n\n"@@ -788,7 +872,7 @@   createDirectoryIfMissing True dirname   utf8WriteFile fname (T.unlines [pragmas, optionsGHC, haddock,                                  prelude, imports, deps, code])-  when (bootCode minfo /= NoCode) $ do+  when (not . isCodeEmpty $ bootCode minfo) $ do     let bootFName = modulePathToFilePath dirPrefix (modulePath minfo) ".hs-boot"     utf8WriteFile bootFName (genHsBoot minfo) 
lib/Data/GI/CodeGen/CodeGen.hs view
@@ -18,7 +18,6 @@  import Data.GI.CodeGen.API import Data.GI.CodeGen.Callable (genCCallableWrapper)-import Data.GI.CodeGen.Config (Config(..), CodeGenFlags(..)) import Data.GI.CodeGen.Constant (genConstant) import Data.GI.CodeGen.Code import Data.GI.CodeGen.EnumFlags (genEnum, genFlags)@@ -109,8 +108,7 @@        else return Nothing     -- Overloaded methods-   cfg <- config-   when (cgOverloadedMethods (cgFlags cfg)) $+   cppIf CPPOverloading $         genMethodList n (catMaybes methods)  -- | Generated wrapper for unions.@@ -152,8 +150,7 @@       else return Nothing    -- Overloaded methods-  cfg <- config-  when (cgOverloadedMethods (cgFlags cfg)) $+  cppIf CPPOverloading $        genMethodList n (catMaybes methods)  -- | When parsing the GIR file we add the implicit object argument to@@ -230,8 +227,7 @@     genCCallableWrapper mn' sym c''     exportMethod (lowerName mn) (lowerName mn') -    cfg <- config-    when (cgOverloadedMethods (cgFlags cfg)) $+    cppIf CPPOverloading $          genMethodInfo cn (m {methodCallable = c''})  -- Type casting with type checking@@ -293,8 +289,7 @@      noName name' -    cfg <- config-    when (cgOverloadedMethods (cgFlags cfg)) $+    cppIf CPPOverloading $          fullObjectMethodList n o >>= genMethodList n      forM_ (objSignals o) $ \s ->@@ -305,9 +300,9 @@      (genSignal s n)      genObjectProperties n o-    when (cgOverloadedProperties (cgFlags cfg)) $+    cppIf CPPOverloading $          genNamespacedPropLabels n (objProperties o) (objMethods o)-    when (cgOverloadedSignals (cgFlags cfg)) $+    cppIf CPPOverloading $          genObjectSignals n o      -- Methods@@ -316,7 +311,7 @@       handleCGExc (\e -> line ("-- XXX Could not generate method "                               <> name' <> "::" <> name mn <> "\n"                               <> "-- Error was : " <> describeCGError e)-                  >> (when (cgOverloadedMethods (cgFlags cfg)) $+                  >> (cppIf CPPOverloading $                            genUnsupportedMethodInfo n f))                   (genMethod n f) @@ -333,15 +328,13 @@    noName name' -  cfg <- config-   forM_ (ifSignals iface) $ \s -> handleCGExc      (line . (T.concat ["-- XXX Could not generate signal ", name', "::"                      , sigName s                      , "\n", "-- Error was : "] <>) . describeCGError)      (genSignal s n) -  when (cgOverloadedSignals (cgFlags cfg)) $+  cppIf CPPOverloading $      genInterfaceSignals n iface    isGO <- apiIsGObject n (APIInterface iface)@@ -354,7 +347,7 @@     genGObjectCasts n cn_ uniqueParents      genInterfaceProperties n iface-    when (cgOverloadedProperties (cgFlags cfg)) $+    cppIf CPPOverloading $        genNamespacedPropLabels n (ifProperties iface) (ifMethods iface)    else group $ do@@ -368,7 +361,7 @@        line $ "-- XXX Skipping property generation for non-GObject interface"    -- Methods-  when (cgOverloadedMethods (cgFlags cfg)) $+  cppIf CPPOverloading $        fullInterfaceMethodList n iface >>= genMethodList n    forM_ (ifMethods iface) $ \f -> do@@ -379,7 +372,7 @@              (\e -> line ("-- XXX Could not generate method "                           <> name' <> "::" <> name mn <> "\n"                           <> "-- Error was : " <> describeCGError e)-             >> (when (cgOverloadedMethods (cgFlags cfg)) $+             >> (cppIf CPPOverloading $                       genUnsupportedMethodInfo n f))              (genMethod n f) 
lib/Data/GI/CodeGen/Config.hs view
@@ -1,29 +1,16 @@ -- | Configuration for the code generator. module Data.GI.CodeGen.Config     ( Config(..)-    , CodeGenFlags(..)     ) where  import Data.Text (Text) import Data.GI.CodeGen.Overrides (Overrides) --- | Flags controlling different aspects of the code generator.-data CodeGenFlags = CodeGenFlags {-    -- | Whether to generate overloaded properties.-      cgOverloadedProperties :: Bool-    -- | Whether to generate support for overloaded signals.-    , cgOverloadedSignals    :: Bool-    -- | Whether to generate support for overloaded methods.-    , cgOverloadedMethods    :: Bool-    } deriving Show- data Config = Config {       -- | Name of the module being generated.       modName        :: Text,       -- | Whether to print extra info.       verbose        :: Bool,       -- | List of loaded overrides for the code generator.-      overrides      :: Overrides,-      -- | List of flags for the code generator.-      cgFlags        :: CodeGenFlags+      overrides      :: Overrides     } deriving Show
lib/Data/GI/CodeGen/Conversions.hs view
@@ -10,6 +10,7 @@      , hToF     , fToH+    , transientToH     , haskellType     , isoHaskellType     , foreignType@@ -88,6 +89,7 @@     fromString = P . T.pack  data FExpr next = Apply Constructor next+                | LambdaConvert Text next                 | MapC Map Constructor next                 | Literal Constructor next                   deriving (Show, Functor)@@ -125,6 +127,9 @@ 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@@ -146,6 +151,11 @@            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@@ -563,6 +573,51 @@   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 =
lib/Data/GI/CodeGen/Haddock.hs view
@@ -279,6 +279,6 @@     Just raw -> do       c2h <- getC2HMap       docBase <- getDocBase-      modify' $ \s -> s{moduleDoc = moduleDoc s <>-                                    Just (formatHaddock c2h docBase-                                           (parseGtkDoc raw))}+      modify' $ \(cgs, s) -> (cgs, s{moduleDoc = moduleDoc s <>+                                      Just (formatHaddock c2h docBase+                                            (parseGtkDoc raw))})
lib/Data/GI/CodeGen/Properties.hs view
@@ -17,8 +17,6 @@ import Foreign.Storable (sizeOf)  import Data.GI.CodeGen.API-import Data.GI.CodeGen.Config (Config(cgFlags),-                               CodeGenFlags(cgOverloadedProperties)) import Data.GI.CodeGen.Conversions import Data.GI.CodeGen.Code import Data.GI.CodeGen.GObject@@ -263,9 +261,8 @@                         then parenthesize sOutType                         else sOutType -  -- Polymorphic _label style lens-  cfg <- config-  when (cgOverloadedProperties (cgFlags cfg)) $ group $ do+  -- Polymorphic #label style lens+  cppIf CPPOverloading $ do     cls <- classConstraint owner     inConstraint <- if writable || constructOnly                     then do@@ -334,19 +331,15 @@ genProperties n ownedProps allProps = do   let name = upperName n -  cfg <- config   forM_ ownedProps $ \prop -> do       handleCGExc (\err -> do                      line $ "-- XXX Generation of property \""                               <> propName prop <> "\" of object \""                               <> name <> "\" failed: " <> describeCGError err-                     (when (cgOverloadedProperties (cgFlags cfg)) $-                           genPlaceholderProperty n prop))+                     cppIf CPPOverloading (genPlaceholderProperty n prop))                   (genOneProperty n prop) -  cfg <- config--  when (cgOverloadedProperties (cgFlags cfg)) $ group $ do+  cppIf CPPOverloading $ do     let propListType = name <> "AttributeList"     line $ "instance O.HasAttributeList " <> name     line $ "type instance O.AttributeList " <> name <> " = " <> propListType
lib/Data/GI/CodeGen/Signal.hs view
@@ -177,7 +177,7 @@   case argType arg of     t@(TCArray False _ _ _) -> convertCallbackInCArray cb arg t name     _ -> do-      let c = convert name $ fToH (argType arg) (transfer arg)+      let c = convert name $ transientToH (argType arg) (transfer arg)       wrapMaybe arg >>= bool c (convertNullable name c)  prepareInoutArg :: Arg -> ExcCodeGen Text@@ -224,7 +224,7 @@   line $ dropper <> " _f " <> T.unwords argNames <> " = _f "            <> T.unwords (catMaybes (map passOrIgnore inWithClosures)) --- | The wrapper itself, marshalling to and from Haskell. The first+-- | The wrapper itself, marshalling to and from Haskell. The `Callable` -- argument is possibly a pointer to a FunPtr to free (via -- freeHaskellFunPtr) once the callback is run once, or Nothing if the -- FunPtr will be freed by someone else (the function registering the
lib/Data/GI/CodeGen/Struct.hs view
@@ -21,7 +21,6 @@ import Data.GI.CodeGen.API import Data.GI.CodeGen.Conversions import Data.GI.CodeGen.Code-import Data.GI.CodeGen.Config (Config(..), CodeGenFlags(..)) import Data.GI.CodeGen.SymbolNaming import Data.GI.CodeGen.Type import Data.GI.CodeGen.Util@@ -277,10 +276,7 @@               exportProperty (lcFirst $ fName field) (fieldClear n field)            Nothing -> return () -     cfg <- config-     if cgOverloadedProperties (cgFlags cfg)-     then Just <$> genAttrInfo n field-     else return Nothing+     Just <$> cppIf CPPOverloading (genAttrInfo n field)      where privateType :: Type -> Bool           privateType (TInterface n) = "Private" `T.isSuffixOf` name n@@ -299,8 +295,7 @@    blank -  cfg <- config-  when (cgOverloadedProperties (cgFlags cfg)) $ group $ do+  cppIf CPPOverloading $ do     let attrListName = name' <> "AttributeList"     line $ "instance O.HasAttributeList " <> name'     line $ "type instance O.AttributeList " <> name' <> " = " <> attrListName