summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordaurnimator <quae@daurnimator.com>2017-05-12 14:52:14 +1000
committerdaurnimator <quae@daurnimator.com>2017-05-15 18:56:25 +1000
commit4a0aa6eecf10432453c22031c247cf24819f1040 (patch)
tree542bf773168d6af2069a91125447801a5576d2c6
parent424a3604dd90a40773e3434450bb5cb685962926 (diff)
downloadfengari-4a0aa6eecf10432453c22031c247cf24819f1040.tar.gz
fengari-4a0aa6eecf10432453c22031c247cf24819f1040.tar.bz2
fengari-4a0aa6eecf10432453c22031c247cf24819f1040.zip
Add facility for a user provided (state-global) native error handler
-rw-r--r--README.md6
-rw-r--r--src/lapi.js7
-rw-r--r--src/ldo.js26
-rw-r--r--src/lstate.js1
-rw-r--r--src/lua.js1
-rw-r--r--tests/lapi.js40
6 files changed, 75 insertions, 6 deletions
diff --git a/README.md b/README.md
index a41b94b..0fbfc4e 100644
--- a/README.md
+++ b/README.md
@@ -106,6 +106,12 @@ Alias for `lua_pushcfunction`.
Alias for `lua_pushcclosure`.
+### `lua_atnativeerror(L, func)`
+
+Sets a function to be called if a native JavaScript error is thrown across a lua pcall.
+The function will be run as if it were a message handler (see https://www.lua.org/manual/5.3/manual.html#2.3).
+
+
### `b = lua_isproxy(p, L)`
Returns a boolean `b` indicating whether `p` is a proxy (See `lua_toproxy`).
diff --git a/src/lapi.js b/src/lapi.js
index f56fc81..c0e619b 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -36,6 +36,12 @@ const lua_atpanic = function(L, panicf) {
return old;
};
+const lua_atnativeerror = function(L, errorf) {
+ let old = L.l_G.atnativeerror;
+ L.l_G.atnativeerror = errorf;
+ return old;
+};
+
// Return value for idx on stack
const index2addr = function(L, idx) {
let ci = L.ci;
@@ -1104,6 +1110,7 @@ module.exports.index2addr_ = index2addr_;
module.exports.lua_absindex = lua_absindex;
module.exports.lua_arith = lua_arith;
module.exports.lua_atpanic = lua_atpanic;
+module.exports.lua_atnativeerror = lua_atnativeerror;
module.exports.lua_call = lua_call;
module.exports.lua_callk = lua_callk;
module.exports.lua_checkstack = lua_checkstack;
diff --git a/src/ldo.js b/src/ldo.js
index bb34216..c4619e5 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -273,12 +273,26 @@ const luaD_rawrunprotected = function(L, f, ud) {
} catch (e) {
if (lj.status === TS.LUA_OK) {
/* error was not thrown via luaD_throw, i.e. it is a JS error */
- lj.status = -1;
- /* run error handler (if possible) with error object as light userdata */
- try {
- lapi.lua_pushlightuserdata(L, e);
- ldebug.luaG_errormsg(L);
- } catch (e) {}
+ /* run user error handler (if it exists) */
+ let atnativeerror = L.l_G.atnativeerror;
+ if (atnativeerror) {
+ try {
+ lj.status = TS.LUA_OK;
+
+ lapi.lua_pushcfunction(L, atnativeerror);
+ lapi.lua_pushlightuserdata(L, e);
+ luaD_callnoyield(L, L.top - 2, 1);
+
+ lj.status = TS.LUA_ERRRUN;
+ } catch(e2) {
+ if (lj.status === TS.LUA_OK) {
+ /* also failed */
+ lj.status = -1;
+ }
+ }
+ } else {
+ lj.status = -1;
+ }
}
}
diff --git a/src/lstate.js b/src/lstate.js
index 7d7ff80..5a65c12 100644
--- a/src/lstate.js
+++ b/src/lstate.js
@@ -66,6 +66,7 @@ class global_State {
this.mainthread = L;
this.l_registry = new lobject.TValue(CT.LUA_TNIL, null);
this.panic = null;
+ this.atnativeerror = null;
this.version = null;
this.tmname = new Array(ltm.TMS.TM_N);
this.mt = new Array(LUA_NUMTAGS);
diff --git a/src/lua.js b/src/lua.js
index 135dadb..94eff3d 100644
--- a/src/lua.js
+++ b/src/lua.js
@@ -95,6 +95,7 @@ module.exports.LUA_DIRSEP = defs.LUA_DIRSEP;
module.exports.lua_absindex = lapi.lua_absindex;
module.exports.lua_arith = lapi.lua_arith;
module.exports.lua_atpanic = lapi.lua_atpanic;
+module.exports.lua_atnativeerror = lapi.lua_atnativeerror;
module.exports.lua_call = lapi.lua_call;
module.exports.lua_callk = lapi.lua_callk;
module.exports.lua_checkstack = lapi.lua_checkstack;
diff --git a/tests/lapi.js b/tests/lapi.js
index b739860..1dbdd5c 100644
--- a/tests/lapi.js
+++ b/tests/lapi.js
@@ -481,3 +481,43 @@ test('lua_settable, lua_gettable', function (t) {
"Correct element(s) on the stack"
);
});
+
+test('lua_atnativeerror', function(t) {
+ t.plan(7);
+
+ let L = lauxlib.luaL_newstate();
+ let errob = {};
+
+ lua.lua_pushcfunction(L, function(L) {
+ throw errob;
+ });
+ t.strictEqual(lua.lua_pcall(L, 0, 0, 0), -1, "without a native error handler pcall should be -1");
+ lua.lua_pop(L, 1);
+
+
+ lua.lua_atnativeerror(L, function(L) {
+ let e = lua.lua_touserdata(L, 1);
+ t.strictEqual(e, errob);
+ lua.lua_pushstring(L, lua.to_luastring("runtime error!"));
+ return 1;
+ });
+ lua.lua_pushcfunction(L, function(L) {
+ throw errob;
+ });
+ t.strictEqual(lua.lua_pcall(L, 0, 0, 0), lua.LUA_ERRRUN, "should return lua.LUA_ERRRUN");
+ t.strictEqual(lua.lua_tojsstring(L, -1), "runtime error!");
+ lua.lua_pop(L, 1);
+
+
+ lua.lua_atnativeerror(L, function(L) {
+ let e = lua.lua_touserdata(L, 1);
+ t.strictEqual(e, errob);
+ lauxlib.luaL_error(L, lua.to_luastring("runtime error!"));
+ });
+ lua.lua_pushcfunction(L, function(L) {
+ throw errob;
+ });
+ t.strictEqual(lua.lua_pcall(L, 0, 0, 0), lua.LUA_ERRRUN, "luaL_error from a native error handler should result in LUA_ERRRUN");
+ t.strictEqual(lua.lua_tojsstring(L, -1), "runtime error!");
+ lua.lua_pop(L, 1);
+});