diff options
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | src/lapi.js | 21 | ||||
-rw-r--r-- | src/ldblib.js | 40 | ||||
-rw-r--r-- | src/ldebug.js | 15 | ||||
-rw-r--r-- | tests/ldblib.js | 66 |
5 files changed, 145 insertions, 6 deletions
@@ -33,7 +33,6 @@ - [ ] lua_getinfo - [ ] lua_getstack - [ ] lua_getupvalue - - [ ] lua_getuservalue - [ ] lua_isboolean - [ ] lua_iscfunction - [ ] lua_islightuserdata @@ -48,8 +47,6 @@ - [ ] lua_register - [ ] lua_setallocf - [ ] lua_sethook - - [ ] lua_setlocal - - [ ] lua_setuservalue - [ ] lua_tocfunction - [ ] lua_upvaluejoin - [ ] Auxiliary library @@ -91,14 +88,14 @@ - [x] debug.getmetatable - [x] debug.getregistry - [x] debug.getupvalue + - [x] debug.getuservalue + - [x] debug.setlocal - [x] debug.setmetatable - [x] debug.setupvalue + - [x] debug.setuservalue - [x] debug.traceback - [ ] debug.gethook - - [ ] debug.getuservalue - [ ] debug.sethook - - [ ] debug.setlocal - - [ ] debug.setuservalue - [ ] debug.upvalueid - [ ] debug.upvaluejoin - [ ] Run [Lua test suite](https://github.com/lua/tests) diff --git a/src/lapi.js b/src/lapi.js index 048a6b7..b41cfbe 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -537,6 +537,15 @@ const lua_getmetatable = function(L, objindex) { return res; }; +const lua_getuservalue = function(L, idx) { + let o = index2addr(L, idx); + assert(L, o.ttisfulluserdata(), "full userdata expected"); + L.stack[L.top].type = o.type; + L.stack[L.top++].value = o.value; + assert(L.top <= L.ci.top, "stack overflow"); + return L.stack[L.top - 1].ttnov(); +}; + const lua_gettable = function(L, idx) { let t = index2addr(L, idx); lvm.gettable(L, t, L.stack[L.top - 1], L.top - 1); @@ -793,6 +802,16 @@ const lua_status = function(L) { return L.status; }; +const lua_setuservalue = function(L, idx) { + assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + let o = index2addr(L, idx); + assert(L, o.ttisfulluserdata(), "full userdata expected"); + L.stack[L.top - 1].type = o.type; + L.stack[L.top - 1].value = o.value; + L.top--; +}; + + const lua_callk = function(L, nargs, nresults, ctx, k) { assert(k === null || !(L.ci.callstatus & lstate.CIST_LUA), "cannot use continuations inside hooks"); assert(nargs + 1 < L.top - L.ci.funcOff, "not enough elements in the stack"); @@ -972,6 +991,7 @@ module.exports.lua_getmetatable = lua_getmetatable; module.exports.lua_gettable = lua_gettable; module.exports.lua_gettop = lua_gettop; module.exports.lua_getupvalue = lua_getupvalue; +module.exports.lua_getuservalue = lua_getuservalue; module.exports.lua_insert = lua_insert; module.exports.lua_isfunction = lua_isfunction; module.exports.lua_isinteger = lua_isinteger; @@ -1023,6 +1043,7 @@ module.exports.lua_setmetatable = lua_setmetatable; module.exports.lua_settable = lua_settable; module.exports.lua_settop = lua_settop; module.exports.lua_setupvalue = lua_setupvalue; +module.exports.lua_setuservalue = lua_setuservalue; module.exports.lua_status = lua_status; module.exports.lua_stringtonumber = lua_stringtonumber; module.exports.lua_toboolean = lua_toboolean; diff --git a/src/ldblib.js b/src/ldblib.js index d3e3c7c..9fc6ce6 100644 --- a/src/ldblib.js +++ b/src/ldblib.js @@ -39,6 +39,23 @@ const db_setmetatable = function(L) { return 1; /* return 1st argument */ }; +const db_getuservalue = function(L) { + if (lapi.lua_type(L, 1) !== lua.CT.LUA_TUSERDATA) + lapi.lua_pushnil(L); + else + lapi.lua_getuservalue(L, 1); + return 1; +}; + + +const db_setuservalue = function(L) { + lauxlib.luaL_checktype(L, 1, lua.CT.LUA_TUSERDATA); + lauxlib.luaL_checkany(L, 2); + lapi.lua_settop(L, 2); + lapi.lua_setuservalue(L, 1); + return 1; +}; + /* ** Auxiliary function used by several library functions: check for ** an optional thread as function's first argument and set 'arg' with @@ -177,6 +194,26 @@ const db_getlocal = function(L) { } }; +const db_setlocal = function(L) { + let thread = getthread(L); + let L1 = thread.thread; + let arg = thread.arg; + let ar = new lua.lua_Debug(); + let level = lauxlib.luaL_checkinteger(L, arg + 1); + let nvar = lauxlib.luaL_checkinteger(L, arg + 2); + if (!ldebug.lua_getstack(L1, level, ar)) /* out of range? */ + return lauxlib.luaL_argerror(L, arg + 1, "level out of range"); + lauxlib.luaL_checkany(L, arg + 3); + lapi.lua_settop(L, arg + 3); + checkstack(L, L1, 1); + lapi.lua_xmove(L, L1, 1); + let name = ldebug.lua_setlocal(L1, ar, nvar); + if (name === null) + lapi.lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lapi.lua_pushstring(L, name.value); + return 1; +}; + /* ** get (if 'get' is true) or set an upvalue from a closure */ @@ -238,8 +275,11 @@ const dblib = { "getmetatable": db_getmetatable, "getregistry": db_getregistry, "getupvalue": db_getupvalue, + "getuservalue": db_getuservalue, + "setlocal": db_setlocal, "setmetatable": db_setmetatable, "setupvalue": db_setupvalue, + "setuservalue": db_setuservalue, "traceback": db_traceback, "upvalueid": db_upvalueid }; diff --git a/src/ldebug.js b/src/ldebug.js index 713a0fb..44410a6 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -116,6 +116,20 @@ const lua_getlocal = function(L, ar, n) { return name; }; +const lua_setlocal = function(L, ar, n) { + swapextra(L); + let local = findlocal(L, ar.i_ci, n); + let name = local.name; + let pos = local.pos; + if (name) { + L.stack[pos].type = L.stack[L.top - 1].type; + L.stack[pos].value = L.stack[L.top - 1].value; + L.top--; /* pop value */ + } + swapextra(L); + return name; +}; + const funcinfo = function(ar, cl) { if (cl === null || cl.type === CT.LUA_TCCL) { ar.source = lua.to_luastring("=[JS]"); @@ -574,3 +588,4 @@ module.exports.luaG_typeerror = luaG_typeerror; module.exports.lua_getinfo = lua_getinfo; module.exports.lua_getlocal = lua_getlocal; module.exports.lua_getstack = lua_getstack; +module.exports.lua_setlocal = lua_setlocal; diff --git a/tests/ldblib.js b/tests/ldblib.js index a770c76..30a3eb6 100644 --- a/tests/ldblib.js +++ b/tests/ldblib.js @@ -54,6 +54,72 @@ test('debug.getlocal', function (t) { }); +test('debug.setlocal', function (t) { + let luaCode = ` + local alocal = "alocal" + local another = "another" + + local l = function() + local infunction = "infunction" + local anotherin = "anotherin" + + debug.setlocal(2, 1, 1) + debug.setlocal(2, 2, 2) + debug.setlocal(1, 1, 3) + debug.setlocal(1, 2, 4) + + return infunction, anotherin + end + + local a, b = l() + + return alocal, another, a, b + `, L; + + t.plan(6); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + linit.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lapi.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + + t.strictEqual( + lapi.lua_tointeger(L, -4), + 1, + "Correct element(s) on the stack" + ); + + t.strictEqual( + lapi.lua_tointeger(L, -3), + 2, + "Correct element(s) on the stack" + ); + + t.strictEqual( + lapi.lua_tointeger(L, -2), + 3, + "Correct element(s) on the stack" + ); + + t.strictEqual( + lapi.lua_tointeger(L, -1), + 4, + "Correct element(s) on the stack" + ); + +}); + test('debug.upvalueid', function (t) { let luaCode = ` local upvalue = "upvalue" |