This patch improves Lua's support for custom error objects. Changes:
* Uncaught error handler in standard Lua interpreter calls tostring()
on error object. This ensures that a call stack is displayed even
for non-string error objects. It also allows use of the __tostring
hook for human-readable error messages.
* Base library error() will set the _WHERE field of any table error
object to the value of luaL_where(). Uncaught error handler in the
standard Lua interpreter will use this, so that for custom error
object the error location is shown in the call stack. This is a bit
of a hack and implies that any thrown table should be a unique
instance of the error (since it will be mutated). Rather than this
scheme, the idea solution would be to have the Lua core manage the
location separate from the error object.
See "Exception Patterns in Lua"
(http://memebeam.org/john/lua/exception_patterns.odp) for more information.
diff -urN lua-5.1.1/src/lbaselib.c lua-5.1.1_custom_errors/src/lbaselib.c
--- lua-5.1.1/src/lbaselib.c 2006年06月02日 11:34:00.000000000 -0400
+++ lua-5.1.1_custom_errors/src/lbaselib.c 2006年09月06日 10:29:52.000000000 -0400
@@ -81,10 +81,14 @@
static int luaB_error (lua_State *L) {
int level = luaL_optint(L, 2, 1);
lua_settop(L, 1);
- if (lua_isstring(L, 1) && level> 0) { /* add extra information? */
+ if ((lua_isstring(L, 1) || lua_istable(L, 1)) && level> 0) { /* add extra information? */
luaL_where(L, level);
- lua_pushvalue(L, 1);
- lua_concat(L, 2);
+ if (lua_isstring(L, 1)) {
+ lua_pushvalue(L, 1);
+ lua_concat(L, 2);
+ }
+ else
+ lua_setfield(L, 1, "_WHERE");
}
return lua_error(L);
}
diff -urN lua-5.1.1/src/lua.c lua-5.1.1_custom_errors/src/lua.c
--- lua-5.1.1/src/lua.c 2006年06月02日 11:34:00.000000000 -0400
+++ lua-5.1.1_custom_errors/src/lua.c 2006年09月06日 11:26:15.000000000 -0400
@@ -84,7 +84,24 @@
lua_pop(L, 2);
return 1;
}
- lua_pushvalue(L, 1); /* pass error message */
+ lua_getglobal(L, "tostring");
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 1);
+ lua_pushvalue(L, 1); /* pass error object */
+ }
+ else {
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 1); /* call tostring on error object */
+ }
+ if (lua_istable(L, 1)) { /* use _WHERE on table error if it exists */
+ lua_getfield(L, 1, "_WHERE");
+ if (lua_isstring(L, -1)) {
+ lua_insert(L, -2);
+ lua_concat(L, 2);
+ }
+ else
+ lua_pop(L, 1);
+ }
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
return 1;