packages feed

hslua 0.9.4 → 0.9.5

raw patch · 9 files changed

+143/−17 lines, 9 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Foreign.Lua.Util: data OrNil a
+ Foreign.Lua: Optional :: Maybe a -> Optional a
+ Foreign.Lua: OrNil :: Maybe a -> OrNil a
+ Foreign.Lua: [fromOptional] :: Optional a -> Maybe a
+ Foreign.Lua: [toMaybe] :: OrNil a -> Maybe a
+ Foreign.Lua: modifyLuaError :: Lua a -> (String -> String) -> Lua a
+ Foreign.Lua: newtype Optional a
+ Foreign.Lua: newtype OrNil a
+ Foreign.Lua: raiseError :: ToLuaStack a => a -> Lua NumResults
+ Foreign.Lua.Types.Error: modifyLuaError :: Lua a -> (String -> String) -> Lua a
+ Foreign.Lua.Util: Optional :: Maybe a -> Optional a
+ Foreign.Lua.Util: OrNil :: Maybe a -> OrNil a
+ Foreign.Lua.Util: [fromOptional] :: Optional a -> Maybe a
+ Foreign.Lua.Util: [toMaybe] :: OrNil a -> Maybe a
+ Foreign.Lua.Util: instance Foreign.Lua.Types.FromLuaStack.FromLuaStack a => Foreign.Lua.Types.FromLuaStack.FromLuaStack (Foreign.Lua.Util.Optional a)
+ Foreign.Lua.Util: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack a => Foreign.Lua.Types.ToLuaStack.ToLuaStack (Foreign.Lua.Util.Optional a)
+ Foreign.Lua.Util: newtype Optional a
+ Foreign.Lua.Util: newtype OrNil a
+ Foreign.Lua.Util: raiseError :: ToLuaStack a => a -> Lua NumResults

Files

CHANGELOG.md view
@@ -1,6 +1,22 @@ ## Changelog -### 0.9.4 (unpublished)+### 0.9.5 (unpublished)++- Provide Optional as a replacement for OrNil. Exports of the latter+  have been fixed.+- Provide utility function `raiseError`: Its argument will be thrown as+  an error in Lua.+- Add `modifyLuaError`: The function lives in Foreign.Lua.Error and+  allows to alter error messages. This is most useful for amending+  errors with additional information.+- Fixed a bug in `toList` which left a element on the stack if+  deserializing that element lead to an error. This also affected the+  FromLuaStack instance for lists.+- Fixed a bug in `pairsFromTable` which left a key-value pair on the+  stack if either of them could not be read into the expected type. This+  also affected the FromLuaStack instance for Map.++### 0.9.4  - Make Lua an instance of MonadMask: MonadMask from Control.Monad.Catch   allows to mask asynchronous exceptions. This allows to define a
hslua.cabal view
@@ -1,5 +1,5 @@ name:                   hslua-version:                0.9.4+version:                0.9.5 stability:              beta cabal-version:          >= 1.8 license:                MIT@@ -201,6 +201,7 @@                       , Foreign.Lua.TypesTest                       , Foreign.Lua.Types.FromLuaStackTest                       , Foreign.Lua.Types.ToLuaStackTest+                      , Foreign.Lua.UtilTest                       , Test.HsLua.Arbitrary                       , Test.HsLua.Util   build-depends:        base
src/Foreign/Lua.hs view
@@ -57,11 +57,14 @@   , freeCFunction   , pushHaskellFunction   , registerHaskellFunction-  -- * Utility functions+  -- * Utility functions and types   , runLua   , runLuaEither   , getglobal'   , setglobal'+  , raiseError+  , Optional (Optional, fromOptional)+  , OrNil (OrNil, toMaybe)   -- * API   , module Foreign.Lua.Api   , module Foreign.Lua.Api.Types@@ -150,6 +153,7 @@   , catchLuaError   , throwLuaError   , tryLua+  , modifyLuaError   ) where  import Prelude hiding (compare, concat)
src/Foreign/Lua/Types/Error.hs view
@@ -35,6 +35,7 @@   ( LuaException (..)   , catchLuaError   , throwLuaError+  , modifyLuaError   , tryLua   ) where @@ -60,6 +61,11 @@ -- | Catch a @'LuaException'@. catchLuaError :: Lua a -> (LuaException -> Lua a) -> Lua a catchLuaError = catch++-- | Catch @'LuaException'@, alter the error message and rethrow.+modifyLuaError :: Lua a -> (String -> String) -> Lua a+modifyLuaError luaOp modifier =+  luaOp `catchLuaError` \(LuaException msg) -> throwLuaError (modifier msg)  -- | Return either the result of a Lua computation or, if an exception was -- thrown, the error.
src/Foreign/Lua/Types/FromLuaStack.hs view
@@ -135,19 +135,20 @@  -- | Read a table into a list toList :: FromLuaStack a => StackIndex -> Lua [a]-toList n = (go . enumFromTo 1 =<< rawlen n) `catchLuaError` amendError+toList n = resetStackOnError ("Could not read list: " ++) $+  go . enumFromTo 1 =<< rawlen n  where   go [] = return []   go (i : is) = do     ret <- rawgeti n i *> peek (-1) <* pop 1     (ret:) <$> go is-  amendError err = throwLuaError ("Could not read list: " ++ show err)  -- | Read a table into a list of pairs. pairsFromTable :: (FromLuaStack a, FromLuaStack b) => StackIndex -> Lua [(a, b)]-pairsFromTable idx = do-  pushnil-  remainingPairs+pairsFromTable idx =+  resetStackOnError ("Could not read key-value pairs: " ++) $ do+    pushnil+    remainingPairs  where   remainingPairs = do     res <- nextPair (if idx < 0 then idx - 1 else idx)@@ -167,6 +168,13 @@       pop 1 -- removes the value, keeps the key       return (Just (k, v))     else return Nothing++resetStackOnError :: (String -> String) -> Lua a -> Lua a+resetStackOnError modifier op = do+  oldTop <- gettop+  op `catchLuaError` \(LuaException msg) -> do+    settop oldTop+    throwLuaError (modifier msg)  -- -- Tuples
src/Foreign/Lua/Util.hs view
@@ -36,7 +36,9 @@   , setglobal'   , runLua   , runLuaEither-  , OrNil (toMaybe)+  , raiseError+  , OrNil (OrNil, toMaybe)+  , Optional (Optional, fromOptional)   ) where  import Control.Exception (bracket, try)@@ -96,19 +98,38 @@   getglobal x   mapM_ (\a -> getfield (-1) a *> remove (-2)) xs +-- | Raise a Lua error, using the given value as the error object. This must be+-- the return value of a function which has been wrapped with+-- @'wrapHaskellFunction'@.+raiseError :: ToLuaStack a => a -> Lua NumResults+raiseError e = do+  push e+  fromIntegral <$> lerror+{-# INLINABLE raiseError #-}+ -- | Newtype wrapper intended to be used for optional Lua values. Nesting this -- type is strongly discouraged as missing values on inner levels are -- indistinguishable from missing values on an outer level; wrong values -- would be the likely result.-newtype OrNil a = OrNil { toMaybe :: Maybe a }+newtype Optional a = Optional { fromOptional :: Maybe a } -instance FromLuaStack a => FromLuaStack (OrNil a) where+instance FromLuaStack a => FromLuaStack (Optional a) where   peek idx = do     noValue <- isnoneornil idx     if noValue-      then return (OrNil Nothing)-      else OrNil . Just <$> peek idx+      then return (Optional Nothing)+      else Optional . Just <$> peek idx +instance ToLuaStack a => ToLuaStack (Optional a) where+  push (Optional Nothing)  = pushnil+  push (Optional (Just x)) = push x++-- | Like @'Optional'@, but deprecated. Will be removed in the next major+-- release.+newtype OrNil a = OrNil { toMaybe :: Maybe a }++instance FromLuaStack a => FromLuaStack (OrNil a) where+  peek idx = fmap (OrNil . fromOptional) (peek idx)+ instance ToLuaStack a => ToLuaStack (OrNil a) where-  push (OrNil Nothing)  = pushnil-  push (OrNil (Just x)) = push x+  push (OrNil x)  = push (Optional x)
test/Foreign/Lua/Types/FromLuaStackTest.hs view
@@ -32,12 +32,12 @@ -} module Foreign.Lua.Types.FromLuaStackTest (tests) where -import Foreign.Lua (Lua, LuaInteger, LuaException (LuaException), call,-                    dostring, loadstring, runLua, tryLua)+import Foreign.Lua import Foreign.Lua.Types.FromLuaStack  import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit (assertEqual, testCase)+import Test.HsLua.Util (pushLuaExpr)  -- | Specifications for Attributes parsing functions. tests :: TestTree@@ -61,4 +61,18 @@       assertEqual "error message mismatched" (Left err) =<< runLua         (loadstring "return {1, 5, 23, true, 42}" *> call 0 1          *> peekEither (-1) :: Lua (Result [LuaInteger]))++  , testCase "stack is unchanged if getting a list fails" . runLua $ do+      liftIO . assertEqual "there should be no element on the stack" 0+        =<< gettop+      pushLuaExpr "{1, 1, 2, 3, 5, 8}"+      _ <- tryLua (toList stackTop :: Lua [Bool])+      liftIO . assertEqual "there should be exactly one element on the stack" 1+        =<< gettop++  , testCase "stack is unchanged if getting key-value pairs fails" . runLua $ do+      pushLuaExpr "{{foo = 'bar', baz = 5}}"+      _ <- tryLua (pairsFromTable stackTop :: Lua [(String, String)])+      liftIO . assertEqual "there should be no element on the stack" 1+        =<< gettop   ]
+ test/Foreign/Lua/UtilTest.hs view
@@ -0,0 +1,54 @@+{-+Copyright © 2018 Albert Krewinkel++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.+-}+{-| Tests for utility types and functions+-}+module Foreign.Lua.UtilTest (tests) where++import Foreign.Lua+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (assertEqual, testCase)++-- | Specifications for Attributes parsing functions.+tests :: TestTree+tests = testGroup "Utilities"+  [ testCase "Optional return the value if it exists" . runLua $ do+      push "Moin"+      liftIO . assertEqual "Optional value should equal pushed value" (Just "Moin")+        =<< fmap fromOptional (peek stackTop)++  , testCase "Optional can deal with missing values" . runLua $ do+      pushnil+      liftIO . assertEqual "Peeking nil should return Nothing" Nothing+        =<< fmap fromOptional (peek stackTop :: Lua (Optional String))+      liftIO . assertEqual "Inexistant indices should be accepted" Nothing+        =<< fmap fromOptional (peek (nthFromBottom 9) :: Lua (Optional String))++  , testCase "raiseError causes a Lua error" $ do+      let msg = "error message"+      let luaOp = do+            pushHaskellFunction (raiseError msg)+            wrapHaskellFunction+            call 0 0+            return ()+      assertEqual "An error should be raised" (Left (LuaException msg))+        =<< runLuaEither luaOp+  ]
test/test-hslua.hs view
@@ -27,6 +27,7 @@ import qualified Foreign.Lua.TypesTest import qualified Foreign.Lua.Types.FromLuaStackTest import qualified Foreign.Lua.Types.ToLuaStackTest+import qualified Foreign.Lua.UtilTest  main :: IO () main = defaultMain $ testGroup "hslua" tests@@ -36,6 +37,7 @@ tests =   [ Foreign.Lua.ApiTest.tests   , Foreign.Lua.FunctionCallingTest.tests+  , Foreign.Lua.UtilTest.tests   , testGroup "Sendings and receiving values from the stack"     [ Foreign.Lua.TypesTest.tests     , Foreign.Lua.Types.FromLuaStackTest.tests