From d075e7322f0ac1de505b025fd3004b8d4123cc56 Mon Sep 17 00:00:00 2001 From: Philipp Janda Date: Sun, 21 Feb 2016 11:59:44 +0100 Subject: Support table errors. LuaSocket wraps error messages raised by newtry() in a table and unpacks them later so that (string) errors raised by 3rd-party code can be passed through as-is. This obviously didn't work when the 3rd-party code raised a table as an error message. This change sets a private metatable on all wrapped LuaSocket exceptions to distinguish them from 3rd-party table errors. --- src/except.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/except.c b/src/except.c index 261ac98..def35a0 100644 --- a/src/except.c +++ b/src/except.c @@ -12,7 +12,7 @@ #if LUA_VERSION_NUM < 502 #define lua_pcallk(L, na, nr, err, ctx, cont) \ - ((void)ctx,(void)cont,lua_pcall(L, na, nr, err)) + (((void)ctx),((void)cont),lua_pcall(L, na, nr, err)) #endif #if LUA_VERSION_NUM < 503 @@ -39,12 +39,11 @@ static luaL_Reg func[] = { * Try factory \*-------------------------------------------------------------------------*/ static void wrap(lua_State *L) { - lua_newtable(L); - lua_pushnumber(L, 1); - lua_pushvalue(L, -3); - lua_settable(L, -3); - lua_insert(L, -2); - lua_pop(L, 1); + lua_createtable(L, 1, 0); + lua_pushvalue(L, -2); + lua_rawseti(L, -2, 1); + lua_pushvalue(L, lua_upvalueindex(2)); + lua_setmetatable(L, -2); } static int finalize(lua_State *L) { @@ -58,15 +57,16 @@ static int finalize(lua_State *L) { } else return lua_gettop(L); } -static int do_nothing(lua_State *L) { +static int do_nothing(lua_State *L) { (void) L; - return 0; + return 0; } static int global_newtry(lua_State *L) { lua_settop(L, 1); if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); - lua_pushcclosure(L, finalize, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushcclosure(L, finalize, 2); return 1; } @@ -74,13 +74,16 @@ static int global_newtry(lua_State *L) { * Protect factory \*-------------------------------------------------------------------------*/ static int unwrap(lua_State *L) { - if (lua_istable(L, -1)) { - lua_pushnumber(L, 1); - lua_gettable(L, -2); - lua_pushnil(L); - lua_insert(L, -2); - return 1; - } else return 0; + if (lua_istable(L, -1) && lua_getmetatable(L, -1)) { + int r = lua_rawequal(L, -1, lua_upvalueindex(2)); + lua_pop(L, 1); + if (r) { + lua_pushnil(L); + lua_rawgeti(L, -2, 1); + return 1; + } + } + return 0; } static int protected_finish(lua_State *L, int status, lua_KContext ctx) { @@ -110,7 +113,9 @@ static int protected_(lua_State *L) { } static int global_protect(lua_State *L) { - lua_pushcclosure(L, protected_, 1); + lua_settop(L, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushcclosure(L, protected_, 2); return 1; } @@ -118,6 +123,9 @@ static int global_protect(lua_State *L) { * Init module \*-------------------------------------------------------------------------*/ int except_open(lua_State *L) { - luaL_setfuncs(L, func, 0); + lua_newtable(L); /* metatable for wrapped exceptions */ + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + luaL_setfuncs(L, func, 1); return 0; } -- cgit v1.2.3-55-g6feb From 7cab8a5006da807d83f427217e2158079bb78145 Mon Sep 17 00:00:00 2001 From: Philipp Janda Date: Sun, 21 Feb 2016 12:28:13 +0100 Subject: Update comment in except.h --- src/except.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/except.h b/src/except.h index 1e7a245..2497c05 100644 --- a/src/except.h +++ b/src/except.h @@ -9,21 +9,26 @@ * error checking was taking a substantial amount of the coding. These * function greatly simplify the task of checking errors. * -* The main idea is that functions should return nil as its first return -* value when it finds an error, and return an error message (or value) +* The main idea is that functions should return nil as their first return +* values when they find an error, and return an error message (or value) * following nil. In case of success, as long as the first value is not nil, * the other values don't matter. * * The idea is to nest function calls with the "try" function. This function -* checks the first value, and calls "error" on the second if the first is -* nil. Otherwise, it returns all values it received. +* checks the first value, and, if it's falsy, wraps the second value in a +* table with metatable and calls "error" on it. Otherwise, it returns all +* values it received. Basically, it works like the Lua "assert" function, +* but it creates errors targeted specifically at "protect". * -* The protect function returns a new function that behaves exactly like the -* function it receives, but the new function doesn't throw exceptions: it -* returns nil followed by the error message instead. +* The "newtry" function is a factory for "try" functions that call a +* finalizer in protected mode before calling "error". * -* With these two function, it's easy to write functions that throw -* exceptions on error, but that don't interrupt the user script. +* The "protect" function returns a new function that behaves exactly like +* the function it receives, but the new function catches exceptions thrown +* by "try" functions and returns nil followed by the error message instead. +* +* With these three functions, it's easy to write functions that throw +* exceptions on error, but that don't interrupt the user script. \*=========================================================================*/ #include "lua.h" -- cgit v1.2.3-55-g6feb