diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lapi.js | 10 | ||||
-rw-r--r-- | src/ldblib.js | 60 | ||||
-rw-r--r-- | src/ldebug.js | 68 |
3 files changed, 133 insertions, 5 deletions
diff --git a/src/lapi.js b/src/lapi.js index 3fbcee9..00db461 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -736,6 +736,14 @@ const lua_isuserdata = function(L, idx) { return o.ttisfulluserdata(o) || o.ttislightuserdata(); }; +const lua_isthread = function(L, idx) { + return lua_type(L, idx) === CT.LUA_TTHREAD; +}; + +const lua_isfunction = function(L, idx) { + return lua_type(L, idx) === CT.LUA_TFUNCTION; +}; + const lua_rawequal = function(L, index1, index2) { let o1 = index2addr(L, index1); let o2 = index2addr(L, index2); @@ -927,6 +935,7 @@ module.exports.lua_getmetatable = lua_getmetatable; module.exports.lua_gettable = lua_gettable; module.exports.lua_gettop = lua_gettop; module.exports.lua_insert = lua_insert; +module.exports.lua_isfunction = lua_isfunction; module.exports.lua_isinteger = lua_isinteger; module.exports.lua_isnil = lua_isnil; module.exports.lua_isnone = lua_isnone; @@ -934,6 +943,7 @@ module.exports.lua_isnoneornil = lua_isnoneornil; module.exports.lua_isnumber = lua_isnumber; module.exports.lua_isstring = lua_isstring; module.exports.lua_istable = lua_istable; +module.exports.lua_isthread = lua_isthread; module.exports.lua_isuserdata = lua_isuserdata; module.exports.lua_len = lua_len; module.exports.lua_load = lua_load; diff --git a/src/ldblib.js b/src/ldblib.js index 39b9574..efab872 100644 --- a/src/ldblib.js +++ b/src/ldblib.js @@ -5,9 +5,69 @@ const assert = require('assert'); const lua = require('./lua.js'); const lapi = require('./lapi.js'); const lauxlib = require('./lauxlib.js'); +const ldebug = require('./ldebug.js'); +/* +** If L1 != L, L1 can be in any state, and therefore there are no +** guarantees about its stack space; any push in L1 must be +** checked. +*/ +const checkstack = function(L, L1, n) { + if (L !== L1 && !lapi.lua_checkstack(L1, n)) + lauxlib.luaL_error(L, "stack overflow"); +}; + +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ +const getthread = function(L) { + if (lapi.lua_isthread(L, 1)) { + return { + arg: 1, + thread: lapi.lua_tothread(L, 1) + }; + } else { + return { + arg: 0, + thread: L + }; /* function will operate over current thread */ + } +}; + +const db_getlocal = function(L) { + let thread = getthread(L); + let L1 = thread.thread; + let arg = thread.arg; + let ar = new lua.lua_Debug(); + let nvar = lauxlib.luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lapi.lua_isfunction(L, arg + 1)) { + lapi.lua_pushvalue(L, arg + 1); /* push function */ + lapi.lua_pushstring(L, ldebug.lua_getlocal(L, null, nvar)); /* push local name */ + return 1; /* return only name (there is no value) */ + } else { /* stack-level argument */ + let level = lauxlib.luaL_checkinteger(L, arg + 1); + if (!ldebug.lua_getstack(L1, level, ar)) /* out of range? */ + return lauxlib.luaL_argerror(L, arg+1, lapi.to_luastring("level out of range")); + checkstack(L, L1, 1); + let name = ldebug.lua_getlocal(L1, ar, nvar); + if (name) { + lapi.lua_xmove(L1, L, 1); /* move local value */ + lapi.lua_pushstring(L, name.value); /* push name */ + lapi.lua_rotate(L, -2, 1); /* re-order */ + return 2; + } + else { + lapi.lua_pushnil(L); /* no name (nor value) */ + return 1; + } + } +}; const dblib = { + "getlocal": db_getlocal }; // Only with Node diff --git a/src/ldebug.js b/src/ldebug.js index 3d66d85..5a5fc34 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -59,6 +59,63 @@ const upvalname = function(p, uv) { return s; }; +const findvararg = function(ci, n, pos) { + let nparams = ci.func.p.numparams; + if (n >= ci.u.l.base - ci.funcOff - nparams) + return null; /* no such vararg */ + else { + return { + pos: ci.funcOff + nparams + n, + name: lua.to_luastring("(*vararg)") /* generic name for any vararg */ + }; + } +}; + +const findlocal = function(L, ci, n) { + let base, name = null; + + if (ci.callstatus & lstate.CIST_LUA) { + if (n < 0) /* access to vararg values? */ + return findvararg(ci, -n); + else { + base = ci.u.l.base; + name = lfunc.luaF_getlocalname(ci.func.p, n, ci.pcOff); + } + } else + base = ci.funcOff + 1; + + if (name === null) { /* no 'standard' name? */ + let limit = ci === L.ci ? L.top : ci.next.func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + name = lua.to_luastring("(*temporary)"); /* generic name for any valid slot */ + else + return null; /* no name */ + } + return { + pos: base + (n - 1), + name: name + }; +}; + +const lua_getlocal = function(L, ar, n) { + let name; + swapextra(L); + if (ar === null) { /* information about non-active function? */ + if (!L.stack[L.top - 1].ttisLclosure()) /* not a Lua function? */ + name = null; + else /* consider live variables at function start (parameters) */ + name = lfunc.luaF_getlocalname(L.stack[L.top - 1].value.p, n, 0); + } else { /* active function; get information through 'ar' */ + let local = findlocal(L, ar.i_ci, n); + name = local.name; + let pos = L.stack[local.pos]; + if (name) + L.stack[L.top++] = new TValue(pos.type, pos.value); + } + swapextra(L); + return name; +}; + const funcinfo = function(ar, cl) { if (cl === null || cl.type === CT.LUA_TCCL) { ar.source = lua.to_luastring("=[JS]"); @@ -503,13 +560,14 @@ const luaG_tointerror = function(L, p1, p2) { luaG_runerror(L, lua.to_luastring(`number${lobject.jsstring(varinfo(L, p2))} has no integer representation`)); }; -module.exports.lua_getstack = lua_getstack; -module.exports.lua_getinfo = lua_getinfo; -module.exports.luaG_errormsg = luaG_errormsg; module.exports.luaG_addinfo = luaG_addinfo; -module.exports.luaG_runerror = luaG_runerror; -module.exports.luaG_typeerror = luaG_typeerror; module.exports.luaG_concaterror = luaG_concaterror; +module.exports.luaG_errormsg = luaG_errormsg; module.exports.luaG_opinterror = luaG_opinterror; module.exports.luaG_ordererror = luaG_ordererror; +module.exports.luaG_runerror = luaG_runerror; module.exports.luaG_tointerror = luaG_tointerror; +module.exports.luaG_typeerror = luaG_typeerror; +module.exports.lua_getinfo = lua_getinfo; +module.exports.lua_getlocal = lua_getlocal; +module.exports.lua_getstack = lua_getstack; |