mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 12:28:21 +01:00
Merge pull request #162 from siffiejoe/exception-meta
Support table errors in LuaSockets LTN13 C implementation.
This commit is contained in:
commit
9ffd96724d
@ -220,13 +220,6 @@ Returns an equivalent function that instead of throwing exceptions,
|
|||||||
returns <tt><b>nil</b></tt> followed by an error message.
|
returns <tt><b>nil</b></tt> followed by an error message.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
Note: Beware that if your function performs some illegal operation that
|
|
||||||
raises an error, the protected function will catch the error and return it
|
|
||||||
as a string. This is because the <a href=#try><tt>try</tt></a> function
|
|
||||||
uses errors as the mechanism to throw exceptions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=select>
|
<p class=name id=select>
|
||||||
@ -424,8 +417,7 @@ socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b
|
|||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Throws an exception in case of error. The exception can only be caught
|
Throws an exception in case of error. The exception can only be caught
|
||||||
by the <a href=#protect><tt>protect</tt></a> function. It does not explode
|
by the <a href=#protect><tt>protect</tt></a> function.
|
||||||
into an error message.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@ -436,7 +428,10 @@ nested with <tt>try</tt>.
|
|||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
|
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
|
||||||
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt>. Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub>.
|
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
|
||||||
|
Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
|
||||||
|
in a table with metatable used by <a href=#protect><tt>protect</tt></a> to
|
||||||
|
distinguish exceptions from runtime errors.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class=example>
|
<pre class=example>
|
||||||
|
42
src/except.c
42
src/except.c
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#if LUA_VERSION_NUM < 502
|
#if LUA_VERSION_NUM < 502
|
||||||
#define lua_pcallk(L, na, nr, err, ctx, cont) \
|
#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
|
#endif
|
||||||
|
|
||||||
#if LUA_VERSION_NUM < 503
|
#if LUA_VERSION_NUM < 503
|
||||||
@ -39,12 +39,11 @@ static luaL_Reg func[] = {
|
|||||||
* Try factory
|
* Try factory
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void wrap(lua_State *L) {
|
static void wrap(lua_State *L) {
|
||||||
lua_newtable(L);
|
lua_createtable(L, 1, 0);
|
||||||
lua_pushnumber(L, 1);
|
lua_pushvalue(L, -2);
|
||||||
lua_pushvalue(L, -3);
|
lua_rawseti(L, -2, 1);
|
||||||
lua_settable(L, -3);
|
lua_pushvalue(L, lua_upvalueindex(2));
|
||||||
lua_insert(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int finalize(lua_State *L) {
|
static int finalize(lua_State *L) {
|
||||||
@ -66,7 +65,8 @@ static int do_nothing(lua_State *L) {
|
|||||||
static int global_newtry(lua_State *L) {
|
static int global_newtry(lua_State *L) {
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,13 +74,16 @@ static int global_newtry(lua_State *L) {
|
|||||||
* Protect factory
|
* Protect factory
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int unwrap(lua_State *L) {
|
static int unwrap(lua_State *L) {
|
||||||
if (lua_istable(L, -1)) {
|
if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
|
||||||
lua_pushnumber(L, 1);
|
int r = lua_rawequal(L, -1, lua_upvalueindex(2));
|
||||||
lua_gettable(L, -2);
|
lua_pop(L, 1);
|
||||||
lua_pushnil(L);
|
if (r) {
|
||||||
lua_insert(L, -2);
|
lua_pushnil(L);
|
||||||
return 1;
|
lua_rawgeti(L, -2, 1);
|
||||||
} else return 0;
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
|
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) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +123,9 @@ static int global_protect(lua_State *L) {
|
|||||||
* Init module
|
* Init module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int except_open(lua_State *L) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
21
src/except.h
21
src/except.h
@ -9,20 +9,25 @@
|
|||||||
* error checking was taking a substantial amount of the coding. These
|
* error checking was taking a substantial amount of the coding. These
|
||||||
* function greatly simplify the task of checking errors.
|
* function greatly simplify the task of checking errors.
|
||||||
*
|
*
|
||||||
* The main idea is that functions should return nil as its first return
|
* The main idea is that functions should return nil as their first return
|
||||||
* value when it finds an error, and return an error message (or value)
|
* 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,
|
* following nil. In case of success, as long as the first value is not nil,
|
||||||
* the other values don't matter.
|
* the other values don't matter.
|
||||||
*
|
*
|
||||||
* The idea is to nest function calls with the "try" function. This function
|
* 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
|
* checks the first value, and, if it's falsy, wraps the second value in a
|
||||||
* nil. Otherwise, it returns all values it received.
|
* 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
|
* The "newtry" function is a factory for "try" functions that call a
|
||||||
* function it receives, but the new function doesn't throw exceptions: it
|
* finalizer in protected mode before calling "error".
|
||||||
* returns nil followed by the error message instead.
|
|
||||||
*
|
*
|
||||||
* With these two function, it's easy to write functions that throw
|
* 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.
|
* exceptions on error, but that don't interrupt the user script.
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
|
@ -1,6 +1,31 @@
|
|||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
try = socket.newtry(function()
|
|
||||||
print("finalized!!!")
|
local finalizer_called
|
||||||
|
|
||||||
|
local func = socket.protect(function(err, ...)
|
||||||
|
local try = socket.newtry(function()
|
||||||
|
finalizer_called = true
|
||||||
|
error("ignored")
|
||||||
|
end)
|
||||||
|
|
||||||
|
if err then
|
||||||
|
return error(err, 0)
|
||||||
|
else
|
||||||
|
return try(...)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
try = socket.protect(try)
|
|
||||||
print(try(nil, "it works"))
|
local ret1, ret2, ret3 = func(false, 1, 2, 3)
|
||||||
|
assert(not finalizer_called, "unexpected finalizer call")
|
||||||
|
assert(ret1 == 1 and ret2 == 2 and ret3 == 3, "incorrect return values")
|
||||||
|
|
||||||
|
ret1, ret2, ret3 = func(false, false, "error message")
|
||||||
|
assert(finalizer_called, "finalizer not called")
|
||||||
|
assert(ret1 == nil and ret2 == "error message" and ret3 == nil, "incorrect return values")
|
||||||
|
|
||||||
|
local err = {key = "value"}
|
||||||
|
ret1, ret2 = pcall(func, err)
|
||||||
|
assert(not ret1, "error not rethrown")
|
||||||
|
assert(ret2 == err, "incorrect error rethrown")
|
||||||
|
|
||||||
|
print("OK")
|
||||||
|
Loading…
Reference in New Issue
Block a user