[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Exceptions from lua_getfield with __index metamethod
- From: Jerome Vuarand <jerome.vuarand@...>
- Date: Fri, 28 Oct 2011 10:59:03 +0200
2011/10/28 Bryan McGinty <bmcginty@silverspringnet.com>:
> I am writing Lua library code in C. I am attempting to
> determine if a global object exists, and if it does has
> a particular key.
>
> I first determine if the global object exists using:
> lua_getglobal(ls, module);
> if (lua_isnil(ls, -1) == 0) {
>
> If the object exists and a key has been specified I then
>
> attempt to determine if the key exists using:
> lua_getfield(ls, -1, key);
>
> With this call the object's __index metamethod is called.
> If the __index metamethod returns an argument error my
> code terminates.
>
> Is there a better way to be doing this operation? If not,
> how can I catch the exception?
You have to wrap the code that can generate the exception in a
protected call. In C it's done with lua_pcall or lua_cpcall. In your
case you would replace code like this:
const char* get_foo_bar(lua_State* L)
{
const char* name;
// Lua part, may throw
lua_getglobal(L, "foo");
if (!lua_isnil(L, -1))
{
lua_getfield(L, -1, "bar");
if (lua_isstring(L, -1))
name = strdup(lua_tostring(L, -1));
lua_pop(L, 1); // pop foo.bar or nil
}
lua_pop(L, 1); // pop foo or nil
// C part, safe
name = adjust_name(name);
return name;
}
with code like this:
struct context_t
{
const char* name;
};
const char* get_foo_bar2(lua_State* L)
{
context_t context;
const char* name;
// protect the Lua part
lua_cpcall(L, get_foo_bar2_helper, &context);
name = context.name;
// C part stays the same
name = adjust_name(name);
return name;
}
int get_foo_bar2_helper(lua_State* L)
{
context_t* context;
const char* name;
context = lua_touserdata(L, 1);
lua_getglobal(L, "foo");
if (!lua_isnil(L, -1))
{
lua_getfield(L, -1, "bar");
if (lua_isstring(L, -1))
name = strdup(lua_tostring(L, -1));
lua_pop(L, 1); // pop foo.bar or nil
}
lua_pop(L, 1); // pop foo or nil
context.name = name;
return 0;
}