From 2f9fe378bc341921e1ae259a2fec049663100738 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Fri, 24 Feb 2017 11:38:23 +0100 Subject: table.move --- .travis.yml | 5 ++++- README.md | 6 +++--- src/lapi.js | 23 +++++++++++++++++++++++ src/ltablib.js | 37 +++++++++++++++++++++++++++++++++++++ src/lua.js | 51 +++++++++++++++++++++++++++++---------------------- tests/ltablib.js | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index 09bac7d..971b027 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,4 +12,7 @@ install: - $NPM i script: - - $NPM t \ No newline at end of file + - $NPM t + +notifications: + email: false \ No newline at end of file diff --git a/README.md b/README.md index 00ceffa..41ae840 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ - [x] lua_call - [x] lua_callk - [x] lua_checkstack + - [x] lua_compare - [x] lua_concat - [x] lua_copy - [x] lua_createtable @@ -36,6 +37,7 @@ - [x] lua_gettable - [x] lua_gettop - [x] lua_insert + - [x] lua_isnoneornil - [x] lua_isstring - [x] lua_istable - [x] lua_isyieldable @@ -93,7 +95,6 @@ - [x] lua_yieldk - [ ] lua_arith - [ ] lua_close - - [ ] lua_compare - [ ] lua_dump - [x] lua_gc (unavailable) - [x] lua_getallocf (unavailable) @@ -114,7 +115,6 @@ - [ ] lua_islightuserdata - [ ] lua_isnil - [ ] lua_isnone - - [ ] lua_isnoneornil - [ ] lua_isnumber - [ ] lua_isthread - [ ] lua_isuserdata @@ -208,10 +208,10 @@ - [ ] Table - [x] table.concat - [x] table.insert + - [x] table.move - [x] table.pack - [x] table.remove - [x] table.unpack - - [ ] table.move - [ ] table.sort - [ ] Run [Lua test suite](https://github.com/lua/tests) - [ ] DOM API binding diff --git a/src/lapi.js b/src/lapi.js index f34216b..488fb58 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -538,6 +538,23 @@ const lua_topointer = function(L, idx) { } }; +const lua_compare = function(L, index1, index2, op) { + let i = 0; + let o1 = index2addr(L, index1); + let o2 = index2addr(L, index1); + + if (!o1.ttisnil() && !o2.ttisnil()) { + switch (op) { + case lua.LUA_OPEQ: i = lvm.luaV_equalobj(L, o1, o2); break; + case lua.LUA_OPLT: i = lvm.luaV_lessthan(L, o1, o2); break; + case lua.LUA_OPLE: i = lvm.luaV_lessequal(L, o1, o2); break; + default: assert(false, "invalid option"); + } + } + + return i; +}; + const lua_stringtonumber = function(L, s) { let number = parseFloat(s); L.stack[L.top++] = new TValue(number % 1 !== 0 ? CT.LUA_TNUMFLT : CT.LUA_TNUMINT, number); @@ -568,6 +585,10 @@ const lua_typename = function(L, t) { return ltm.ttypename(t); }; +const lua_isnoneornil = function(L, n) { + return lua_type(L, n) <= 0; +} + const lua_istable = function(L, idx) { return index2addr(L, idx).ttistable(); }; @@ -741,6 +762,7 @@ module.exports.lua_atpanic = lua_atpanic; module.exports.lua_call = lua_call; module.exports.lua_callk = lua_callk; module.exports.lua_checkstack = lua_checkstack; +module.exports.lua_compare = lua_compare; module.exports.lua_concat = lua_concat; module.exports.lua_copy = lua_copy; module.exports.lua_createtable = lua_createtable; @@ -755,6 +777,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_isnoneornil = lua_isnoneornil; module.exports.lua_isstring = lua_isstring; module.exports.lua_istable = lua_istable; module.exports.lua_len = lua_len; diff --git a/src/ltablib.js b/src/ltablib.js index 6255761..97ecd65 100644 --- a/src/ltablib.js +++ b/src/ltablib.js @@ -9,6 +9,7 @@ const lauxlib = require('./lauxlib.js'); const lstate = require('./lstate.js'); const ldo = require('./ldo.js'); const ldebug = require('./ldebug.js'); +const llimit = require('./llimit.js'); const CT = lua.constant_types; const TS = lua.thread_status; @@ -98,6 +99,41 @@ const tremove = function(L) { return 1; }; +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +const tmove = function(L) { + let f = lauxlib.luaL_checkinteger(L, 2); + let e = lauxlib.luaL_checkinteger(L, 3); + let t = lauxlib.luaL_checkinteger(L, 4); + let tt = !lapi.lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lauxlib.luaL_argcheck(L, f > 0 || e < llimit.LUA_MAXINTEGER + f, 3, "too many elements to move"); + let n = e - f + 1; /* number of elements to move */ + lauxlib.luaL_argcheck(L, t <= llimit.LUA_MAXINTEGER - n + 1, 4, "destination wrap around"); + + if (t > e || t <= f || (tt !== 1 && lapi.lua_compare(L, 1, tt, lua.LUA_OPEQ) !== 1)) { + for (let i = 0; i < n; i++) { + lapi.lua_geti(L, 1, f + i); + lapi.lua_seti(L, tt, t + i); + } + } else { + for (let i = n - 1; i >= 0; i--) { + lapi.lua_geti(L, 1, f + i); + lapi.lua_seti(L, tt, t + i); + } + } + } + + lapi.lua_pushvalue(L, tt); /* return destination table */ + return 1; +}; + const tconcat = function(L) { let last = aux_getn(L, 1, TAB_R); let sep = lauxlib.luaL_optlstring(L, 2, ""); @@ -147,6 +183,7 @@ const unpack = function(L) { const tab_funcs = { "concat": tconcat, "insert": tinsert, + "move": tmove, "pack": pack, "remove": tremove, "unpack": unpack diff --git a/src/lua.js b/src/lua.js index 358be64..c7d1fd7 100644 --- a/src/lua.js +++ b/src/lua.js @@ -62,6 +62,10 @@ constant_types.LUA_TLCL = constant_types.LUA_TFUNCTION | (0 << 4); /* Lua closu constant_types.LUA_TLCF = constant_types.LUA_TFUNCTION | (1 << 4); /* light C function */ constant_types.LUA_TCCL = constant_types.LUA_TFUNCTION | (2 << 4); /* C closure */ +const LUA_OPEQ = 0; +const LUA_OPLT = 1; +const LUA_OPLE = 2; + const LUA_NUMTAGS = 9; const LUA_MINSTACK = 20; @@ -102,33 +106,36 @@ class lua_Debug { } -module.exports.lua_Debug = lua_Debug; -module.exports.constant_types = constant_types; -module.exports.thread_status = thread_status; -module.exports.LUA_MULTRET = -1; -module.exports.print_version = print_version; -module.exports.LUA_VERSION_MAJOR = LUA_VERSION_MAJOR; -module.exports.LUA_VERSION_MINOR = LUA_VERSION_MINOR; -module.exports.LUA_VERSION_NUM = LUA_VERSION_NUM; -module.exports.LUA_VERSION_RELEASE = LUA_VERSION_RELEASE; -module.exports.LUA_VERSION = LUA_VERSION; -module.exports.LUA_RELEASE = LUA_RELEASE; -module.exports.LUA_COPYRIGHT = LUA_COPYRIGHT; -module.exports.LUA_AUTHORS = LUA_AUTHORS; +module.exports.FENGARI_AUTHORS = FENGARI_AUTHORS; +module.exports.FENGARI_COPYRIGHT = FENGARI_COPYRIGHT; +module.exports.FENGARI_RELEASE = FENGARI_RELEASE; +module.exports.FENGARI_VERSION = FENGARI_VERSION; module.exports.FENGARI_VERSION_MAJOR = FENGARI_VERSION_MAJOR; module.exports.FENGARI_VERSION_MINOR = FENGARI_VERSION_MINOR; module.exports.FENGARI_VERSION_NUM = FENGARI_VERSION_NUM; module.exports.FENGARI_VERSION_RELEASE = FENGARI_VERSION_RELEASE; -module.exports.FENGARI_VERSION = FENGARI_VERSION; -module.exports.FENGARI_RELEASE = FENGARI_RELEASE; -module.exports.FENGARI_COPYRIGHT = FENGARI_COPYRIGHT; -module.exports.FENGARI_AUTHORS = FENGARI_AUTHORS; -module.exports.LUA_INIT_VAR = LUA_INIT_VAR; +module.exports.LUA_AUTHORS = LUA_AUTHORS; +module.exports.LUA_COPYRIGHT = LUA_COPYRIGHT; module.exports.LUA_INITVARVERSION = LUA_INITVARVERSION; -module.exports.LUA_NUMTAGS = LUA_NUMTAGS; +module.exports.LUA_INIT_VAR = LUA_INIT_VAR; module.exports.LUA_MINSTACK = LUA_MINSTACK; -module.exports.LUA_RIDX_MAINTHREAD = LUA_RIDX_MAINTHREAD; +module.exports.LUA_MULTRET = -1; +module.exports.LUA_NUMTAGS = LUA_NUMTAGS; +module.exports.LUA_OPEQ = LUA_OPEQ; +module.exports.LUA_OPLE = LUA_OPLE; +module.exports.LUA_OPLT = LUA_OPLT; +module.exports.LUA_REGISTRYINDEX = LUA_REGISTRYINDEX; +module.exports.LUA_RELEASE = LUA_RELEASE; module.exports.LUA_RIDX_GLOBALS = LUA_RIDX_GLOBALS; module.exports.LUA_RIDX_LAST = LUA_RIDX_LAST; -module.exports.LUA_REGISTRYINDEX = LUA_REGISTRYINDEX; -module.exports.lua_upvalueindex = lua_upvalueindex; \ No newline at end of file +module.exports.LUA_RIDX_MAINTHREAD = LUA_RIDX_MAINTHREAD; +module.exports.LUA_VERSION = LUA_VERSION; +module.exports.LUA_VERSION_MAJOR = LUA_VERSION_MAJOR; +module.exports.LUA_VERSION_MINOR = LUA_VERSION_MINOR; +module.exports.LUA_VERSION_NUM = LUA_VERSION_NUM; +module.exports.LUA_VERSION_RELEASE = LUA_VERSION_RELEASE; +module.exports.constant_types = constant_types; +module.exports.lua_Debug = lua_Debug; +module.exports.lua_upvalueindex = lua_upvalueindex; +module.exports.print_version = print_version; +module.exports.thread_status = thread_status; \ No newline at end of file diff --git a/tests/ltablib.js b/tests/ltablib.js index 9a18ff6..990b1f8 100644 --- a/tests/ltablib.js +++ b/tests/ltablib.js @@ -184,4 +184,37 @@ test('table.remove', function (t) { [1, 2, 3, 4, null, null], "Correct element(s) on the stack" ); +}); + + +test('table.move', function (t) { + let luaCode = ` + local t1 = {3, 4, 5} + local t2 = {1, 2, nil, nil, nil, 6} + return table.move(t1, 1, #t1, 3, t2) + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + let bc = toByteCode(luaCode).dataView; + + L = lauxlib.luaL_newstate(); + + linit.luaL_openlibs(L); + + lapi.lua_load(L, bc, "test-table.insert"); + + lapi.lua_call(L, 0, -1); + + }, "JS Lua program ran without error"); + + t.deepEqual( + [...lapi.lua_topointer(L, -1).entries()] + .filter(e => typeof e[0] === 'number') + .map(e => e[1].value).sort(), + [1, 2, 3, 4, 5, 6], + "Correct element(s) on the stack" + ); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2