packages feed

hslua 0.8.0 → 0.9.0

raw patch · 9 files changed

+307/−15 lines, 9 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Foreign.Lua.Api: throwTopMessageAsError :: Lua a
+ Foreign.Lua.Api: throwTopMessageAsError' :: (String -> String) -> Lua a
+ Foreign.Lua.Types.FromLuaStack: instance Foreign.Lua.Types.FromLuaStack.FromLuaStack Data.ByteString.Lazy.Internal.ByteString
+ Foreign.Lua.Types.ToLuaStack: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack Data.ByteString.Lazy.Internal.ByteString

Files

CHANGELOG.md view
@@ -1,4 +1,19 @@ ## Changelog+### 0.9.0++- Added cabal flag to allow fully safe garbage collection: Lua garbage+  collection can occur in most of the API functions, even in those usually not+  calling back into haskell and hence marked as optimizable. The effect of this+  is that finalizers which call Haskell functions will cause the program to+  hang. A new flag `allow-unsafe-gc` is introduced and enabled by default.+  Disabling this flag will mark more C API functions as potentially calling back+  into Haskell. This has a serious performance impact.+- `FromLuaStack` and `ToLuaStack` instances for lazy ByteStrings are added.+- None-string error messages are handled properly: Lua allows error messages to+  be of any type, but the haskell error handlers expected string values. Tables,+  booleans, and other non-string values are now handled as well and converted to+  strings.+ ### 0.8.0  - Use newtype definitions instead of type aliases for LuaNumber and LuaInteger.
README.md view
@@ -14,16 +14,47 @@ [Hackage]: http://img.shields.io/hackage/v/hslua.svg  -Using a different lua version------------------------------+Build flags+----------- -To use system-wide installed Lua/LuaJIT when linking hslua as a dependency,+The following cabal build flags are supported:++- `system-lua`: Use the locally installed Lua version instead of the version+  shipped as part of HsLua.++- `use-pkgconfig`: Use `pkg-config` to discover library and include paths. This+  is used only when the `system-lua` flag is set or implied.++- `lua501`: Build against Lua 5.1; this implies the flag `system-lua` as well.++- `lua502`: Build against Lua 5.2; this implies the flag `system-lua` as well.++- `luajit`: Build against LuaJIT; this implies the flag `system-lua` as well.++- `allow-unsafe-gc`: Allow optimizations which make Lua's garbage collection+  potentially unsafe; haskell finalizers must be handled with extreme care. This+  is *enabled* per default, as this is rarely a problem in practice.++- `apicheck`: Compile Lua with its API checks enabled.++- `lua_32bits`: Compile Lua for a 32-bits system (e.g., i386, PowerPC G4).+++### Example: using a different lua version++To use a system-wide installed Lua/LuaJIT when linking hslua as a dependency, build/install your package using `--constraint="hslua +system-lua"` or for-LuaJIT: `--constraint="hslua +system-lua +luajit"`. For example, you can install-Pandoc with hslua that uses system-wide LuaJIT like this:+LuaJIT: `--constraint="hslua +luajit"`. For example, you can install Pandoc with+hslua that uses system-wide LuaJIT like this:  ``` sh cabal install pandoc --constraint="hslua +system-lua +luajit"+```++or with stack:++``` sh+stack install pandoc --flag=hslua:luajit ```  
hslua.cabal view
@@ -1,5 +1,5 @@ name:                   hslua-version:                0.8.0+version:                0.9.0 stability:              beta cabal-version:          >= 1.8 license:                MIT@@ -47,6 +47,12 @@   description:          Compile Lua with -DLUA_32BITS   default:              False +flag allow-unsafe-gc+  description:          Allow optimizations which make Lua's garbage collection+                        potentially unsafe; haskell finalizers must be handled+                        with extreme care.+  default:              True+ flag luajit   description:          Link with LuaJIT.  This implies flag system-lua as well.   default:              False@@ -171,6 +177,9 @@    if flag(lua_32bits)     cc-options:         "-DLUA_32BITS"++  if flag(allow-unsafe-gc)+    cc-options:         "-DALLOW_UNSAFE_GC"    if flag(apicheck)     cc-options:         "-DLUA_USE_APICHECK"
src/Foreign/Lua/Api.hs view
@@ -166,6 +166,9 @@   , newmetatable   , ref   , unref+  -- * Helper functions+  , throwTopMessageAsError+  , throwTopMessageAsError'   ) where  import Prelude hiding (EQ, LT, compare, concat)@@ -198,9 +201,41 @@   else return x  throwTopMessageAsError :: Lua a-throwTopMessageAsError = do-  msg <- tostring (-1) <* pop 1-  throwLuaError (BC.unpack msg)+throwTopMessageAsError = throwTopMessageAsError' id++throwTopMessageAsError' :: (String -> String) -> Lua a+throwTopMessageAsError' msgMod = do+  ty <- ltype (-1)+  msg <- case ty of+           TypeNil -> return "nil"+           TypeBoolean -> show <$> toboolean (-1)+           TypeLightUserdata -> showPointer+           TypeNumber -> BC.unpack <$> tostring (-1)+           TypeString -> BC.unpack <$> tostring (-1)+           TypeTable  -> tryTostringMetaMethod+           TypeFunction -> showPointer+           TypeThread -> showPointer+           TypeUserdata -> showPointer+           TypeNone -> error "Error while receiving the error message!"+  pop 1+  throwLuaError (msgMod msg)+ where+  showPointer = show <$> topointer (-1)+  tryTostringMetaMethod = do+    hasMT <- getmetatable (-1)+    if not hasMT+      then showPointer+      else do+        -- push getmetatable(t).__tostring+        pushstring (BC.pack "__tostring") *> rawget (-2)+        remove (-2)              -- remove metatable from stack+        isFn <- isfunction (-1)+        if isFn+          then do+            insert (-2)+            call 1 1+            BC.unpack <$> tostring (-1)+          else pop 1 *> showPointer  -- -- API functions
src/Foreign/Lua/Api/RawBindings.hsc view
@@ -72,37 +72,69 @@   lua_gettop :: LuaState -> IO StackIndex  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_settop lua_settop>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_settop"+#else+foreign import ccall safe "lua.h lua_settop"+#endif   lua_settop :: LuaState -> StackIndex -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushvalue lua_pushvalue>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushvalue"+#else+foreign import ccall safe "lua.h lua_pushvalue"+#endif   lua_pushvalue :: LuaState -> StackIndex -> IO ()  #if LUA_VERSION_NUMBER >= 503 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rotate lua_rotate>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rotate"+#else+foreign import ccall "lua.h lua_rotate"+#endif   lua_rotate :: LuaState -> StackIndex -> CInt -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_copy lua_copy>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_copy"+#else+foreign import ccall "lua.h lua_copy"+#endif   lua_copy :: LuaState -> StackIndex -> StackIndex -> IO () #else -- | See <https://www.lua.org/manual/5.2/manual.html#lua_remove lua_remove>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_remove"+#else+foreign import ccall safe "lua.h lua_remove"+#endif   lua_remove :: LuaState -> StackIndex -> IO ()  -- | See <https://www.lua.org/manual/5.2/manual.html#lua_insert lua_insert>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_insert"+#else+foreign import ccall safe "lua.h lua_insert"+#endif   lua_insert :: LuaState -> StackIndex -> IO ()  -- | See <https://www.lua.org/manual/5.2/manual.html#lua_replace lua_replace>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_replace"+#else+foreign import ccall safe "lua.h lua_replace"+#endif   lua_replace :: LuaState -> StackIndex -> IO () #endif  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_checkstack lua_checkstack>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_checkstack"+#else+foreign import ccall safe "lua.h lua_checkstack"+#endif   lua_checkstack :: LuaState -> StackIndex -> IO LuaBool  -- lua_xmove is currently not supported.@@ -112,27 +144,51 @@ -- * Stack access functions  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_isnumber lua_isnumber>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_isnumber"+#else+foreign import ccall safe "lua.h lua_isnumber"+#endif   lua_isnumber :: LuaState -> StackIndex -> IO LuaBool  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_isstring lua_isstring>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_isstring"+#else+foreign import ccall safe "lua.h lua_isstring"+#endif   lua_isstring :: LuaState -> StackIndex -> IO LuaBool  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_iscfunction lua_iscfunction>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_iscfunction"+#else+foreign import ccall safe "lua.h lua_iscfunction"+#endif   lua_iscfunction :: LuaState -> StackIndex -> IO LuaBool  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_isuserdata lua_isuserdata>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_isuserdata"+#else+foreign import ccall safe "lua.h lua_isuserdata"+#endif   lua_isuserdata :: LuaState -> StackIndex -> IO LuaBool  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_type lua_type>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_type"+#else+foreign import ccall safe "lua.h lua_type"+#endif   lua_type :: LuaState -> StackIndex -> IO TypeCode  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_typename lua_typename>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_typename"+#else+foreign import ccall safe "lua.h lua_typename"+#endif   lua_typename :: LuaState -> TypeCode -> IO (Ptr CChar)  -- lua_compare is unsafe (might cause a longjmp), use hslua_compare instead.@@ -153,52 +209,96 @@ #endif  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawequal lua_rawequal>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rawequal"+#else+foreign import ccall safe "lua.h lua_rawequal"+#endif   lua_rawequal :: LuaState -> StackIndex -> StackIndex -> IO LuaBool  -- -- Type coercion -- -- | See <https://www.lua.org/manual/5.3/manual.html#lua_toboolean lua_toboolean>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_toboolean"+#else+foreign import ccall safe "lua.h lua_toboolean"+#endif   lua_toboolean :: LuaState -> StackIndex -> IO StackIndex  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tocfunction lua_tocfunction>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tocfunction"+#else+foreign import ccall safe "lua.h lua_tocfunction"+#endif   lua_tocfunction :: LuaState -> StackIndex -> IO CFunction  #if LUA_VERSION_NUMBER >= 502 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tointegerx lua_tointegerx>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tointegerx"+#else+foreign import ccall safe "lua.h lua_tointegerx"+#endif   lua_tointegerx :: LuaState -> StackIndex -> Ptr LuaBool -> IO LuaInteger  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tonumberx lua_tonumberx>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tonumberx"+#else+foreign import ccall safe "lua.h lua_tonumberx"+#endif   lua_tonumberx :: LuaState -> StackIndex -> Ptr LuaBool -> IO LuaNumber #else -- | See <https://www.lua.org/manual/5.1/manual.html#lua_tointeger lua_tointeger>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tointeger"+#else+foreign import ccall safe "lua.h lua_tointeger"+#endif   lua_tointeger :: LuaState -> StackIndex -> IO LuaInteger  -- | See <https://www.lua.org/manual/5.1/manual.html#lua_tonumber lua_tonumber>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tonumber"+#else+foreign import ccall safe "lua.h lua_tonumber"+#endif   lua_tonumber :: LuaState -> StackIndex -> IO LuaNumber #endif  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tolstring lua_tolstring>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tolstring"+#else+foreign import ccall safe "lua.h lua_tolstring"+#endif   lua_tolstring :: LuaState -> StackIndex -> Ptr CSize -> IO (Ptr CChar)  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_topointer lua_topointer>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_topointer"+#else+foreign import ccall safe "lua.h lua_topointer"+#endif   lua_topointer :: LuaState -> StackIndex -> IO (Ptr ())  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tothread lua_tothread>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_tothread"+#else+foreign import ccall safe "lua.h lua_tothread"+#endif   lua_tothread :: LuaState -> StackIndex -> IO LuaState  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_touserdata lua_touserdata>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_touserdata"+#else+foreign import ccall safe "lua.h lua_touserdata"+#endif   lua_touserdata :: LuaState -> StackIndex -> IO (Ptr a)  @@ -208,11 +308,19 @@  #if LUA_VERSION_NUMBER >= 502 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawlen lua_rawlen>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rawlen"+#else+foreign import ccall safe "lua.h lua_rawlen"+#endif   lua_rawlen :: LuaState -> StackIndex -> IO CSize #else -- | See <https://www.lua.org/manual/5.1/manual.html#lua_objlen lua_objlen>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_objlen"+#else+foreign import ccall safe "lua.h lua_objlen"+#endif   lua_objlen :: LuaState -> StackIndex -> IO CSize #endif @@ -221,38 +329,70 @@ -- * Push functions  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushnil lua_pushnil>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushnil"+#else+foreign import ccall safe "lua.h lua_pushnil"+#endif   lua_pushnil :: LuaState -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushnumber lua_pushnumber>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushnumber"+#else+foreign import ccall safe "lua.h lua_pushnumber"+#endif   lua_pushnumber :: LuaState -> LuaNumber -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushinteger lua_pushinteger>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushinteger"+#else+foreign import ccall safe "lua.h lua_pushinteger"+#endif   lua_pushinteger :: LuaState -> LuaInteger -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushlstring lua_pushlstring>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushlstring"+#else+foreign import ccall safe "lua.h lua_pushlstring"+#endif   lua_pushlstring :: LuaState -> Ptr CChar -> CSize -> IO ()  -- lua_pushstring is currently not supported. It's difficult to use in a haskell -- context.  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushcclosure lua_pushcclosure>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushcclosure"+#else+foreign import ccall safe "lua.h lua_pushcclosure"+#endif   lua_pushcclosure :: LuaState -> CFunction -> NumArgs -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushboolean lua_pushboolean>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushboolean"+#else+foreign import ccall safe "lua.h lua_pushboolean"+#endif   lua_pushboolean :: LuaState -> LuaBool -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushlightuserdata lua_pushlightuserdata>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushlightuserdata"+#else+foreign import ccall safe "lua.h lua_pushlightuserdata"+#endif   lua_pushlightuserdata :: LuaState -> Ptr a -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushthread lua_pushthread>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_pushthread"+#else+foreign import ccall safe "lua.h lua_pushthread"+#endif   lua_pushthread :: LuaState -> IO CInt  @@ -275,23 +415,43 @@   hslua_getfield :: LuaState -> StackIndex -> Ptr CChar -> IO CInt  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawget lua_rawget>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rawget"+#else+foreign import ccall safe "lua.h lua_rawget"+#endif   lua_rawget :: LuaState -> StackIndex -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawgeti lua_rawgeti>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rawgeti"+#else+foreign import ccall safe "lua.h lua_rawgeti"+#endif   lua_rawgeti :: LuaState -> StackIndex -> CInt -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_createtable lua_createtable>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_createtable"+#else+foreign import ccall safe "lua.h lua_createtable"+#endif   lua_createtable :: LuaState -> CInt -> CInt -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_newuserdata lua_newuserdata>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_newuserdata"+#else+foreign import ccall safe "lua.h lua_newuserdata"+#endif   lua_newuserdata :: LuaState -> CInt -> IO (Ptr ())  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_getmetatable lua_getmetatable>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_getmetatable"+#else+foreign import ccall safe "lua.h lua_getmetatable"+#endif   lua_getmetatable :: LuaState -> StackIndex -> IO CInt  -- | Wrapper around <https://lua.org/manual/5.3/manual.html#lua_getglobal \@@ -319,15 +479,27 @@   hslua_setfield :: LuaState -> StackIndex -> Ptr CChar -> IO CInt  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawset lua_rawset>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rawset"+#else+foreign import ccall safe "lua.h lua_rawset"+#endif   lua_rawset :: LuaState -> StackIndex -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawseti lua_rawseti>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_rawseti"+#else+foreign import ccall safe "lua.h lua_rawseti"+#endif   lua_rawseti :: LuaState -> StackIndex -> CInt -> IO ()  -- | See <https://www.lua.org/manual/5.3/manual.html#lua_setmetatable lua_setmetatable>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lua.h lua_setmetatable"+#else+foreign import ccall safe "lua.h lua_setmetatable"+#endif   lua_setmetatable :: LuaState -> StackIndex -> IO ()  -- | Wrapper around <https://lua.org/manual/5.3/manual.html#lua_setglobal \@@ -462,5 +634,9 @@ #endif  -- | See <https://www.lua.org/manual/5.3/manual.html#luaL_loadstring luaL_loadstring>+#ifdef ALLOW_UNSAFE_GC foreign import ccall unsafe "lauxlib.h luaL_loadstring"+#else+foreign import ccall safe "lauxlib.h luaL_loadstring"+#endif   luaL_loadstring :: LuaState -> Ptr CChar -> IO StatusCode
src/Foreign/Lua/FunctionCalling.hs view
@@ -56,7 +56,6 @@   ) where  import Control.Monad (when)-import Data.ByteString.Char8 (unpack) import Foreign.C (CInt (..)) import Foreign.Lua.Api import Foreign.Lua.Types@@ -133,9 +132,9 @@     getglobal' fnName     x     z <- pcall nargs 1 Nothing-    if z /= OK-      then tostring (-1) >>= throwLuaError . unpack-      else peek (-1) <* pop 1+    if z == OK+      then peek (-1) <* pop 1+      else throwTopMessageAsError  instance (ToLuaStack a, LuaCallFunc b) => LuaCallFunc (a -> b) where   callFunc' fnName pushArgs nargs x =
src/Foreign/Lua/Types/FromLuaStack.hs view
@@ -57,6 +57,7 @@  import qualified Data.Text as T import qualified Data.Text.Encoding as T+import qualified Data.ByteString.Lazy as BL  -- | Result returned when trying to get a value from the lua stack. type Result a = Either String a@@ -115,6 +116,9 @@  instance FromLuaStack T.Text where   peek = fmap T.decodeUtf8 . peek++instance FromLuaStack BL.ByteString where+  peek = fmap BL.fromStrict . peek  #if MIN_VERSION_base(4,8,0) instance {-# OVERLAPS #-} FromLuaStack [Char] where
src/Foreign/Lua/Types/ToLuaStack.hs view
@@ -53,6 +53,7 @@  import qualified Data.Text as T import qualified Data.Text.Encoding as T+import qualified Data.ByteString.Lazy as BL  -- | A value that can be pushed to the Lua stack. class ToLuaStack a where@@ -83,6 +84,9 @@  instance ToLuaStack T.Text where   push = push . T.encodeUtf8++instance ToLuaStack BL.ByteString where+  push = push . BL.toStrict  #if MIN_VERSION_base(4,8,0) instance {-# OVERLAPS #-} ToLuaStack [Char] where
test/Foreign/Lua/ApiTest.hs view
@@ -37,6 +37,7 @@ import Prelude hiding (compare)  import Control.Monad (forM_)+import Data.Monoid ((<>)) import Foreign.Lua as Lua import Test.HsLua.Arbitrary () import Test.HsLua.Util (luaTestCase, pushLuaExpr)@@ -64,7 +65,7 @@         rawequal (-1) (-3)     ] -  , testGroup "insert" $+  , testGroup "insert"     [ luaTestCase "inserts stack elements using negative indices" $ do         pushLuaExpr "1, 2, 3, 4, 5, 6, 7, 8, 9"         insert (-6)@@ -226,7 +227,7 @@           pushLuaExpr "function () error 'error in error handler' end"           loadstring "error 'this fails'" *> pcall 0 0 (Just (-2)) -  , testCase "garbage collection" . runLua $ do+  , testCase "garbage collection" . runLua $       -- test that gc can be called with all constructors of type GCCONTROL.       forM_ [GCSTOP .. GCSETSTEPMUL] $ \what -> (gc what 23) @@ -247,6 +248,24 @@       let n1 = fromType lt1           n2 = fromType lt2       in Prelude.compare n1 n2 == Prelude.compare lt1 lt2++  , testCase "functions can throw a table as error message" $ do+      let mt = "{__tostring = function (e) return e.error_code end}"+      let err = "error(setmetatable({error_code = 23}," <> mt <> "))"+      res <- runLua . tryLua $ openbase *> loadstring err *> call 0 0+      assertEqual "wrong error message" (Left (LuaException "23")) res++  , testCase "handling table errors won't leak" $ do+      let mt = "{__tostring = function (e) return e.code end}"+      let err = "error(setmetatable({code = 5}," <> mt <> "))"+      let luaOp = do+            openbase+            oldtop <- gettop+            _ <- tryLua $ loadstring err *> call 0 0+            newtop <- gettop+            return (newtop - oldtop)+      res <- runLua luaOp+      assertEqual "error handling leaks values to the stack" 0 res   ]  compareWith :: (LuaInteger -> LuaInteger -> Bool)