Skip to content

Commit

Permalink
Make Lua type an instance of Alternative
Browse files Browse the repository at this point in the history
When one operation fails, it should be possible to try a second.
  • Loading branch information
tarleb committed Jul 19, 2017
1 parent 41d79db commit d7686bd
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/Foreign/Lua.hs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,9 @@ module Foreign.Lua
-- Lua program, you need to define @_HASKELLERR = {}@ manually, after creating
-- the Lua state.
, LuaException (..)
, throwLuaError
, catchLuaError
, throwLuaError
, tryLua
) where

import Prelude hiding (compare, concat)
Expand Down
16 changes: 14 additions & 2 deletions src/Foreign/Lua/Types/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-|
Module : Foreign.Lua.Types.Error
Copyright : © 2017 Albert Krewinkel
Expand All @@ -34,16 +35,18 @@ module Foreign.Lua.Types.Error
( LuaException (..)
, catchLuaError
, throwLuaError
, tryLua
) where

import Control.Applicative (Alternative (..))
import Control.Exception (Exception)
import Control.Monad.Catch (throwM, catch)
import Control.Monad.Catch (catch, throwM, try)
import Data.Typeable (Typeable)
import Foreign.Lua.Types.Lua (Lua)

-- | Exceptions raised by Lua-related operations.
data LuaException = LuaException String
deriving (Typeable)
deriving (Eq, Typeable)

instance Show LuaException where
show (LuaException err) = err
Expand All @@ -57,3 +60,12 @@ throwLuaError = throwM . LuaException
-- | Catch a @'LuaException'@.
catchLuaError :: Lua a -> (LuaException -> Lua a) -> Lua a
catchLuaError = catch

-- | Return either the result of a Lua computation or, if an exception was
-- thrown, the error.
tryLua :: Lua a -> Lua (Either LuaException a)
tryLua = try

instance Alternative Lua where
empty = throwLuaError "empty"
x <|> y = either (const y) return =<< tryLua x
8 changes: 8 additions & 0 deletions test/Foreign/LuaTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module Foreign.LuaTest (tests) where

import Prelude hiding (concat)

import Control.Applicative ((<|>))
import Data.ByteString (ByteString)
import Data.Either (isLeft, isRight)
import Data.Monoid ((<>))
Expand Down Expand Up @@ -144,6 +145,13 @@ tests = testGroup "lua integration tests"
, testCase "error-less code gives in 'Right' result" $
assertBool "error was not intercepted" . isRight =<<
runLuaEither (push True *> peek (-1) :: Lua Bool)

, testCase "catching lua errors within the lua type" $
assert . isLeft =<< (runLua $ tryLua (throwLuaError "test"))

, testCase "second alternative is used when first fails" $
assertEqual "alternative failed" (Right True) =<<
runLuaEither (throwLuaError "test" <|> return True)
]
]

Expand Down

0 comments on commit d7686bd

Please sign in to comment.