[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: RE: std::exception Interoperability
- From: "Erik Cassel" <erik@...>
- Date: Sat, 25 Mar 2006 11:30:26 -0800
The patch can be implemented in luaconf.h, but for clarity I will show it
expanded in ldo.c. Afterwards I include a sample function illustrating the
uses of this patch.
First we replace Lua's proprietary exception with a class derived from
std::exception. Its job is to properly maintain Lua's stack during the
lifetime of the exception. Then, in luaD_rawrunprotected we replace "catch
(...)" with type-specific exception handlers.
// ************************************************************
// Exception definition
class lua_exception : public std::exception
{
private:
bool committed; // == luaD_rawrunprotected has handled the exception
struct lua_longjmp *const errorJmp;
public:
struct lua_State* const L;
lua_exception(struct lua_State *L, struct lua_longjmp *errorJmp);
~lua_exception();
/*override*/ const char *what() const;
// To be called only by luaD_rawrunprotected:
void commit() { committed = true; }
};
lua_exception::lua_exception(struct lua_State *L, struct lua_longjmp
*errorJmp)
:L(L)
,errorJmp(errorJmp)
,committed(false)
{
}
const char *lua_exception::what() const
{
// Look! You can inspect the error message using a standard call!
return lua_tostring(L, -1);
}
lua_exception::~lua_exception()
{
if (!committed)
{
// The exception was caught before Lua got it.
// Revert the error state
// TODO: Is it safe to set it to 0 or should we
// restore it to a previous state?
errorJmp->status = 0;
// Pop the error message
lua_pop(L, 1);
}
}
// ************************************************************
// Throwing exceptions
#define LUAI_THROW(L,c) throw(lua_exception(L,c))
#define luai_jmpbuf int /* dummy type */
// ***********************************************************
// Exception handling
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
struct lua_longjmp lj;
lj.status = 0;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
#if defined(__cplusplus)
try
{
(*f)(L, ud);
}
catch (lua_exception& e)
{
// lua_error was called somewhere and the
// error message is on the stack. Commit the
// lua_exception so that it doesn't take the
// error message off of the stack
e.commit();
// Is this necessary?
if (lj.status == 0)
lj.status = -1;
}
catch (std::exception const& e)
{
// We caught a conventional exception.
// Convert it into a lua_exception that can then
// be passed on to Lua.
// If I were comfortable
// with the inner workings of lua_error() I could
// avoid this extra try/catch block and just set
// all the proper Lua states myself. However, this
// code is reasonably future-proof.
try
{
lua_pushstring(L, e.what());
lua_error(L);
}
catch (lua_exception& e)
{
e.commit();
// Is this necessary?
if (lj.status == 0)
lj.status = -1;
}
}
#else
LUAI_TRY(L, &lj,
(*f)(L, ud);
);
#endif
L->errorJmp = lj.previous; /* restore old error handler */
return lj.status;
}
// Done
// ***********************************************************************
Here is some pseudo-code:
int myFunction(lua_State *thread)
{
int n = lua_gettop(thread);
if (n!=7)
// Lua will catch this exception and push the message
// onto the Lua stack
throw std::runtime_error("Expected 7 arguments");
try
{
// This could throw a Lua exception
luaL_argcheck (thread, 3, 6, "foo");
// This could throw a bad_cast exception
Bar* bar = boost::polymorphic_cast<Bar*>(getFoo());
}
catch (std::exception& e)
{
// You can inspect the error message
fprintf(stderr, e.what());
// It is safe to throw or not throw e
if (!myHandleIt(e))
throw e;
}
return 0;
}
-Erik
-----Original Message-----
From: lua-bounces@bazar2.conectiva.com.br
[mailto:lua-bounces@bazar2.conectiva.com.br] On Behalf Of D Burgess
Sent: Friday, March 24, 2006 2:26 PM
To: Lua list
Subject: Re: std::exception Interoperability
I use a std::exception scheme in WIndows to handle the MS
defiencies with setjmp/longjmp. I would like to see what you have
done
DB
On 3/25/06, Erik Cassel <erik@roblox.com> wrote:
>
> I have patched Lua 5.1 to seamlessly work with std::exception.
>
> This lets me throw an std::exception-derived object from anywhere in C++
> code. Lua will catch it and translate it appropriately in
> luaD_rawrunprotected().
>
> Also, Lua uses an std::exception-derived class to throw Lua errors. This
> means I can catch errors thrown by Lua (as in lua_touserdata).
>
>
> The benefits of this approach are:
>
> 1) I don't have to write exception handlers in every entry point in
my
> code. If my code is based on std/boost then I can be confident that
> exceptions thrown by my code will be handled by Lua. I don't have to
> translate them into lua_error() calls.
>
> 2) It is perfectly safe for me to intercept an exception thrown by
Lua.
> Since Lua now throws std::exception-derived objects I can catch and
inspect
> errors with a catch(std::exception&) clause. Moreover, if I decide *not*
to
> re-throw the exception, then Lua automatically pops the error message from
> the stack.
>
>
> Has anybody else done something like this? Would it be useful to anybody?
> Have I missed something?
>
> I'd be happy to post my patch (and go over implementation details) and/or
> show some sample code of how it can be used.
>
> -Erik
>
>
>