diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/except.c | 46 | ||||
| -rw-r--r-- | src/except.h | 23 |
2 files changed, 41 insertions, 28 deletions
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 @@ | |||
| 12 | 12 | ||
| 13 | #if LUA_VERSION_NUM < 502 | 13 | #if LUA_VERSION_NUM < 502 |
| 14 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ | 14 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ |
| 15 | ((void)ctx,(void)cont,lua_pcall(L, na, nr, err)) | 15 | (((void)ctx),((void)cont),lua_pcall(L, na, nr, err)) |
| 16 | #endif | 16 | #endif |
| 17 | 17 | ||
| 18 | #if LUA_VERSION_NUM < 503 | 18 | #if LUA_VERSION_NUM < 503 |
| @@ -39,12 +39,11 @@ static luaL_Reg func[] = { | |||
| 39 | * Try factory | 39 | * Try factory |
| 40 | \*-------------------------------------------------------------------------*/ | 40 | \*-------------------------------------------------------------------------*/ |
| 41 | static void wrap(lua_State *L) { | 41 | static void wrap(lua_State *L) { |
| 42 | lua_newtable(L); | 42 | lua_createtable(L, 1, 0); |
| 43 | lua_pushnumber(L, 1); | 43 | lua_pushvalue(L, -2); |
| 44 | lua_pushvalue(L, -3); | 44 | lua_rawseti(L, -2, 1); |
| 45 | lua_settable(L, -3); | 45 | lua_pushvalue(L, lua_upvalueindex(2)); |
| 46 | lua_insert(L, -2); | 46 | lua_setmetatable(L, -2); |
| 47 | lua_pop(L, 1); | ||
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | static int finalize(lua_State *L) { | 49 | static int finalize(lua_State *L) { |
| @@ -58,15 +57,16 @@ static int finalize(lua_State *L) { | |||
| 58 | } else return lua_gettop(L); | 57 | } else return lua_gettop(L); |
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | static int do_nothing(lua_State *L) { | 60 | static int do_nothing(lua_State *L) { |
| 62 | (void) L; | 61 | (void) L; |
| 63 | return 0; | 62 | return 0; |
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | static int global_newtry(lua_State *L) { | 65 | static int global_newtry(lua_State *L) { |
| 67 | lua_settop(L, 1); | 66 | lua_settop(L, 1); |
| 68 | if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); | 67 | if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); |
| 69 | lua_pushcclosure(L, finalize, 1); | 68 | lua_pushvalue(L, lua_upvalueindex(1)); |
| 69 | lua_pushcclosure(L, finalize, 2); | ||
| 70 | return 1; | 70 | return 1; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| @@ -74,13 +74,16 @@ static int global_newtry(lua_State *L) { | |||
| 74 | * Protect factory | 74 | * Protect factory |
| 75 | \*-------------------------------------------------------------------------*/ | 75 | \*-------------------------------------------------------------------------*/ |
| 76 | static int unwrap(lua_State *L) { | 76 | static int unwrap(lua_State *L) { |
| 77 | if (lua_istable(L, -1)) { | 77 | if (lua_istable(L, -1) && lua_getmetatable(L, -1)) { |
| 78 | lua_pushnumber(L, 1); | 78 | int r = lua_rawequal(L, -1, lua_upvalueindex(2)); |
| 79 | lua_gettable(L, -2); | 79 | lua_pop(L, 1); |
| 80 | lua_pushnil(L); | 80 | if (r) { |
| 81 | lua_insert(L, -2); | 81 | lua_pushnil(L); |
| 82 | return 1; | 82 | lua_rawgeti(L, -2, 1); |
| 83 | } else return 0; | 83 | return 1; |
| 84 | } | ||
| 85 | } | ||
| 86 | return 0; | ||
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | static int protected_finish(lua_State *L, int status, lua_KContext ctx) { | 89 | static int protected_finish(lua_State *L, int status, lua_KContext ctx) { |
| @@ -110,7 +113,9 @@ static int protected_(lua_State *L) { | |||
| 110 | } | 113 | } |
| 111 | 114 | ||
| 112 | static int global_protect(lua_State *L) { | 115 | static int global_protect(lua_State *L) { |
| 113 | lua_pushcclosure(L, protected_, 1); | 116 | lua_settop(L, 1); |
| 117 | lua_pushvalue(L, lua_upvalueindex(1)); | ||
| 118 | lua_pushcclosure(L, protected_, 2); | ||
| 114 | return 1; | 119 | return 1; |
| 115 | } | 120 | } |
| 116 | 121 | ||
| @@ -118,6 +123,9 @@ static int global_protect(lua_State *L) { | |||
| 118 | * Init module | 123 | * Init module |
| 119 | \*-------------------------------------------------------------------------*/ | 124 | \*-------------------------------------------------------------------------*/ |
| 120 | int except_open(lua_State *L) { | 125 | int except_open(lua_State *L) { |
| 121 | luaL_setfuncs(L, func, 0); | 126 | lua_newtable(L); /* metatable for wrapped exceptions */ |
| 127 | lua_pushboolean(L, 0); | ||
| 128 | lua_setfield(L, -2, "__metatable"); | ||
| 129 | luaL_setfuncs(L, func, 1); | ||
| 122 | return 0; | 130 | return 0; |
| 123 | } | 131 | } |
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 @@ | |||
| 9 | * error checking was taking a substantial amount of the coding. These | 9 | * error checking was taking a substantial amount of the coding. These |
| 10 | * function greatly simplify the task of checking errors. | 10 | * function greatly simplify the task of checking errors. |
| 11 | * | 11 | * |
| 12 | * The main idea is that functions should return nil as its first return | 12 | * The main idea is that functions should return nil as their first return |
| 13 | * value when it finds an error, and return an error message (or value) | 13 | * values when they find an error, and return an error message (or value) |
| 14 | * following nil. In case of success, as long as the first value is not nil, | 14 | * following nil. In case of success, as long as the first value is not nil, |
| 15 | * the other values don't matter. | 15 | * the other values don't matter. |
| 16 | * | 16 | * |
| 17 | * The idea is to nest function calls with the "try" function. This function | 17 | * The idea is to nest function calls with the "try" function. This function |
| 18 | * checks the first value, and calls "error" on the second if the first is | 18 | * checks the first value, and, if it's falsy, wraps the second value in a |
| 19 | * nil. Otherwise, it returns all values it received. | 19 | * table with metatable and calls "error" on it. Otherwise, it returns all |
| 20 | * values it received. Basically, it works like the Lua "assert" function, | ||
| 21 | * but it creates errors targeted specifically at "protect". | ||
| 20 | * | 22 | * |
| 21 | * The protect function returns a new function that behaves exactly like the | 23 | * The "newtry" function is a factory for "try" functions that call a |
| 22 | * function it receives, but the new function doesn't throw exceptions: it | 24 | * finalizer in protected mode before calling "error". |
| 23 | * returns nil followed by the error message instead. | ||
| 24 | * | 25 | * |
| 25 | * With these two function, it's easy to write functions that throw | 26 | * The "protect" function returns a new function that behaves exactly like |
| 26 | * exceptions on error, but that don't interrupt the user script. | 27 | * the function it receives, but the new function catches exceptions thrown |
| 28 | * by "try" functions and returns nil followed by the error message instead. | ||
| 29 | * | ||
| 30 | * With these three functions, it's easy to write functions that throw | ||
| 31 | * exceptions on error, but that don't interrupt the user script. | ||
| 27 | \*=========================================================================*/ | 32 | \*=========================================================================*/ |
| 28 | 33 | ||
| 29 | #include "lua.h" | 34 | #include "lua.h" |
