hoppy-generator 0.7.1 → 0.8.0
raw patch · 33 files changed
+575/−213 lines, 33 filessetup-changedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Foreign.Hoppy.Generator.Spec: EvaluatedEnumData :: Type -> EvaluatedEnumValueMap -> EvaluatedEnumData
- Foreign.Hoppy.Generator.Spec: [evaluatedEnumType] :: EvaluatedEnumData -> Type
- Foreign.Hoppy.Generator.Spec: [evaluatedEnumValueMap] :: EvaluatedEnumData -> EvaluatedEnumValueMap
- Foreign.Hoppy.Generator.Spec: data EvaluatedEnumData
- Foreign.Hoppy.Generator.Spec: interfaceEvaluatedEnumData :: Interface -> Maybe (Map ExtName EvaluatedEnumData)
- Foreign.Hoppy.Generator.Spec: interfaceGetEvaluatedEnumData :: HasCallStack => Interface -> ExtName -> EvaluatedEnumData
- Foreign.Hoppy.Generator.Spec: type EvaluatedEnumValueMap = Map [String] Integer
+ Foreign.Hoppy.Generator.Compiler: [ccHeaderSearchPath] :: CustomCompiler -> [FilePath]
+ Foreign.Hoppy.Generator.Compiler: prependIncludePath :: Compiler a => [FilePath] -> a -> a
+ Foreign.Hoppy.Generator.Hook: [enumEvaluatorArgsPrependedIncludeDirs] :: EnumEvaluatorArgs -> [FilePath]
+ Foreign.Hoppy.Generator.Hook: data NumericTypeInfo
+ Foreign.Hoppy.Generator.Hook: pickNumericType :: Int -> Integer -> Integer -> Maybe NumericTypeInfo
+ Foreign.Hoppy.Generator.Language.Cpp: askComputedInterfaceData :: Generator ComputedInterfaceData
+ Foreign.Hoppy.Generator.Language.Haskell: [envComputedInterfaceData] :: Env -> ComputedInterfaceData
+ Foreign.Hoppy.Generator.Language.Haskell: askComputedInterfaceData :: Generator ComputedInterfaceData
+ Foreign.Hoppy.Generator.Main: CleanCpp :: FilePath -> Action
+ Foreign.Hoppy.Generator.Main: CleanHs :: FilePath -> Action
+ Foreign.Hoppy.Generator.Main: EnumCacheMustExist :: EnumEvalCacheMode
+ Foreign.Hoppy.Generator.Main: EnumEvalCacheMode :: EnumEvalCacheMode -> Action
+ Foreign.Hoppy.Generator.Main: EnumEvalCachePath :: Maybe FilePath -> Action
+ Foreign.Hoppy.Generator.Main: RefreshEnumCache :: EnumEvalCacheMode
+ Foreign.Hoppy.Generator.Main: data EnumEvalCacheMode
+ Foreign.Hoppy.Generator.Main: ensureInterfaces :: [Either String Interface] -> IO [Interface]
+ Foreign.Hoppy.Generator.Spec.Computed: ComputedInterfaceData :: String -> Map ExtName EvaluatedEnumData -> ComputedInterfaceData
+ Foreign.Hoppy.Generator.Spec.Computed: EvaluatedEnumData :: NumericTypeInfo -> EvaluatedEnumValueMap -> EvaluatedEnumData
+ Foreign.Hoppy.Generator.Spec.Computed: [computedInterfaceName] :: ComputedInterfaceData -> String
+ Foreign.Hoppy.Generator.Spec.Computed: [evaluatedEnumMap] :: ComputedInterfaceData -> Map ExtName EvaluatedEnumData
+ Foreign.Hoppy.Generator.Spec.Computed: [evaluatedEnumNumericType] :: EvaluatedEnumData -> NumericTypeInfo
+ Foreign.Hoppy.Generator.Spec.Computed: [evaluatedEnumValueMap] :: EvaluatedEnumData -> EvaluatedEnumValueMap
+ Foreign.Hoppy.Generator.Spec.Computed: data ComputedInterfaceData
+ Foreign.Hoppy.Generator.Spec.Computed: data EvaluatedEnumData
+ Foreign.Hoppy.Generator.Spec.Computed: data NumericTypeInfo
+ Foreign.Hoppy.Generator.Spec.Computed: findNumericTypeInfo :: Type -> Maybe NumericTypeInfo
+ Foreign.Hoppy.Generator.Spec.Computed: getEvaluatedEnumData :: HasCallStack => ComputedInterfaceData -> ExtName -> EvaluatedEnumData
+ Foreign.Hoppy.Generator.Spec.Computed: instance GHC.Read.Read Foreign.Hoppy.Generator.Spec.Computed.EvaluatedEnumData
+ Foreign.Hoppy.Generator.Spec.Computed: instance GHC.Read.Read Foreign.Hoppy.Generator.Spec.Computed.NumericTypeInfo
+ Foreign.Hoppy.Generator.Spec.Computed: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Computed.EvaluatedEnumData
+ Foreign.Hoppy.Generator.Spec.Computed: instance GHC.Show.Show Foreign.Hoppy.Generator.Spec.Computed.NumericTypeInfo
+ Foreign.Hoppy.Generator.Spec.Computed: numBytes :: NumericTypeInfo -> Int
+ Foreign.Hoppy.Generator.Spec.Computed: numMaxBound :: NumericTypeInfo -> Integer
+ Foreign.Hoppy.Generator.Spec.Computed: numMinBound :: NumericTypeInfo -> Integer
+ Foreign.Hoppy.Generator.Spec.Computed: numType :: NumericTypeInfo -> Type
+ Foreign.Hoppy.Generator.Spec.Computed: pickNumericType :: Int -> Integer -> Integer -> Maybe NumericTypeInfo
+ Foreign.Hoppy.Generator.Spec.Computed: type EvaluatedEnumValueMap = Map [String] Integer
- Foreign.Hoppy.Generator.Compiler: CustomCompiler :: String -> (FilePath -> FilePath -> IO Bool) -> CustomCompiler
+ Foreign.Hoppy.Generator.Compiler: CustomCompiler :: String -> (CustomCompiler -> FilePath -> FilePath -> IO Bool) -> [FilePath] -> CustomCompiler
- Foreign.Hoppy.Generator.Compiler: [ccCompile] :: CustomCompiler -> FilePath -> FilePath -> IO Bool
+ Foreign.Hoppy.Generator.Compiler: [ccCompile] :: CustomCompiler -> CustomCompiler -> FilePath -> FilePath -> IO Bool
- Foreign.Hoppy.Generator.Hook: EnumEvaluatorArgs :: Interface -> Reqs -> [Identifier] -> [EnumEvaluatorEntry] -> Bool -> EnumEvaluatorArgs
+ Foreign.Hoppy.Generator.Hook: EnumEvaluatorArgs :: Interface -> [FilePath] -> Reqs -> [Identifier] -> [EnumEvaluatorEntry] -> Bool -> EnumEvaluatorArgs
- Foreign.Hoppy.Generator.Hook: internalEvaluateEnumsForInterface :: Interface -> Bool -> IO Interface
+ Foreign.Hoppy.Generator.Hook: internalEvaluateEnumsForInterface :: Interface -> Maybe FilePath -> Bool -> IO (Map ExtName EvaluatedEnumData)
- Foreign.Hoppy.Generator.Language.Cpp: execGenerator :: Interface -> Module -> Maybe String -> Generator a -> Either ErrorMsg String
+ Foreign.Hoppy.Generator.Language.Cpp: execGenerator :: Interface -> ComputedInterfaceData -> Module -> Maybe String -> Generator a -> Either ErrorMsg String
- Foreign.Hoppy.Generator.Language.Haskell: Env :: Interface -> Module -> String -> Env
+ Foreign.Hoppy.Generator.Language.Haskell: Env :: Interface -> ComputedInterfaceData -> Module -> String -> Env
- Foreign.Hoppy.Generator.Language.Haskell: evalGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg a
+ Foreign.Hoppy.Generator.Language.Haskell: evalGenerator :: Interface -> ComputedInterfaceData -> Module -> Generator a -> Either ErrorMsg a
- Foreign.Hoppy.Generator.Language.Haskell: execGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg Partial
+ Foreign.Hoppy.Generator.Language.Haskell: execGenerator :: Interface -> ComputedInterfaceData -> Module -> Generator a -> Either ErrorMsg Partial
- Foreign.Hoppy.Generator.Language.Haskell: runGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg (Partial, a)
+ Foreign.Hoppy.Generator.Language.Haskell: runGenerator :: Interface -> ComputedInterfaceData -> Module -> Generator a -> Either ErrorMsg (Partial, a)
Files
- Setup.hs +1/−1
- hoppy-generator.cabal +4/−3
- src/Foreign/Hoppy/Generator/Common.hs +1/−1
- src/Foreign/Hoppy/Generator/Common/Consume.hs +1/−1
- src/Foreign/Hoppy/Generator/Compiler.hs +37/−4
- src/Foreign/Hoppy/Generator/Hook.hs +35/−58
- src/Foreign/Hoppy/Generator/Hook.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Language/Cpp.hs +17/−5
- src/Foreign/Hoppy/Generator/Language/Cpp.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Language/Cpp/Internal.hs +5/−5
- src/Foreign/Hoppy/Generator/Language/Haskell.hs +25/−8
- src/Foreign/Hoppy/Generator/Language/Haskell.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Language/Haskell/Internal.hs +5/−5
- src/Foreign/Hoppy/Generator/Main.hs +237/−54
- src/Foreign/Hoppy/Generator/Override.hs +1/−1
- src/Foreign/Hoppy/Generator/Spec.hs +7/−5
- src/Foreign/Hoppy/Generator/Spec/Base.hs +15/−35
- src/Foreign/Hoppy/Generator/Spec/Base.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Spec/Callback.hs +1/−1
- src/Foreign/Hoppy/Generator/Spec/Callback.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Spec/Class.hs +1/−1
- src/Foreign/Hoppy/Generator/Spec/Class.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Spec/ClassFeature.hs +1/−1
- src/Foreign/Hoppy/Generator/Spec/Computed.hs +131/−0
- src/Foreign/Hoppy/Generator/Spec/Conversion.hs +1/−1
- src/Foreign/Hoppy/Generator/Spec/Enum.hs +36/−10
- src/Foreign/Hoppy/Generator/Spec/Enum.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Spec/Function.hs +1/−1
- src/Foreign/Hoppy/Generator/Spec/Function.hs-boot +1/−1
- src/Foreign/Hoppy/Generator/Spec/Variable.hs +1/−1
- src/Foreign/Hoppy/Generator/Types.hs +1/−1
- src/Foreign/Hoppy/Generator/Util.hs +1/−1
- src/Foreign/Hoppy/Generator/Version.hs +1/−1
Setup.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
hoppy-generator.cabal view
@@ -1,15 +1,15 @@ name: hoppy-generator-version: 0.7.1+version: 0.8.0 synopsis: C++ FFI generator - Code generator homepage: http://khumba.net/projects/hoppy license: AGPL-3 license-file: LICENSE author: Bryan Gardiner <bog@khumba.net> maintainer: Bryan Gardiner <bog@khumba.net>-copyright: Copyright 2015-2020 Bryan Gardiner+copyright: Copyright 2015-2021 Bryan Gardiner category: Foreign build-type: Simple-cabal-version: >=1.10+cabal-version: 1.24 description: Hoppy generates Haskell bindings to C++ libraries. .@@ -27,6 +27,7 @@ , Foreign.Hoppy.Generator.Spec.Callback , Foreign.Hoppy.Generator.Spec.ClassFeature , Foreign.Hoppy.Generator.Spec.Class+ , Foreign.Hoppy.Generator.Spec.Computed , Foreign.Hoppy.Generator.Spec.Enum , Foreign.Hoppy.Generator.Spec.Function , Foreign.Hoppy.Generator.Spec.Variable
src/Foreign/Hoppy/Generator/Common.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Common/Consume.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Compiler.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -51,6 +51,10 @@ -- error, and false is returned. compileProgram :: a -> FilePath -> FilePath -> IO Bool + -- | Modifies the compiler to prepend the given paths to the header search+ -- path.+ prependIncludePath :: [FilePath] -> a -> a+ -- | An existential data type for 'Compiler's. data SomeCompiler = forall a. Compiler a => SomeCompiler a @@ -60,6 +64,8 @@ instance Compiler SomeCompiler where compileProgram (SomeCompiler c) = compileProgram c + prependIncludePath paths (SomeCompiler c) = SomeCompiler $ prependIncludePath paths c+ -- | A compiler that can compile a source file into a binary with a single -- program invocation. --@@ -87,6 +93,12 @@ (scArguments compiler) (M.fromList [("in", inPath), ("out", outPath)]) + prependIncludePath paths compiler =+ compiler { scArguments =+ concatMap (\path -> ["-I", path]) paths +++ scArguments compiler+ }+ -- | Adds arguments to the start of a compiler's argument list. prependArguments :: [String] -> SimpleCompiler -> SimpleCompiler prependArguments args compiler =@@ -119,20 +131,41 @@ { ccLabel :: String -- ^ A label to display when the compiler is 'show'n. The string is -- @\"\<CustomCompiler \" ++ label ++ \">\"@.- , ccCompile :: FilePath -> FilePath -> IO Bool++ , ccCompile :: CustomCompiler -> FilePath -> FilePath -> IO Bool -- ^ Given a source file path and an output path, compiles the source file, -- producing a binary at the output path. Returns true on success. Logs to -- standard error and returns false on failure.+ --+ -- This should inspect the compiler argument to make use of its+ -- 'ccHeaderSearchPath'.+ --+ -- The first argument is the 'CustomCompiler' object that this function was+ -- pulled out of. This is passed in explicitly by 'compileProgram' because+ -- due to the presence of 'prependIncludePath' it's not always possible to+ -- have access to the final compiler object ahead of time.++ , ccHeaderSearchPath :: [FilePath]+ -- ^ Paths to be searched for C++ header files, in addition to the+ -- compiler's default search directories. } instance Show CustomCompiler where show c = "<CustomCompiler " ++ ccLabel c ++ ">" instance Compiler CustomCompiler where- compileProgram = ccCompile+ compileProgram c = ccCompile c c + prependIncludePath paths c =+ c { ccHeaderSearchPath = paths ++ ccHeaderSearchPath c }+ -- | The default compiler, used by an 'Foreign.Hoppy.Generator.Spec.Interface'--- that doesn't specify its own. This is:+-- that doesn't specify its own. This will be 'gppCompiler', however if the+-- environment variables @CXX@ or @CXXFLAGS@ are set and nonempty, they will be+-- used. @CXX@ will override the path to the compiler used, and @CXXFLAGS@ will+-- be split on spaces and appended to the compiler's argument list.+--+-- Specifically, this is defined as: -- -- @'unsafePerformIO' $ 'overrideCompilerFromEnvironment' 'gppCompiler'@ defaultCompiler :: SimpleCompiler
src/Foreign/Hoppy/Generator/Hook.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -31,6 +31,8 @@ makeCppSourceToEvaluateEnums, interpretOutputToEvaluateEnums, -- * Internal+ NumericTypeInfo (..),+ pickNumericType, internalEvaluateEnumsForInterface, ) where @@ -46,18 +48,27 @@ import Data.List (splitAt) #endif import qualified Data.Map as M-import Data.Maybe (isJust, listToMaybe, mapMaybe)+import Data.Maybe (isJust, mapMaybe, maybeToList) import qualified Data.Set as S-import Foreign.C (CInt, CLong, CLLong, CUInt, CULong, CULLong) import Foreign.Hoppy.Generator.Common (doubleQuote, for, fromMaybeM, pluralize) import Foreign.Hoppy.Generator.Common.Consume (MonadConsume, evalConsume, next)-import Foreign.Hoppy.Generator.Compiler (Compiler, SomeCompiler (SomeCompiler), compileProgram)+import Foreign.Hoppy.Generator.Compiler (+ Compiler,+ SomeCompiler (SomeCompiler),+ compileProgram,+ prependIncludePath,+ ) import Foreign.Hoppy.Generator.Language.Cpp (renderIdentifier) import Foreign.Hoppy.Generator.Spec.Base-import Foreign.Hoppy.Generator.Types (intT, llongT, longT, uintT, ullongT, ulongT)+import Foreign.Hoppy.Generator.Spec.Computed (+ EvaluatedEnumData (..),+ NumericTypeInfo,+ findNumericTypeInfo,+ numBytes,+ pickNumericType,+ ) 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) import System.Process (readProcessWithExitCode)@@ -90,6 +101,8 @@ data EnumEvaluatorArgs = EnumEvaluatorArgs { enumEvaluatorArgsInterface :: Interface -- ^ The interface that enum values are being calculated for.+ , enumEvaluatorArgsPrependedIncludeDirs :: [FilePath]+ -- ^ Additional paths to prepend to the C++ include path during compilation. , enumEvaluatorArgsReqs :: Reqs -- ^ Requirements (includes, etc.) needed to reference the enum identifiers -- being evaluated.@@ -150,17 +163,21 @@ -- | Evaluate enums using a specified compiler. evaluateEnumsWithCompiler :: Compiler a => a -> EnumEvaluator evaluateEnumsWithCompiler compiler args =+ let compiler' = case enumEvaluatorArgsPrependedIncludeDirs args of+ [] -> compiler+ dirs -> prependIncludePath dirs compiler+ in withTempFile "hoppy-enum.cpp" removeBuildFailures $ \cppPath cppHandle -> withTempFile "hoppy-enum" removeBuildFailures $ \binPath binHandle -> do hPut cppHandle program hClose cppHandle hClose binHandle- success <- compileProgram compiler cppPath binPath+ success <- compileProgram compiler' cppPath binPath result <- case success of False -> do hPutStrLn stderr $ "evaluateEnumsWithCompiler: Failed to build program " ++ show cppPath ++- " to evaluate enums with " ++ show compiler ++ "." ++ removeBuildFailuresNote+ " to evaluate enums with " ++ show compiler' ++ "." ++ removeBuildFailuresNote return Nothing True -> runAndGetOutput binPath let remove = isJust result || removeBuildFailures@@ -304,14 +321,12 @@ -- | Collects all of the enum values that need calculating in an interface, runs -- the hook to evaluate them, and stores the result in the interface. This -- won't recalculate enum data if it's already been calculated.-internalEvaluateEnumsForInterface :: Interface -> Bool -> IO Interface-internalEvaluateEnumsForInterface iface keepBuildFailures =- case interfaceEvaluatedEnumData iface of- Just _ -> return iface- Nothing -> internalEvaluateEnumsForInterface' iface keepBuildFailures--internalEvaluateEnumsForInterface' :: Interface -> Bool -> IO Interface-internalEvaluateEnumsForInterface' iface keepBuildFailures = do+internalEvaluateEnumsForInterface ::+ Interface+ -> Maybe FilePath+ -> Bool+ -> IO (M.Map ExtName EvaluatedEnumData)+internalEvaluateEnumsForInterface iface maybeCppDir keepBuildFailures = do let validateEnumTypes = interfaceValidateEnumTypes iface -- Collect all exports in the interface.@@ -367,7 +382,7 @@ (namesToShow, namesToSkip) = splitAt 10 scopedEnumsWithAutoEntries unless (null scopedEnumsWithAutoEntries) $ do hPutStrLn stderr $- "internalEvaluateEnumsForInterface': Automatic evaluation of enum values is not " +++ "internalEvaluateEnumsForInterface': Automatic evaluation of enum values " ++ "requires at least " ++ show Cpp2011 ++ ", but we are compiling for " ++ show activeCppVersion ++ ", aborting. Enums requesting evaluation are " ++ show namesToShow ++@@ -383,6 +398,7 @@ let hooks = interfaceHooks iface args = EnumEvaluatorArgs { enumEvaluatorArgsInterface = iface+ , enumEvaluatorArgsPrependedIncludeDirs = maybeToList maybeCppDir , enumEvaluatorArgsReqs = sumReqs , enumEvaluatorArgsSizeofIdentifiers = map ordIdentifier sizeofIdentifiersToEvaluate@@ -487,12 +503,12 @@ pickNumericType bytes low high let result = EvaluatedEnumData- { evaluatedEnumType = numericType+ { evaluatedEnumNumericType = numericType , evaluatedEnumValueMap = numMap } return (extName, result) - return iface { interfaceEvaluatedEnumData = Just evaluatedDataMap }+ return evaluatedDataMap newtype OrdIdentifier = OrdIdentifier { ordIdentifier :: Identifier } deriving (Eq, Show)@@ -500,45 +516,6 @@ instance Ord OrdIdentifier where compare (OrdIdentifier i1) (OrdIdentifier i2) = compare (renderIdentifier i1) (renderIdentifier i2)---- | Bound information about numeric types.-data NumericTypeInfo = NumericTypeInfo- { numType :: Type- , numBytes :: Int- , numMinBound :: Integer- , numMaxBound :: Integer- }---- | Numeric types usable to hold enum values. These are ordered by decreasing--- precedence (increasing word size).-numericTypeInfo :: [NumericTypeInfo]-numericTypeInfo =- [ mk intT (undefined :: CInt)- , mk uintT (undefined :: CUInt)- , mk longT (undefined :: CLong)- , mk ulongT (undefined :: CULong)- , mk llongT (undefined :: CLLong)- , mk ullongT (undefined :: CULLong)- ]- where mk :: forall a. (Bounded a, Integral a, Storable a) => Type -> a -> NumericTypeInfo- mk t _ = NumericTypeInfo- { numType = t- , numBytes = sizeOf (undefined :: a)- , numMinBound = toInteger (minBound :: a)- , numMaxBound = toInteger (maxBound :: a)- }--findNumericTypeInfo :: Type -> Maybe NumericTypeInfo-findNumericTypeInfo t = listToMaybe $ filter (\i -> numType i == t) numericTypeInfo---- | Selects the preferred numeric type for holding numeric values in the given--- range.-pickNumericType :: Int -> Integer -> Integer -> Maybe Type-pickNumericType bytes low high =- fmap numType $ listToMaybe $ flip filter numericTypeInfo $ \info ->- numBytes info == bytes &&- numMinBound info <= low &&- numMaxBound info >= high isAuto :: EnumValue -> Bool isAuto (EnumValueAuto _) = True
src/Foreign/Hoppy/Generator/Hook.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Language/Cpp.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -24,7 +24,7 @@ Env, execGenerator, addIncludes, addInclude, addReqsM,- askInterface, askModule, abort,+ askInterface, askComputedInterfaceData, askModule, abort, -- * Names makeCppName, externalNameToCpp,@@ -70,6 +70,7 @@ import qualified Data.Set as S import Foreign.Hoppy.Generator.Common import Foreign.Hoppy.Generator.Spec.Base+import Foreign.Hoppy.Generator.Spec.Computed (ComputedInterfaceData) import {-# SOURCE #-} Foreign.Hoppy.Generator.Spec.Class (classIdentifier, classReqs) import Foreign.Hoppy.Generator.Types @@ -81,14 +82,21 @@ -- | Context information for generating C++ code. data Env = Env { envInterface :: Interface+ , envComputedInterfaceData :: ComputedInterfaceData , envModule :: Module } -- | Runs a generator action and returns its output, or an error message if -- unsuccessful.-execGenerator :: Interface -> Module -> Maybe String -> Generator a -> Either ErrorMsg String-execGenerator iface m maybeHeaderGuardName action = do- chunk <- execChunkWriterT $ runReaderT action $ Env iface m+execGenerator ::+ Interface+ -> ComputedInterfaceData+ -> Module+ -> Maybe String+ -> Generator a+ -> Either ErrorMsg String+execGenerator iface computed m maybeHeaderGuardName action = do+ chunk <- execChunkWriterT $ runReaderT action $ Env iface computed m let contents = chunkContents chunk includes = chunkIncludes chunk return $ chunkContents $ execChunkWriter $ do@@ -125,6 +133,10 @@ -- | Returns the currently generating interface. askInterface :: MonadReader Env m => m Interface askInterface = fmap envInterface ask++-- | Returns the computed data for the currently generating interface.+askComputedInterfaceData :: Generator ComputedInterfaceData+askComputedInterfaceData = fmap envComputedInterfaceData ask -- | Returns the currently generating module. askModule :: MonadReader Env m => m Module
src/Foreign/Hoppy/Generator/Language/Cpp.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Language/Cpp/Internal.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -51,15 +51,15 @@ } -- | Runs the C++ code generator against an interface.-generate :: Interface -> Either ErrorMsg Generation-generate iface =+generate :: Interface -> ComputedInterfaceData -> Either ErrorMsg Generation+generate iface computed = fmap (Generation . M.fromList) $ execWriterT $ forM_ (M.elems $ interfaceModules iface) $ \m -> do let headerGuard = concat ["HOPPY_MODULE_", interfaceName iface, "_", moduleName m]- header <- lift $ execGenerator iface m (Just headerGuard) sayModuleHeader+ header <- lift $ execGenerator iface computed m (Just headerGuard) sayModuleHeader tell [(moduleHppPath m, header)]- source <- lift $ execGenerator iface m Nothing sayModuleSource+ source <- lift $ execGenerator iface computed m Nothing sayModuleSource tell [(moduleCppPath m, source)] sayModuleHeader :: Generator ()
src/Foreign/Hoppy/Generator/Language/Haskell.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -33,6 +33,7 @@ renderPartial, Env (..), askInterface,+ askComputedInterfaceData, askModule, askModuleName, getModuleForExtName,@@ -90,6 +91,7 @@ import Data.Tuple (swap) import Foreign.Hoppy.Generator.Common import Foreign.Hoppy.Generator.Spec.Base+import Foreign.Hoppy.Generator.Spec.Computed (ComputedInterfaceData) import {-# SOURCE #-} Foreign.Hoppy.Generator.Spec.Class ( Class, ClassHaskellConversion,@@ -242,6 +244,7 @@ -- | Context information for generating Haskell code. data Env = Env { envInterface :: Interface+ , envComputedInterfaceData :: ComputedInterfaceData , envModule :: Module , envModuleName :: String }@@ -250,6 +253,10 @@ askInterface :: Generator Interface askInterface = asks envInterface +-- | Returns the computed data for the currently generating interface.+askComputedInterfaceData :: Generator ComputedInterfaceData+askComputedInterfaceData = asks envComputedInterfaceData+ -- | Returns the currently generating module. askModule :: Generator Module askModule = asks envModule@@ -317,21 +324,31 @@ -- | Runs a generator action for the given interface and module name string. -- Returns an error message if an error occurred, otherwise the action's output -- together with its value.-runGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg (Partial, a)-runGenerator iface m generator =+runGenerator ::+ Interface+ -> ComputedInterfaceData+ -> Module+ -> Generator a+ -> Either ErrorMsg (Partial, a)+runGenerator iface computed m generator = let modName = getModuleName iface m in fmap (first (Partial modName) . swap) $ runExcept $ flip catchError (\msg -> throwError $ msg ++ ".") $- runWriterT $ runReaderT generator $ Env iface m modName+ runWriterT $ runReaderT generator $ Env iface computed m modName -- | Runs a generator action and returns the its value.-evalGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg a-evalGenerator iface m = fmap snd . runGenerator iface m+evalGenerator :: Interface -> ComputedInterfaceData -> Module -> Generator a -> Either ErrorMsg a+evalGenerator iface computed m = fmap snd . runGenerator iface computed m -- | Runs a generator action and returns its output.-execGenerator :: Interface -> Module -> Generator a -> Either ErrorMsg Partial-execGenerator iface m = fmap fst . runGenerator iface m+execGenerator ::+ Interface+ -> ComputedInterfaceData+ -> Module+ -> Generator a+ -> Either ErrorMsg Partial+execGenerator iface computed m = fmap fst . runGenerator iface computed m -- | Converts a 'Partial' into a complete Haskell module. renderPartial :: Partial -> String
src/Foreign/Hoppy/Generator/Language/Haskell.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Language/Haskell/Internal.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -58,11 +58,11 @@ } -- | Runs the C++ code generator against an interface.-generate :: Interface -> Either ErrorMsg Generation-generate iface = do+generate :: Interface -> ComputedInterfaceData -> Either ErrorMsg Generation+generate iface computed = do -- Build the partial generation of each module. modPartials <- forM (M.elems $ interfaceModules iface) $ \m ->- (,) m <$> execGenerator iface m (generateSource m)+ (,) m <$> execGenerator iface computed m (generateSource m) -- Compute the strongly connected components. If there is a nontrivial SCC, -- then there is a module import cycle that we'll have to break with hs-boot@@ -85,7 +85,7 @@ let cycleModNames = S.fromList $ map (partialModuleHsName . snd) mps forM_ mps $ \(m, p) -> do -- Create a boot partial.- pBoot <- lift $ execGenerator iface m (generateBootSource m)+ pBoot <- lift $ execGenerator iface computed m (generateBootSource m) -- Change the source and boot partials so that all imports of modules in -- this cycle are {-# SOURCE #-} imports.
src/Foreign/Hoppy/Generator/Main.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -33,8 +33,10 @@ -- @ module Foreign.Hoppy.Generator.Main ( Action (..),+ EnumEvalCacheMode (..), defaultMain, defaultMain',+ ensureInterfaces, run, ) where @@ -55,7 +57,7 @@ import qualified Foreign.Hoppy.Generator.Language.Cpp.Internal as Cpp import qualified Foreign.Hoppy.Generator.Language.Haskell.Internal as Haskell import Foreign.Hoppy.Generator.Spec-import System.Directory (createDirectoryIfMissing, doesDirectoryExist)+import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, removeFile) import System.Environment (getArgs) import System.Exit (exitFailure, exitSuccess) import System.FilePath ((</>), takeDirectory)@@ -75,6 +77,10 @@ -- ^ Generates C++ wrappers for an interface in the given location. | GenHaskell FilePath -- ^ Generates Haskell bindings for an interface in the given location.+ | CleanCpp FilePath+ -- ^ Removes the generated files in C++ bindings.+ | CleanHs FilePath+ -- ^ Removes the generated files in Haskell bindings. | KeepTempOutputsOnFailure -- ^ Instructs the generator to keep on disk any temporary programs or files -- created, in case of failure.@@ -83,14 +89,45 @@ -- interface. | DumpEnums -- ^ Dumps to stdout information about all enums in the current interface.+ | EnumEvalCachePath (Maybe FilePath)+ -- ^ Specifies the path to a enum evaluation cache file to use.+ | EnumEvalCacheMode EnumEvalCacheMode+ -- ^ Specifies the behaviour with respect to how the enum evaluation cache+ -- cache file is used. data AppState = AppState { appInterfaces :: Map String Interface , appCurrentInterfaceName :: String , appCaches :: Caches , appKeepTempOutputsOnFailure :: Bool+ , appEnumEvalCachePath :: Maybe FilePath+ , appEnumEvalCacheMode :: EnumEvalCacheMode } +-- | Controls the behaviour of a generatior with respect to the enum cache file,+-- when a file path provided (@--enum-eval-cache-path@).+--+-- If enum evaluation is required, based on the presence of the cache file and+-- which of these modes is selected, then the compiler will be called and the+-- results will be written to the cache file+--+-- If an enum cache file path is not provided, then this mode is ignored, and+-- enum evaluation is attempted if a generator requires it.+--+-- Change detection is not currently supported. There is no ability to detect+-- whether the cache file is up to date and contains all of the enum entries for+-- the current state of the enums defined in an interface. The cache file is+-- meant to be refreshed with 'RefreshEnumCache' when building the C++ binding+-- package, and installed with them so that the Haskell binding package can use+-- 'EnumCacheMustExist'.+data EnumEvalCacheMode =+ RefreshEnumCache+ -- ^ The default. Ignore the presence of an existing cache file, and+ -- evaluate enums freshly, updating the cache file with new contents.+ | EnumCacheMustExist+ -- ^ Require the cache file to exist. If it does not, enum evaluation will+ -- not be attempted; the generator will exit unsuccessfully instead.+ appCurrentInterface :: AppState -> Interface appCurrentInterface state = let name = appCurrentInterfaceName state@@ -107,49 +144,118 @@ , appCurrentInterfaceName = interfaceName $ head ifaces , appCaches = M.empty , appKeepTempOutputsOnFailure = False+ , appEnumEvalCachePath = Nothing+ , appEnumEvalCacheMode = RefreshEnumCache } type Caches = Map String InterfaceCache data InterfaceCache = InterfaceCache- { generatedCpp :: Maybe Cpp.Generation- , generatedHaskell :: Maybe Haskell.Generation+ { cacheGeneratedCpp :: Maybe Cpp.Generation+ , cacheGeneratedHaskell :: Maybe Haskell.Generation+ , cacheComputedData :: Maybe ComputedInterfaceData } emptyCache :: InterfaceCache-emptyCache = InterfaceCache Nothing Nothing+emptyCache = InterfaceCache Nothing Nothing Nothing getGeneratedCpp ::- AppState+ Maybe FilePath+ -> AppState -> Interface -> InterfaceCache- -> IO (Interface, InterfaceCache, Either String Cpp.Generation)-getGeneratedCpp state iface cache = case generatedCpp cache of- Just gen -> return (iface, cache, Right gen)- _ -> do- iface' <- evaluateEnums state iface- case Cpp.generate iface' of- l@(Left _) -> return (iface', cache, l)- r@(Right gen) -> return (iface', cache { generatedCpp = Just gen }, r)+ -> IO (InterfaceCache, Either String Cpp.Generation)+getGeneratedCpp maybeCppDir state iface cache = case cacheGeneratedCpp cache of+ Just gen -> return (cache, Right gen)+ Nothing -> do+ cache' <- generateComputedData maybeCppDir state iface cache+ computedData <- flip fromMaybeM (cacheComputedData cache') $ do+ hPutStrLn stderr $+ "getGeneratedCpp: Expected computed data to already exist for " ++ show iface ++ "."+ exitFailure+ case Cpp.generate iface computedData of+ l@(Left _) -> return (cache', l)+ r@(Right gen) -> return (cache' { cacheGeneratedCpp = Just gen }, r) getGeneratedHaskell :: AppState -> Interface -> InterfaceCache- -> IO (Interface, InterfaceCache, Either String Haskell.Generation)-getGeneratedHaskell state iface cache = case generatedHaskell cache of- Just gen -> return (iface, cache, Right gen)- _ -> do- iface' <- evaluateEnums state iface- case Haskell.generate iface' of- l@(Left _) -> return (iface', cache, l)- r@(Right gen) -> return (iface', cache { generatedHaskell = Just gen }, r)+ -> IO (InterfaceCache, Either String Haskell.Generation)+getGeneratedHaskell state iface cache = case cacheGeneratedHaskell cache of+ Just gen -> return (cache, Right gen)+ Nothing -> do+ cache' <- generateComputedData Nothing state iface cache+ computedData <- flip fromMaybeM (cacheComputedData cache') $ do+ hPutStrLn stderr $+ "getGeneratedHaskell: Expected computed data to already exist for " ++ show iface ++ "."+ exitFailure+ case Haskell.generate iface computedData of+ l@(Left _) -> return (cache', l)+ r@(Right gen) -> return (cache' { cacheGeneratedHaskell = Just gen }, r) -evaluateEnums :: AppState -> Interface -> IO Interface-evaluateEnums state iface =- internalEvaluateEnumsForInterface iface $- appKeepTempOutputsOnFailure state+-- | Ensures that the cached computed data for an interface been calculated,+-- doing so if it hasn't.+--+-- This ensures that the 'ComputedInterfaceData' for an 'Interface' has been+-- calculated. This is only computed once for an interface, and is stored in+-- the interface's 'InterfaceCache'. This function returns the resulting cache+-- with the computed data populated.+generateComputedData ::+ Maybe FilePath+ -> AppState+ -> Interface+ -> InterfaceCache+ -> IO InterfaceCache+generateComputedData maybeCppDir state iface cache = case cacheComputedData cache of+ Just _ -> return cache+ Nothing -> do+ evaluatedEnumMap <- generateEnumData state iface maybeCppDir+ return cache+ { cacheComputedData = Just ComputedInterfaceData+ { computedInterfaceName = interfaceName iface+ , evaluatedEnumMap = evaluatedEnumMap+ }+ } +-- | Generates evaluated enum data for storing in the interface cache.+--+-- If there is a cache path provided, and the file exists, then it is loaded and+-- used. Otherwise, if there is a cache path provided and the file doesn't+-- exist, but a cache path is set to be required ('appEnumEvalCacheRequire'),+-- then generation aborts. Otherwise, the enum evaluation hook is called to+-- evaluate the enums (see "Foreign.Hoppy.Generator.Hook"), and if a cache path+-- is provided, then the result is serialized and written to the path.+generateEnumData :: AppState -> Interface -> Maybe FilePath -> IO (Map ExtName EvaluatedEnumData)+generateEnumData state iface maybeCppDir =+ case appEnumEvalCachePath state of+ Nothing -> doEnumEval+ Just path -> do+ cached <- doesFileExist path+ case (appEnumEvalCacheMode state, cached) of+ (RefreshEnumCache, _) -> evalAndWriteFile path+ (EnumCacheMustExist, True) -> useFile path+ (EnumCacheMustExist, False) -> do+ hPutStrLn stderr $+ "generateEnumData: Error, enum evaluation cache expected for " +++ show iface ++ ", but none found at path '" ++ path ++ "'."+ exitFailure++ where useFile path = deserializeEnumData <$> readFile path+ evalAndWriteFile path = do+ result <- doEnumEval+ writeFileIfDifferent path $ serializeEnumData result+ return result+ doEnumEval = do+ internalEvaluateEnumsForInterface iface maybeCppDir+ (appKeepTempOutputsOnFailure state)++serializeEnumData :: Map ExtName EvaluatedEnumData -> String+serializeEnumData = show . M.mapKeys fromExtName++deserializeEnumData :: String -> Map ExtName EvaluatedEnumData+deserializeEnumData = M.mapKeys toExtName . read+ -- | This provides a simple @main@ function for a generator. Define your @main@ -- as: --@@ -165,16 +271,22 @@ -- | This is a version of 'defaultMain' that accepts multiple interfaces. defaultMain' :: [Either String Interface] -> IO () defaultMain' interfaceResults = do- interfaces <- forM interfaceResults $ \case- Left errorMsg -> do- hPutStrLn stderr $ "Error initializing interface: " ++ errorMsg- exitFailure- Right iface -> return iface-+ interfaces <- ensureInterfaces interfaceResults args <- getArgs _ <- run interfaces args return () +-- | Ensures that all of the entries in a list of results coming from+-- 'interface' are successful, and returns the list of 'Interface' values. If+-- any results are unsuccessful, then an error message is printed, and the+-- program exits with an error ('exitFailure').+ensureInterfaces :: [Either String Interface] -> IO [Interface]+ensureInterfaces interfaceResults = forM interfaceResults $ \case+ Left errorMsg -> do+ hPutStrLn stderr $ "Error initializing interface: " ++ errorMsg+ exitFailure+ Right iface -> return iface+ -- | @run interfaces args@ runs the driver with the command-line arguments from -- @args@ against the listed interfaces, and returns the list of actions -- performed.@@ -182,6 +294,9 @@ -- The recognized arguments are listed below. The exact forms shown are -- required; the @--long-arg=value@ style is not supported. --+-- Arguments are processed in the order given, this means that settings must+-- come before action arguments.+-- -- - __@--help@:__ Displays a menu listing the valid commands. -- -- - __@--list-interfaces@:__ Lists the interfaces compiled into the generator.@@ -193,6 +308,18 @@ -- -- - __@--gen-hs \<outdir\>@:__ Generates Haskell bindings under the given -- top-level source directory.+--+-- - __@--enum-eval-cache-path \<cachefile\>@:__ Specifies a cache file to use+-- for the results of enum evaluation. If the cache file already exists, then+-- it may be loaded to save calling the compiler, depending on the cache mode+-- (@--enum-eval-cache-mode@). Because enum evaluation results are required+-- when generating both the C++ and Haskell interfaces and these are normally+-- separate packages, this allows the C++ package's evaluation work to be+-- shared with the Haskell package.+--+-- - __@--enum-eval-cache-mode \<refresh|must-exist\>@:__+-- Controls the specific behaviour of the generator with respect to the enum+-- evaluation cache file. See 'EnumEvalCacheMode'. run :: [Interface] -> [String] -> IO [Action] run interfaces args = do stateVar <- newMVar $ initialAppState interfaces@@ -210,24 +337,36 @@ mapM_ putStrLn [ "Hoppy binding generator" , ""+ , "Arguments: [ option... ] [ action... ]"+ , " Arguments are processed in the order seen, so put options before the"+ , " arguments they apply to. Normally, pass --gen-* last."+ , "" , "Interfaces: " ++ intercalate ", " interfaceNames , ""- , "Supported options:"+ , "Supported actions:" , " --help Displays this menu."- , " --interface <iface> Sets the interface used for subsequent options." , " --list-interfaces Lists the interfaces compiled into this binary." , " --list-cpp-files Lists generated file paths in C++ bindings." , " --list-hs-files Lists generated file paths in Haskell bindings." , " --gen-cpp <outdir> Generate C++ bindings in a directory." , " --gen-hs <outdir> Generate Haskell bindings under the given" , " top-level source directory."- , " --keep-temp-outputs-on-failure"- , " Keeps on disk any temporary programs that fail"- , " to build. Pass this before --gen-* commands."+ , " --clean-cpp <outdir> Removes generated file paths in C++ bindings."+ , " --clean-hs <outdir> Removes generated file paths in Haskell bindings." , " --dump-ext-names Lists the current interface's external names." , " --dump-enums Lists the current interface's enum data." , ""- , "Arguments are processed in the order seen."+ , "Supported options:"+ , " --interface <iface> Sets the interface used for subsequent options."+ , " --keep-temp-outputs-on-failure"+ , " Keeps on disk any temporary programs that fail"+ , " to build. Pass this before --gen-* commands."+ , " --enum-eval-cache-path <path>"+ , " --enum-eval-cache-mode <refresh|must-exist>"+ , " Controls the behaviour of the enum evaluation result caching."+ , " Caching is disabled if no path is given. With 'refresh', enums"+ , " are always evaluated freshly and the cache file is updated."+ , " With 'must-exist', the cache file must already exist." ] processArgs :: MVar AppState -> [String] -> IO [Action]@@ -251,7 +390,7 @@ (ListInterfaces:) <$> processArgs stateVar rest "--list-cpp-files":rest -> do- genResult <- withCurrentCache stateVar getGeneratedCpp+ genResult <- withCurrentCache stateVar $ getGeneratedCpp Nothing case genResult of Left errorMsg -> do hPutStrLn stderr $ "--list-cpp-files: Failed to generate: " ++ errorMsg@@ -277,7 +416,7 @@ "--gen-cpp: Please create this directory so that I can generate files in it: " ++ baseDir exitFailure- genResult <- withCurrentCache stateVar getGeneratedCpp+ genResult <- withCurrentCache stateVar $ getGeneratedCpp $ Just baseDir case genResult of Left errorMsg -> do hPutStrLn stderr $ "--gen-cpp: Failed to generate: " ++ errorMsg@@ -300,25 +439,55 @@ hPutStrLn stderr $ "--gen-hs: Failed to generate: " ++ errorMsg exitFailure Right gen -> do- forM_ (M.toList $ Haskell.generatedFiles gen) $- uncurry $ writeGeneratedFile baseDir+ forM_ (M.toList $ Haskell.generatedFiles gen) $ \(subpath, contents) ->+ writeGeneratedFile baseDir subpath contents (GenHaskell baseDir:) <$> processArgs stateVar rest + "--clean-cpp":baseDir:rest -> do+ baseDirExists <- doesDirectoryExist baseDir+ when baseDirExists $ do+ genResult <- withCurrentCache stateVar $ getGeneratedCpp $ Just baseDir+ case genResult of+ Left errorMsg -> do+ hPutStrLn stderr $ "--clean-cpp: Failed to evaluate interface: " ++ errorMsg+ exitFailure+ Right gen -> do+ -- TODO Remove empty directories.+ forM_ (M.keys $ Cpp.generatedFiles gen) $ \path ->+ removeFile $ baseDir </> path+ (CleanCpp baseDir:) <$> processArgs stateVar rest++ "--clean-hs":baseDir:rest -> do+ baseDirExists <- doesDirectoryExist baseDir+ when baseDirExists $ do+ genResult <- withCurrentCache stateVar $ getGeneratedHaskell+ case genResult of+ Left errorMsg -> do+ hPutStrLn stderr $ "--clean-hs: Failed to evaluate interface: " ++ errorMsg+ exitFailure+ Right gen -> do+ -- TODO Remove empty directories.+ forM_ (M.keys $ Haskell.generatedFiles gen) $ \path ->+ removeFile $ baseDir </> path+ (CleanHs baseDir:) <$> processArgs stateVar rest+ "--dump-ext-names":rest -> do withCurrentCache stateVar $ \_ iface cache -> do forM_ (interfaceModules iface) $ \m -> forM_ (moduleExports m) $ \export -> forM_ (getAllExtNames export) $ \extName -> putStrLn $ "extname module=" ++ moduleName m ++ " name=" ++ fromExtName extName- return (iface, cache, ())+ return (cache, ()) (DumpExtNames:) <$> processArgs stateVar rest "--dump-enums":rest -> do withCurrentCache stateVar $ \state iface cache -> do- iface' <- evaluateEnums state iface- allEvaluatedData <- flip fromMaybeM (interfaceEvaluatedEnumData iface') $ do+ -- TODO 'Nothing' is less than ideal here.+ cache' <- generateComputedData Nothing state iface cache+ computed <- flip fromMaybeM (cacheComputedData cache') $ do hPutStrLn stderr $ "--dump-enums expected to have evaluated enum data, but doesn't." exitFailure+ let allEvaluatedData = evaluatedEnumMap computed forM_ (M.toList allEvaluatedData) $ \(extName, evaluatedData) -> do m <- flip fromMaybeM (M.lookup extName $ interfaceNamesToModules iface) $ do hPutStrLn stderr $@@ -326,20 +495,36 @@ exitFailure let typeStr = Cpp.chunkContents $ Cpp.execChunkWriter $- Cpp.sayType Nothing $ evaluatedEnumType evaluatedData+ Cpp.sayType Nothing $ numType $ evaluatedEnumNumericType evaluatedData putStrLn $ "enum name=" ++ fromExtName extName ++ " module=" ++ moduleName m ++ " type=" ++ typeStr forM_ (M.toList $ evaluatedEnumValueMap evaluatedData) $ \(words', number) -> putStrLn $ "entry value=" ++ show number ++ " name=" ++ show words'- return (iface', cache, ())+ return (cache', ()) (DumpEnums:) <$> processArgs stateVar rest "--keep-temp-outputs-on-failure":rest -> do- modifyMVar_ stateVar $ \state -> return $ state { appKeepTempOutputsOnFailure = True }+ modifyMVar_ stateVar $ \state -> return state { appKeepTempOutputsOnFailure = True } (KeepTempOutputsOnFailure:) <$> processArgs stateVar rest + "--enum-eval-cache-path":path:rest -> do+ let path' = if path == "" then Nothing else Just path+ modifyMVar_ stateVar $ \state -> return state { appEnumEvalCachePath = path' }+ (EnumEvalCachePath path':) <$> processArgs stateVar rest++ "--enum-eval-cache-mode":arg:rest -> do+ mode <- case arg of+ "must-exist" -> return EnumCacheMustExist+ "refresh" -> return RefreshEnumCache+ _ -> do+ hPutStrLn stderr $+ "--enum-eval-cache-mode received unexpected argument, got: '" ++ arg ++ "'"+ exitFailure+ modifyMVar_ stateVar $ \state -> return state { appEnumEvalCacheMode = mode }+ (EnumEvalCacheMode mode:) <$> processArgs stateVar rest+ arg:_ -> do- hPutStrLn stderr $ "Invalid option or missing argument for '" ++ arg ++ "'."+ hPutStrLn stderr $ "Invalid option, or missing argument for '" ++ arg ++ "'." exitFailure writeGeneratedFile :: FilePath -> FilePath -> String -> IO ()@@ -350,16 +535,14 @@ withCurrentCache :: MVar AppState- -> (AppState -> Interface -> InterfaceCache -> IO (Interface, InterfaceCache, a))+ -> (AppState -> Interface -> InterfaceCache -> IO (InterfaceCache, a)) -> IO a withCurrentCache stateVar fn = modifyMVar stateVar $ \state -> do let iface = appCurrentInterface state name = interfaceName iface let cache = fromMaybe emptyCache $ M.lookup name $ appCaches state- (iface', cache', result) <- fn state iface cache- return ( state { appInterfaces = M.insert name iface' $ appInterfaces state- , appCaches = M.insert name cache' $ appCaches state- }+ (cache', result) <- fn state iface cache+ return ( state { appCaches = M.insert name cache' $ appCaches state } , result )
src/Foreign/Hoppy/Generator/Override.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -23,19 +23,21 @@ -- \" ++ show cls@. module Foreign.Hoppy.Generator.Spec ( module Foreign.Hoppy.Generator.Spec.Base,- module Foreign.Hoppy.Generator.Spec.Conversion,- module Foreign.Hoppy.Generator.Spec.Variable,- module Foreign.Hoppy.Generator.Spec.Enum,- module Foreign.Hoppy.Generator.Spec.Function, module Foreign.Hoppy.Generator.Spec.Callback, module Foreign.Hoppy.Generator.Spec.Class, module Foreign.Hoppy.Generator.Spec.ClassFeature,+ module Foreign.Hoppy.Generator.Spec.Computed,+ module Foreign.Hoppy.Generator.Spec.Conversion,+ module Foreign.Hoppy.Generator.Spec.Enum,+ module Foreign.Hoppy.Generator.Spec.Function,+ module Foreign.Hoppy.Generator.Spec.Variable, ) where import Foreign.Hoppy.Generator.Spec.Base import Foreign.Hoppy.Generator.Spec.Callback import Foreign.Hoppy.Generator.Spec.Class import Foreign.Hoppy.Generator.Spec.ClassFeature+import Foreign.Hoppy.Generator.Spec.Computed import Foreign.Hoppy.Generator.Spec.Conversion import Foreign.Hoppy.Generator.Spec.Enum import Foreign.Hoppy.Generator.Spec.Function
src/Foreign/Hoppy/Generator/Spec/Base.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -167,12 +167,8 @@ hsWholeModuleImport, hsQualifiedImport, hsImport1, hsImport1', hsImports, hsImports', hsImportSetMakeSource, -- * Internal to Hoppy- EvaluatedEnumData (..),- EvaluatedEnumValueMap, interfaceAllExceptionClasses, interfaceSharedPtr,- interfaceEvaluatedEnumData,- interfaceGetEvaluatedEnumData, -- ** Haskell imports makeHsImportSet, getHsImportSet,@@ -265,13 +261,19 @@ -- it. This defaults to using @std::shared_ptr@ from @\<memory\>@, but can -- be changed if necessary via 'interfaceSetSharedPtr'. , interfaceCompiler :: Maybe SomeCompiler- -- ^ The compiler to use when building code for the interface. This can be- -- overridden or disabled. This defaults to 'defaultCompiler'.+ -- ^ The C++ compiler for the generator itself to use when building+ -- temporary code for the interface. This can be overridden or disabled.+ -- This defaults to 'defaultCompiler'.+ --+ -- __This is separate__ from the @./configure && make@ compilation process+ -- used by @Foreign.Hoppy.Runtime.Setup.cppMain@ to build generated C+++ -- bindings (see hoppy-runtime). This compiler is used to evaluate enums'+ -- numeric values when the generator is called, and is not used otherwise.+ -- See 'Foreign.Hoppy.Generator.Spec.Enum.makeAutoEnum' and+ -- "Foreign.Hoppy.Generator.Hooks". , interfaceHooks :: Hooks -- ^ Hooks allowing the interface to execute code at various points during -- the code generator's execution. This defaults to 'defaultHooks'.- , interfaceEvaluatedEnumData :: Maybe (M.Map ExtName EvaluatedEnumData)- -- ^ Evaluated numeric types and values for all enums in the interface. , interfaceValidateEnumTypes :: Bool -- ^ Whether to validate manually-provided enum numeric types -- ('Foreign.Hoppy.Generator.Spec.Enum.enumNumericType') using a compiled@@ -365,7 +367,6 @@ , interfaceSharedPtr = (reqInclude $ includeStd "memory", "std::shared_ptr") , interfaceCompiler = Just $ SomeCompiler defaultCompiler , interfaceHooks = defaultHooks- , interfaceEvaluatedEnumData = Nothing , interfaceValidateEnumTypes = True } @@ -494,18 +495,6 @@ interfaceModifyHooks f iface = iface { interfaceHooks = f $ interfaceHooks iface } --- | Returns the map containing the calculated values for all entries in the--- enum with the given 'ExtName'. This requires hooks to have been run.-interfaceGetEvaluatedEnumData :: HasCallStack => Interface -> ExtName -> EvaluatedEnumData-interfaceGetEvaluatedEnumData iface extName =- case interfaceEvaluatedEnumData iface of- Nothing -> error $ "interfaceGetEvaluatedEnumData: Data have not been " ++- "evaluated for " ++ show iface ++ "."- Just enumMap -> case M.lookup extName enumMap of- Nothing -> error $ "interfaceGetEvaluatedEnumData: No data found for " ++- show extName ++ " in " ++ show iface ++ "."- Just info -> info- -- | An @#include@ directive in a C++ file. newtype Include = Include { includeToString :: String@@ -514,10 +503,14 @@ } deriving (Eq, Ord, Show) -- | Creates an @#include \<...\>@ directive.+--+-- This can be added to most types of C++ entities with 'addReqIncludes'. includeStd :: String -> Include includeStd path = Include $ "#include <" ++ path ++ ">\n" -- | Creates an @#include "..."@ directive.+--+-- This can be added to most types of C++ entities with 'addReqIncludes'. includeLocal :: String -> Include includeLocal path = Include $ "#include \"" ++ path ++ "\"\n" @@ -1520,19 +1513,6 @@ , conversionSpecHaskellToCppFn = toCppFn , conversionSpecHaskellFromCppFn = fromCppFn }---- | Information about the enum that has been completed beyond what the--- interface definition provides, possibly by building actual C++ code.-data EvaluatedEnumData = EvaluatedEnumData- { evaluatedEnumType :: Type- -- ^ The numeric type that C++ uses to hold the enum's values, or an- -- equivalently-sized type.- , evaluatedEnumValueMap :: EvaluatedEnumValueMap- -- ^ Calculated values for all of the enum's entries.- }---- | Contains the numeric values for each of the entries in a C++ enum.-type EvaluatedEnumValueMap = M.Map [String] Integer -- | Each exception class has a unique exception ID. newtype ExceptionId = ExceptionId
src/Foreign/Hoppy/Generator/Spec/Base.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Callback.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Callback.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Class.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Class.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/ClassFeature.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
+ src/Foreign/Hoppy/Generator/Spec/Computed.hs view
@@ -0,0 +1,131 @@+-- This file is part of Hoppy.+--+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net>+--+-- This program is free software: you can redistribute it and/or modify+-- it under the terms of the GNU Affero General Public License as published by+-- the Free Software Foundation, either version 3 of the License, or+-- (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU Affero General Public License for more details.+--+-- You should have received a copy of the GNU Affero General Public License+-- along with this program. If not, see <http://www.gnu.org/licenses/>.++-- | Module for computed data for an interface.+module Foreign.Hoppy.Generator.Spec.Computed (+ ComputedInterfaceData (..),+ EvaluatedEnumData (..),+ EvaluatedEnumValueMap,+ getEvaluatedEnumData,+ -- * Numeric types+ NumericTypeInfo,+ numType, numBytes, numMinBound, numMaxBound,+ findNumericTypeInfo,+ pickNumericType,+ ) where++import qualified Data.Map as M+import Data.Map (Map)+import Data.Maybe (listToMaybe)+import Foreign.C (CInt, CLong, CLLong, CUInt, CULong, CULLong)+import Foreign.Hoppy.Generator.Spec.Base (ExtName, Type)+import Foreign.Hoppy.Generator.Types (intT, llongT, longT, uintT, ullongT, ulongT)+import Foreign.Storable (Storable, sizeOf)+import GHC.Stack (HasCallStack)++-- | Holds "computed data" for an interface. This is data that is calculated by+-- Hoppy, beyond what is directly specified in the interface.+data ComputedInterfaceData = ComputedInterfaceData+ { computedInterfaceName :: String+ -- ^ The name of the interface.+ , evaluatedEnumMap :: Map ExtName EvaluatedEnumData+ -- ^ Evaluated numeric types and values for all enums in the interface.+ }++-- | Information about the enum that has been completed beyond what the+-- interface definition provides, possibly by building actual C++ code.+data EvaluatedEnumData = EvaluatedEnumData+ { evaluatedEnumNumericType :: NumericTypeInfo+ -- ^ The numeric type that C++ uses to hold the enum's values, or an+ -- equivalently-sized type.+ , evaluatedEnumValueMap :: EvaluatedEnumValueMap+ -- ^ Calculated values for all of the enum's entries.+ } deriving (Read, Show)++-- | Contains the numeric values for each of the entries in a C++ enum.+type EvaluatedEnumValueMap = Map [String] Integer++-- | Returns the map containing the calculated values for all entries in the+-- enum with the given 'ExtName'. This requires hooks to have been run.+getEvaluatedEnumData ::+ HasCallStack+ => ComputedInterfaceData+ -> ExtName+ -> EvaluatedEnumData+getEvaluatedEnumData computed extName = case M.lookup extName (evaluatedEnumMap computed) of+ Nothing -> error $ "interfaceGetEvaluatedEnumData: No data found for " +++ show extName ++ " in interface '" ++ computedInterfaceName computed ++ "'."+ Just info -> info++-- | Bound information about numeric types.+data NumericTypeInfo = NumericTypeInfo+ { numType :: Type+ -- ^ The numeric data type described by the record.+ , numBytes :: Int+ -- ^ The number of bytes in a value of the type.+ , numMinBound :: Integer+ -- ^ The lowest (most negative) value representable by the type.+ , numMaxBound :: Integer+ -- ^ The highest (most positive) value representable by the type.+ }++instance Show NumericTypeInfo where+ show info = show (numBytes info, numMinBound info, numMaxBound info)++instance Read NumericTypeInfo where+ readsPrec p s =+ case readsPrec p s of+ [((bytes, minBound, maxBound), rest)] ->+ case pickNumericType bytes minBound maxBound of+ Just info -> [(info, rest)]+ Nothing -> []+ [] -> []+ other ->+ error $ "Read NumericTypeInfo: Unexpected readsPrec result: " ++ show other++-- | Numeric types usable to hold enum values. These are ordered by decreasing+-- precedence (increasing word size).+numericTypeInfo :: [NumericTypeInfo]+numericTypeInfo =+ [ mk intT (undefined :: CInt)+ , mk uintT (undefined :: CUInt)+ , mk longT (undefined :: CLong)+ , mk ulongT (undefined :: CULong)+ , mk llongT (undefined :: CLLong)+ , mk ullongT (undefined :: CULLong)+ ]+ where mk :: forall a. (Bounded a, Integral a, Storable a) => Type -> a -> NumericTypeInfo+ mk t _ = NumericTypeInfo+ { numType = t+ , numBytes = sizeOf (undefined :: a)+ , numMinBound = toInteger (minBound :: a)+ , numMaxBound = toInteger (maxBound :: a)+ }++-- | Searches the list of known numeric types usable for enum values, and+-- returns the record for the given type.+findNumericTypeInfo :: Type -> Maybe NumericTypeInfo+findNumericTypeInfo t = listToMaybe $ filter (\i -> numType i == t) numericTypeInfo++-- | Selects the preferred numeric type for holding numeric values in the given+-- range.+pickNumericType :: Int -> Integer -> Integer -> Maybe NumericTypeInfo+pickNumericType bytes low high =+ listToMaybe $ flip filter numericTypeInfo $ \info ->+ numBytes info == bytes &&+ numMinBound info <= low &&+ numMaxBound info >= high
src/Foreign/Hoppy/Generator/Spec/Conversion.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Enum.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -64,6 +64,13 @@ import qualified Data.Map as M import Foreign.Hoppy.Generator.Common (butLast, capitalize, for) import Foreign.Hoppy.Generator.Spec.Base+import Foreign.Hoppy.Generator.Spec.Computed (+ EvaluatedEnumData,+ evaluatedEnumNumericType,+ evaluatedEnumValueMap,+ getEvaluatedEnumData,+ numType,+ ) import qualified Foreign.Hoppy.Generator.Language.Cpp as LC import qualified Foreign.Hoppy.Generator.Language.Haskell as LH import Foreign.Hoppy.Generator.Override (addOverrideMap, overriddenMapLookup, plainMap)@@ -218,7 +225,23 @@ -- | Creates a binding for a C++ enum. -- -- An enum created using this function will determine its entries' numeric--- values automatically when the generator is run, by compiling a C++ program.+-- values automatically when the generator is run, by compiling a temporary,+-- autogenerated C++ helper program.+--+-- This helper program needs to be able to access the C++ declaration of the+-- enum. In addition to any 'includeStd' or 'includeLocal' requirements added+-- to the enum for the generated C++ bindings to use, the /interface's compiler/+-- ('interfaceCompiler') will need to be able to use these includes to access+-- the enum from C++ file built in a temporary directory. To add @-I@ arguments+-- or otherwise change the compiler, you can reconfigure the interface:+--+-- @+-- myInterface =+-- 'interfaceSetCompiler' (prependArguments [\"-I\" ++ pathToIncludes] defaultCompiler) $+-- 'interface' ...+-- @+--+-- See "Foreign.Hoppy.Generator.Compiler". makeAutoEnum :: IsAutoEnumValue v => Identifier -- ^ 'enumIdentifier'@@ -264,7 +287,7 @@ -- The @('EnumEntryWords', String)@ instance is the canonical one, with -- 'toAutoEnumValue' defined as @id@. The string on the right is the C++ name -- of the entry, and the list of strings on the left are the words from which to--- generate foreign binding's entries.+-- generate foreign bindings' entry names. -- -- The @String@ instance takes the C++ name of the entry, and splits it into -- words via 'splitIntoWords'.@@ -350,7 +373,8 @@ makeConversionSpecHaskell (HsTyCon . UnQual . HsIdent <$> toHsEnumTypeName e) (Just $ do evaluatedData <- hsGetEvaluatedEnumData $ enumExtName e- LH.cppTypeToHsTypeAndUse LH.HsCSide $ evaluatedEnumType evaluatedData)+ LH.cppTypeToHsTypeAndUse LH.HsCSide $+ numType $ evaluatedEnumNumericType evaluatedData) (CustomConversion $ do LH.addImports $ mconcat [hsImport1 "Prelude" "(.)", hsImportForPrelude,@@ -377,7 +401,8 @@ LH.SayExportDecls -> do hsTypeName <- toHsEnumTypeName enum evaluatedData <- hsGetEvaluatedEnumData $ enumExtName enum- numericType <- LH.cppTypeToHsTypeAndUse LH.HsCSide $ evaluatedEnumType evaluatedData+ numericType <- LH.cppTypeToHsTypeAndUse LH.HsCSide $+ numType $ evaluatedEnumNumericType evaluatedData let evaluatedValueMap = evaluatedEnumValueMap evaluatedData evaluatedValues <- forM (enumValueMapNames $ enumValues enum) $ \name -> case M.lookup name evaluatedValueMap of@@ -475,7 +500,8 @@ LH.SayExportBoot -> do hsTypeName <- toHsEnumTypeName enum evaluatedData <- hsGetEvaluatedEnumData $ enumExtName enum- numericType <- LH.cppTypeToHsTypeAndUse LH.HsCSide $ evaluatedEnumType evaluatedData+ numericType <- LH.cppTypeToHsTypeAndUse LH.HsCSide $+ numType $ evaluatedEnumNumericType evaluatedData LH.addImports $ mconcat [hsImportForPrelude, hsImportForRuntime] LH.addExport hsTypeName LH.ln@@ -491,15 +517,15 @@ -- | Reads evaluated data for the named enum from the C++ generator environment. cppGetEvaluatedEnumData :: HasCallStack => ExtName -> LC.Generator EvaluatedEnumData cppGetEvaluatedEnumData extName = do- iface <- LC.askInterface- return $ interfaceGetEvaluatedEnumData iface extName+ computed <- LC.askComputedInterfaceData+ return $ getEvaluatedEnumData computed extName -- | Reads evaluated data for the named enum from the Haskell generator -- environment. hsGetEvaluatedEnumData :: HasCallStack => ExtName -> LH.Generator EvaluatedEnumData hsGetEvaluatedEnumData extName = do- iface <- LH.askInterface- return $ interfaceGetEvaluatedEnumData iface extName+ computed <- LH.askComputedInterfaceData+ return $ getEvaluatedEnumData computed extName -- | Returns the Haskell name for an enum. --
src/Foreign/Hoppy/Generator/Spec/Enum.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Function.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Function.hs-boot view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Spec/Variable.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Types.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Util.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
src/Foreign/Hoppy/Generator/Version.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2020 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by