inline-c-cpp 0.2.2.1 → 0.3.0.0
raw patch · 3 files changed
+60/−15 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Language.C.Inline.Cpp.Exceptions: CppOtherException :: CppException
+ Language.C.Inline.Cpp.Exceptions: CppOtherException :: (Maybe String) -> CppException
Files
- inline-c-cpp.cabal +1/−1
- src/Language/C/Inline/Cpp/Exceptions.hs +44/−6
- test/tests.hs +15/−8
inline-c-cpp.cabal view
@@ -1,5 +1,5 @@ name: inline-c-cpp-version: 0.2.2.1+version: 0.3.0.0 synopsis: Lets you embed C++ code into Haskell. description: Utilities to inline C++ code into Haskell using inline-c. See tests for example on how to build.
src/Language/C/Inline/Cpp/Exceptions.hs view
@@ -21,7 +21,7 @@ -- | An exception thrown in C++ code. data CppException = CppStdException String- | CppOtherException+ | CppOtherException (Maybe String) -- contains the exception type, if available. deriving (Eq, Ord, Show) instance Exception CppException@@ -55,8 +55,15 @@ errMsg <- peekCString msgPtr free msgPtr return (Left (CppStdException errMsg))- ExTypeOtherException ->- return (Left CppOtherException)+ ExTypeOtherException -> do+ msgPtr <- peek msgPtrPtr+ mbExcType <- if msgPtr == nullPtr+ then return Nothing+ else do+ excType <- peekCString msgPtr+ free msgPtr+ return (Just excType)+ return (Left (CppOtherException mbExcType)) _ -> error "Unexpected C++ exception type." -- | Like 'tryBlock', but will throw 'CppException's rather than returning@@ -88,8 +95,23 @@ _ <- C.include "<exception>" _ <- C.include "<cstring>" _ <- C.include "<cstdlib>"+ -- see+ -- <https://stackoverflow.com/questions/28166565/detect-gcc-as-opposed-to-msvc-clang-with-macro>+ -- regarding how to detect g++ or clang.+ --+ -- the defined(__clang__) should actually be redundant, since apparently it also+ -- defines GNUC, but but let's be safe.+ C.verbatim $ unlines+ [ "#if defined(__GNUC__) || defined(__clang__)"+ , "#include <cxxabi.h>"+ , "#include <string>"+ , "#endif"+ ] typePtrVarName <- newName "exTypePtr" msgPtrVarName <- newName "msgPtr"+ -- see+ -- <https://stackoverflow.com/questions/561997/determining-exception-type-after-the-exception-is-caught/47164539#47164539>+ -- regarding how to show the type of an exception. let inlineCStr = unlines [ ty ++ " {" , " int* __inline_c_cpp_exception_type__ = $(int* " ++ nameBase typePtrVarName ++ ");"@@ -98,12 +120,28 @@ , body , " } catch (std::exception &e) {" , " *__inline_c_cpp_exception_type__ = " ++ show ExTypeStdException ++ ";"- , " size_t whatLen = std::strlen(e.what()) + 1;"- , " *__inline_c_cpp_error_message__ = static_cast<char*>(std::malloc(whatLen));"- , " std::memcpy(*__inline_c_cpp_error_message__, e.what(), whatLen);"+ , "#if defined(__GNUC__) || defined(__clang__)"+ , " int demangle_status;"+ , " const char* demangle_result = abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &demangle_status);"+ , " std::string message = \"Exception: \" + std::string(e.what()) + \"; type: \" + std::string(demangle_result);"+ , "#else"+ , " std::string message = \"Exception: \" + std::string(e.what()) + \"; type: not available (please use g++ or clang)\";"+ , "#endif"+ , " size_t message_len = message.size() + 1;"+ , " *__inline_c_cpp_error_message__ = static_cast<char*>(std::malloc(message_len));"+ , " std::memcpy(*__inline_c_cpp_error_message__, message.c_str(), message_len);" , if ty == "void" then "return;" else "return {};" , " } catch (...) {" , " *__inline_c_cpp_exception_type__ = " ++ show ExTypeOtherException ++ ";"+ , "#if defined(__GNUC__) || defined(__clang__)"+ , " int demangle_status;"+ , " const char* message = abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &demangle_status);"+ , " size_t message_len = strlen(message) + 1;"+ , " *__inline_c_cpp_error_message__ = static_cast<char*>(std::malloc(message_len));"+ , " std::memcpy(*__inline_c_cpp_error_message__, message, message_len);"+ , "#else"+ , " *__inline_c_cpp_error_message__ = NULL;"+ , "#endif" , if ty == "void" then "return;" else "return {};" , " }" , "}"
test/tests.hs view
@@ -28,22 +28,29 @@ throw std::runtime_error("C++ error message"); |] - result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")+ result `Hspec.shouldBe` Left (C.CppStdException "Exception: C++ error message; type: std::runtime_error") - Hspec.it "non-exceptions are caught" $ do+ Hspec.it "non-exceptions are caught (unsigned int)" $ do result <- try [C.catchBlock| throw 0xDEADBEEF; |] - result `Hspec.shouldBe` Left C.CppOtherException+ result `Hspec.shouldBe` Left (C.CppOtherException (Just "unsigned int")) + Hspec.it "non-exceptions are caught (std::string)" $ do+ result <- try [C.catchBlock|+ throw std::string("FOOBAR");+ |]++ result `Hspec.shouldBe` Left (C.CppOtherException (Just "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >"))+ Hspec.it "catch without return (pure)" $ do result <- [C.tryBlock| void { throw std::runtime_error("C++ error message"); } |] - result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")+ result `Hspec.shouldBe` Left (C.CppStdException "Exception: C++ error message; type: std::runtime_error") Hspec.it "try and return without throwing (pure)" $ do result <- [C.tryBlock| int {@@ -69,7 +76,7 @@ } |] - result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")+ result `Hspec.shouldBe` Left (C.CppStdException "Exception: C++ error message; type: std::runtime_error") Hspec.it "catch without return (pure)" $ do result <- [C.tryBlock| void {@@ -77,7 +84,7 @@ } |] - result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")+ result `Hspec.shouldBe` Left (C.CppStdException "Exception: C++ error message; type: std::runtime_error") Hspec.it "try and return without throwing (throw)" $ do result :: Either C.CppException C.CInt <- try [C.throwBlock| int {@@ -103,7 +110,7 @@ } |] - result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")+ result `Hspec.shouldBe` Left (C.CppStdException "Exception: C++ error message; type: std::runtime_error") Hspec.it "catch without return (throw)" $ do result <- try [C.throwBlock| void {@@ -111,7 +118,7 @@ } |] - result `Hspec.shouldBe` Left (C.CppStdException "C++ error message")+ result `Hspec.shouldBe` Left (C.CppStdException "Exception: C++ error message; type: std::runtime_error") Hspec.it "code without exceptions works normally" $ do result :: Either C.CppException C.CInt <- try $ C.withPtr_ $ \resPtr -> [C.catchBlock|