diff options
Diffstat (limited to 'src/ltablib.js')
-rw-r--r-- | src/ltablib.js | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/ltablib.js b/src/ltablib.js new file mode 100644 index 0000000..8e1f758 --- /dev/null +++ b/src/ltablib.js @@ -0,0 +1,92 @@ +/* jshint esversion: 6 */ +"use strict"; + +const assert = require('assert'); + +const lua = require('./lua.js'); +const lapi = require('./lapi.js'); +const lauxlib = require('./lauxlib.js'); +const lstate = require('./lstate.js'); +const ldo = require('./ldo.js'); +const ldebug = require('./ldebug.js'); +const CT = lua.constant_types; +const TS = lua.thread_status; + + +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +const TAB_R = 1; /* read */ +const TAB_W = 2; /* write */ +const TAB_L = 4; /* length */ +const TAB_RW = (TAB_R | TAB_W); /* read/write */ + +const checkfield = function(L, key, n) { + lapi.lua_pushstring(L, key); + return lapi.lua_rawget(L, -n) !== CT.LUA_TNIL; +}; + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +const checktab = function(L, arg, what) { + if (lapi.lua_type(L, arg) !== CT.LUA_TTABLE) { /* is it not a table? */ + let n = 1; + if (lapi.lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lapi.lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + lauxlib.luaL_checktype(L, arg, CT.LUA_TTABLE); /* force an error */ + } +}; + +const aux_getn = function(L, n, w) { + checktab(L, n, w | TAB_L); + lauxlib.luaL_len(L, n); +}; + +const addfield = function(L, b, i) { + lapi.lua_geti(L, 1, i); + if (!lapi.lua_isstring(L, -1)) + lauxlib.luaL_error(L, `invalid value (${lauxlib.luaL_typename(L, -1)}) at index ${i} in table for 'concat'`); + + lauxlib.luaL_addvalue(b); +}; + +const tconcat = function(L) { + let last = aux_getn(L, 1, TAB_R); + let sep = lauxlib.luaL_optlstring(L, 2, ""); + let i = lauxlib.luaL_optinteger(L, 3, 1); + last = lauxlib.luaL_optinteger(L, 4, last); + + let b = new lauxlib.luaL_Buffer(); + lauxlib.luaL_buffinit(L, b); + + for (; i < last; i++) { + addfield(L, b, i); + lauxlib.luaL_addlstring(b, sep); + } + + if (i === last) + addfield(L, b, i); + + lauxlib.luaL_pushresult(b); + + return 1; +}; + +const tab_funcs = { + "concat": tconcat +}; + +const luaopen_table = function(L) { + lauxlib.luaL_newlib(L, tab_funcs); + return 1; +}; + +module.exports.luaopen_table = luaopen_table;
\ No newline at end of file |