packages feed

hoppy-generator 0.6.0 → 0.7.0

raw patch · 4 files changed

+106/−25 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Foreign.Hoppy.Generator.Hook: [enumEvaluatorArgsEntryIdentifiers] :: EnumEvaluatorArgs -> [Identifier]
+ Foreign.Hoppy.Generator.Hook: EnumEvaluatorEntry :: Scoped -> Identifier -> EnumEvaluatorEntry
+ Foreign.Hoppy.Generator.Hook: [enumEvaluatorArgsEntries] :: EnumEvaluatorArgs -> [EnumEvaluatorEntry]
+ Foreign.Hoppy.Generator.Hook: [enumEvaluatorEntryIdentifier] :: EnumEvaluatorEntry -> Identifier
+ Foreign.Hoppy.Generator.Hook: [enumEvaluatorEntryScoped] :: EnumEvaluatorEntry -> Scoped
+ Foreign.Hoppy.Generator.Hook: data EnumEvaluatorEntry
+ Foreign.Hoppy.Generator.Hook: instance GHC.Classes.Eq Foreign.Hoppy.Generator.Hook.EnumEvaluatorEntry
+ Foreign.Hoppy.Generator.Hook: instance GHC.Classes.Ord Foreign.Hoppy.Generator.Hook.EnumEvaluatorEntry
+ Foreign.Hoppy.Generator.Spec: Scoped :: Scoped
+ Foreign.Hoppy.Generator.Spec: Unscoped :: Scoped
+ Foreign.Hoppy.Generator.Spec: [enumInfoScoped] :: EnumInfo -> Scoped
+ Foreign.Hoppy.Generator.Spec: data Scoped
+ Foreign.Hoppy.Generator.Spec: isScoped :: Scoped -> Bool
- Foreign.Hoppy.Generator.Hook: EnumEvaluatorArgs :: Interface -> Reqs -> [Identifier] -> [Identifier] -> Bool -> EnumEvaluatorArgs
+ Foreign.Hoppy.Generator.Hook: EnumEvaluatorArgs :: Interface -> Reqs -> [Identifier] -> [EnumEvaluatorEntry] -> Bool -> EnumEvaluatorArgs
- Foreign.Hoppy.Generator.Spec: EnumInfo :: ExtName -> Identifier -> Maybe Type -> Reqs -> EnumValueMap -> EnumInfo
+ Foreign.Hoppy.Generator.Spec: EnumInfo :: ExtName -> Identifier -> Maybe Type -> Reqs -> Scoped -> EnumValueMap -> EnumInfo
- Foreign.Hoppy.Generator.Spec.Enum: makeAutoEnum :: IsAutoEnumValue v => Identifier -> Maybe ExtName -> Bool -> [v] -> CppEnum
+ Foreign.Hoppy.Generator.Spec.Enum: makeAutoEnum :: IsAutoEnumValue v => Identifier -> Maybe ExtName -> Scoped -> [v] -> CppEnum

Files

hoppy-generator.cabal view
@@ -1,5 +1,5 @@ name: hoppy-generator-version: 0.6.0+version: 0.7.0 synopsis: C++ FFI generator - Code generator homepage: http://khumba.net/projects/hoppy license: AGPL-3
src/Foreign/Hoppy/Generator/Hook.hs view
@@ -22,6 +22,7 @@   -- * Enum evaluation   EnumEvaluator,   EnumEvaluatorArgs (..),+  EnumEvaluatorEntry (..),   EnumEvaluatorResult (..),   evaluateEnumsWithCompiler,   evaluateEnumsWithDefaultCompiler,@@ -39,6 +40,7 @@ import Control.Monad.Writer (execWriter, tell) import Data.ByteString.Lazy (ByteString, hPut) import Data.ByteString.Builder (stringUtf8, toLazyByteString)+import Data.List (splitAt) import qualified Data.Map as M import Data.Maybe (isJust, listToMaybe, mapMaybe) import qualified Data.Set as S@@ -50,6 +52,7 @@ import Foreign.Hoppy.Generator.Spec.Base import Foreign.Hoppy.Generator.Types (intT, llongT, longT, uintT, ullongT, ulongT) import Foreign.Hoppy.Generator.Util (withTempFile)+import Foreign.Hoppy.Generator.Version (CppVersion (Cpp2011), activeCppVersion) import Foreign.Storable (Storable, sizeOf) import System.Exit (ExitCode (ExitFailure, ExitSuccess), exitFailure) import System.IO (hClose, hPutStrLn, stderr)@@ -88,8 +91,8 @@     -- being evaluated.   , enumEvaluatorArgsSizeofIdentifiers :: [Identifier]     -- ^ The list of identifiers that we need to compute sizeof() for.-  , enumEvaluatorArgsEntryIdentifiers :: [Identifier]-    -- ^ The list of identifiers to calculate values for.+  , enumEvaluatorArgsEntries :: [EnumEvaluatorEntry]+    -- ^ The list of entries to calculate values for.   , enumEvaluatorArgsKeepOutputsOnFailure :: Bool     -- ^ Whether to leave temporary build inputs and outputs on disk in case the     -- calculation fails.  If failure does occur and this is true, then the@@ -97,13 +100,27 @@     -- (this is taken care of by the @calculateEnumValues*@ functions here.)   } +-- | An entry in an enumeration.  This also tracks whether the entry came from a+-- scoped enum, for assertion reasons.+data EnumEvaluatorEntry = EnumEvaluatorEntry+  { enumEvaluatorEntryScoped :: Scoped+    -- ^ Whether the entry comes from a scoped enum.+  , enumEvaluatorEntryIdentifier :: Identifier+    -- ^ The identifier referring to the entry.+  }+  deriving (Eq)++instance Ord EnumEvaluatorEntry where+  compare (EnumEvaluatorEntry _ i1) (EnumEvaluatorEntry _ i2) =+    compare (OrdIdentifier i1) (OrdIdentifier i2)+ -- | Raw outputs parsed from the output of an enum evaluator. data EnumEvaluatorResult = EnumEvaluatorResult   { enumEvaluatorResultSizes :: ![Int]     -- ^ The sizeof() for each identifier in 'enumEvaluatorArgsSizeofIdentifiers'.     -- The lengths of these two lists must match.   , enumEvaluatorResultValues :: ![Integer]-    -- ^ The numeric value for each identifier in 'enumEvaluatorArgsEntryIdentifiers'.+    -- ^ The numeric value for each identifier in 'enumEvaluatorArgsEntries'.     -- The lengths of these two lists must match.   } deriving (Show) @@ -178,7 +195,11 @@ makeCppSourceToEvaluateEnums args =   toLazyByteString $ stringUtf8 $ unlines $   [ "#include <iostream>"-  , ""+  ] +++  (if any isEntryScoped $ enumEvaluatorArgsEntries args+    then [ "#include <type_traits>" ]  -- We've asserted that we have C++11 in this case.+    else []) +++  [ ""   ] ++ [concatMap includeToString $         S.elems $ reqsIncludes $ enumEvaluatorArgsReqs args] ++   [ ""@@ -190,10 +211,15 @@          in "  std::cout << sizeof(" ++ rendered ++ ") << ' ' << " ++             doubleQuote rendered ++ " << '\\n';") ++   [ "  std::cout << \"#values\\n\";"-  ] ++ for (enumEvaluatorArgsEntryIdentifiers args)-       (\identifier ->+  ] ++ for (enumEvaluatorArgsEntries args)+       (\(EnumEvaluatorEntry scoped identifier) ->          let rendered = renderIdentifier identifier-         in "  std::cout << (" ++ rendered ++ ") << ' ' << " +++             numericExpr = case scoped of+               Unscoped -> rendered+               Scoped ->+                 "static_cast<std::underlying_type<decltype(" ++ rendered ++ ")>::type>(" +++                 rendered ++ ")"+         in "  std::cout << (" ++ numericExpr ++ ") << ' ' << " ++             doubleQuote rendered ++ " << '\\n';") ++   [ ""   , "  return 0;"@@ -212,7 +238,7 @@   expectLine "#sizes"   readSizes $ enumEvaluatorArgsSizeofIdentifiers args   expectLine "#values"-  readValues $ enumEvaluatorArgsEntryIdentifiers args+  readValues $ map (\(EnumEvaluatorEntry _ i) -> i) $ enumEvaluatorArgsEntries args   expectEof   modify' $ \EnumEvaluatorResult              { enumEvaluatorResultSizes = sizes@@ -296,11 +322,12 @@       -- Maybe Identifier: The enum's identifier, if we need to evaluate it.       -- Reqs: Requirements to reference the enum.       -- EnumValueMap: Entries, so that we can evaluate the auto ones.-      enumExports :: [(ExtName, Maybe Type, Maybe Identifier, Reqs, EnumValueMap)]+      enumExports :: [(ExtName, Maybe Type, Scoped, Maybe Identifier, Reqs, EnumValueMap)]       enumExports = flip mapMaybe (M.elems allExports) $ \export ->         flip fmap (getExportEnumInfo export) $ \(info :: EnumInfo) ->           (enumInfoExtName info,            enumInfoNumericType info,+           enumInfoScoped info,            case (enumInfoNumericType info, validateEnumTypes) of              (Just _, False) -> Nothing  -- Don't need to evaluate sizeof().              _ -> Just $ enumInfoIdentifier info,  -- Need to evaluate sizeof().@@ -311,21 +338,42 @@       -- so.       sumReqs :: Reqs       sizeofIdentifiersToEvaluate :: [OrdIdentifier]-      entryIdentifiersToEvaluate :: [OrdIdentifier]-      (sumReqs, sizeofIdentifiersToEvaluate, entryIdentifiersToEvaluate) =-        (\(a, b, c) -> (a, b, S.toList $ S.fromList $ map OrdIdentifier c)) $-        execWriter $ forM_ enumExports $ \(_, _, maybeIdent, reqs, entries) -> do+      entriesToEvaluate :: [EnumEvaluatorEntry]+      (sumReqs, sizeofIdentifiersToEvaluate, entriesToEvaluate) =+        -- Deduplicate entries by passing them through a set.+        (\(a, b, c) -> (a, b, S.toList $ S.fromList c)) $+        execWriter $ forM_ enumExports $ \(_, _, scoped, maybeIdent, reqs, entries) -> do           tell (reqs,                 maybe [] (\i -> [OrdIdentifier i]) maybeIdent,                 [])           forM_ (M.toList $ enumValueMapValues entries) $ \(_, value) -> case value of             EnumValueManual _ -> return ()-            EnumValueAuto identifier -> tell (mempty, [], [identifier])+            EnumValueAuto identifier -> tell (mempty, [], [EnumEvaluatorEntry scoped identifier]) +  -- We currently only support evaluation of scoped enum entries in C++11+  -- and later, because we use std::underlying_type to perform the+  -- conversion of those entries to integral types, rather than doing+  -- e.g. two compilations, first determining their size.+  when (activeCppVersion < Cpp2011) $ do+    let scopedEnumsWithAutoEntries :: [ExtName] = flip mapMaybe enumExports $+          \(extName, _, _, _, _, entries) ->+            if any isAuto $ M.elems $ enumValueMapValues entries+            then Just extName+            else Nothing+        (namesToShow, namesToSkip) = splitAt 10 scopedEnumsWithAutoEntries+    unless (null scopedEnumsWithAutoEntries) $ do+      hPutStrLn stderr $+        "internalEvaluateEnumsForInterface': Automatic evaluation of enum values is not " +++        "requires at least " ++ show Cpp2011 ++ ", but we are compiling for " +++        show activeCppVersion ++ ", aborting.  Enums requesting evaluation are " +++        show namesToShow +++        (if not $ null namesToSkip then " (and more)" else "") ++ "."+      exitFailure+   -- Evaluate the identifiers we are curious about, using the hook provided by   -- the interface.   evaluatorResult :: EnumEvaluatorResult <--    case (sizeofIdentifiersToEvaluate, entryIdentifiersToEvaluate) of+    case (sizeofIdentifiersToEvaluate, entriesToEvaluate) of       ([], []) -> return emptyEnumEvaluatorResult       _ -> do         let hooks = interfaceHooks iface@@ -334,8 +382,7 @@                    , enumEvaluatorArgsReqs = sumReqs                    , enumEvaluatorArgsSizeofIdentifiers =                        map ordIdentifier sizeofIdentifiersToEvaluate-                   , enumEvaluatorArgsEntryIdentifiers =-                       map ordIdentifier entryIdentifiersToEvaluate+                   , enumEvaluatorArgsEntries = entriesToEvaluate                    , enumEvaluatorArgsKeepOutputsOnFailure = keepBuildFailures                    }         hookEvaluateEnums hooks args >>=@@ -344,7 +391,11 @@                 "internalEvaluateEnumsForInterface': Failed to build and run program.  Aborting."               exitFailure) -  let evaluatedIdentifierSizes :: M.Map OrdIdentifier Int+  let entryIdentifiersToEvaluate :: [OrdIdentifier]+      entryIdentifiersToEvaluate =+        map (OrdIdentifier . enumEvaluatorEntryIdentifier) entriesToEvaluate++      evaluatedIdentifierSizes :: M.Map OrdIdentifier Int       evaluatedIdentifierSizes =         M.fromList $ zip sizeofIdentifiersToEvaluate $ enumEvaluatorResultSizes evaluatorResult @@ -382,7 +433,8 @@   -- Build a map containing the evaluated type and numeric values for all of   -- the enums in the interface.   evaluatedDataMap :: M.Map ExtName EvaluatedEnumData <--    fmap M.fromList $ forM enumExports $ \(extName, maybeNumericType, maybeIdent, _, values) -> do+    fmap M.fromList $ forM enumExports $+    \(extName, maybeNumericType, _, maybeIdent, _, values) -> do       -- Build a map containing all of the numeric values in the enum.       numMap :: M.Map [String] Integer <-         fmap M.fromList $ forM (M.toList $ enumValueMapValues values) $ \(label, value) -> do@@ -483,3 +535,10 @@   numBytes info == bytes &&   numMinBound info <= low &&   numMaxBound info >= high++isAuto :: EnumValue -> Bool+isAuto (EnumValueAuto _) = True+isAuto (EnumValueManual _) = False++isEntryScoped :: EnumEvaluatorEntry -> Bool+isEntryScoped (EnumEvaluatorEntry scoped _) = isScoped scoped
src/Foreign/Hoppy/Generator/Spec/Base.hs view
@@ -111,6 +111,8 @@   Type (..),   normalizeType,   stripConst,+  Scoped (..),+  isScoped,   -- * Functions and parameters   Constness (..), constNegate,   Purity (..),@@ -1190,6 +1192,20 @@   Internal_TConst t' -> stripConst t'   _ -> t +-- | Indicates whether an entity is scoped or unscoped.+--+-- This is used to distinguish unscoped enums (@enum@) or scoped ones (@enum+-- class@ or @enum struct@).+data Scoped =+    Unscoped  -- ^ Indicates an unscoped entity (e.g. an enum).+  | Scoped  -- ^ Indicates a scoped entity (e.g. an enum).+  deriving (Eq, Ord, Show)++-- | Returns true if a 'Scoped' value is scoped, and false if it is unscoped.+isScoped :: Scoped -> Bool+isScoped Unscoped = False+isScoped Scoped = True+ -- | Whether or not @const@ is applied to an entity. data Constness = Nonconst | Const                deriving (Bounded, Enum, Eq, Show)@@ -1616,6 +1632,8 @@     -- 'interfaceValidateEnumTypes').   , enumInfoReqs :: Reqs     -- ^ Requirements for accessing the enum.+  , enumInfoScoped :: Scoped+    -- ^ Whether the enum is scoped or unscoped.   , enumInfoValues :: EnumValueMap     -- ^ The entries in the enum.   }
src/Foreign/Hoppy/Generator/Spec/Enum.hs view
@@ -93,6 +93,8 @@     -- using a C++ compiler.  If this is present however, Hoppy will use it, and     -- additionally validate it against what the C++ compiler thinks, if     -- validation is enabled (see 'interfaceValidateEnumTypes').+  , enumScoped :: Scoped+    -- ^ Whether the enum is scoped or unscoped.   , enumValues :: EnumValueMap     -- ^ The numeric values and names of the enum entires.   , enumReqs :: Reqs@@ -154,6 +156,7 @@     , enumInfoIdentifier = enumIdentifier e     , enumInfoNumericType = enumNumericType e     , enumInfoReqs = enumReqs e+    , enumInfoScoped = enumScoped e     , enumInfoValues = enumValues e     } @@ -198,6 +201,7 @@      extName      identifier      Nothing+     Unscoped  -- Assume this is an unscoped enum.      (let entries' = for entries $ \(num, words') -> (words', EnumValueManual num)           entryNames = map fst entries'       in EnumValueMap@@ -221,7 +225,7 @@   -> Maybe ExtName   -- ^ An optional external name; will be automatically derived from the   -- identifier if absent.-  -> Bool+  -> Scoped   -- ^ Is the enum scoped (@enum class@ or @enum struct@)?  That is, are its   -- entries scoped underneath its name, rather than being at the same level as   -- its name (as with just @enum@).@@ -235,10 +239,10 @@      extName      identifier      Nothing-     (let namespaceForValues =-            if scoped-            then identifier-            else makeIdentifier $ butLast $ identifierParts identifier+     scoped+     (let namespaceForValues = case scoped of+            Scoped -> identifier+            Unscoped -> makeIdentifier $ butLast $ identifierParts identifier           entries' =             map (fmap (\name -> namespaceForValues `mappend` ident name) .                  toAutoEnumValue)