lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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
>
>
>