From bd3ffd7282de8236cd4eb2ff2e21bbc10791bfeb Mon Sep 17 00:00:00 2001
From: Benoit Giannangeli <benoit.giannangeli@boursorama.fr>
Date: Fri, 24 Feb 2017 08:13:38 +0100
Subject: table.pack

---
 README.md        | 24 ++++++++++++++++--------
 src/lapi.js      |  8 ++++++++
 src/ltablib.js   | 14 +++++++++++++-
 tests/ltablib.js | 31 +++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index 714c482..aafcec2 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,7 @@
     - [x] lua_isstring
     - [x] lua_istable
     - [x] lua_isyieldable
+    - [x] lua_len
     - [x] lua_load
     - [x] lua_newstate
     - [x] lua_newtable
@@ -66,6 +67,7 @@
     - [x] lua_rotate
     - [x] lua_setfield
     - [x] lua_setglobal
+    - [x] lua_seti
     - [x] lua_setmetatable
     - [x] lua_settable
     - [x] lua_settop
@@ -114,7 +116,6 @@
     - [ ] lua_isnumber
     - [ ] lua_isthread
     - [ ] lua_isuserdata
-    - [ ] lua_len
     - [ ] lua_newuserdata
     - [ ] lua_numbertointeger
     - [ ] lua_pcallk
@@ -128,7 +129,6 @@
     - [ ] lua_replace
     - [ ] lua_setallocf
     - [ ] lua_sethook
-    - [ ] lua_seti
     - [ ] lua_setlocal
     - [ ] lua_setupvalue
     - [ ] lua_setuservalue
@@ -137,8 +137,12 @@
     - [ ] lua_upvalueid
     - [ ] lua_upvaluejoin
 - [ ] Auxiliary library
+    - [x] luaL_addlstring
+    - [x] luaL_addstring
+    - [x] luaL_addvalue
     - [x] luaL_argcheck
     - [x] luaL_argerror
+    - [x] luaL_buffinit
     - [x] luaL_callmeta
     - [x] luaL_checkany
     - [x] luaL_checkinteger
@@ -148,23 +152,21 @@
     - [x] luaL_error
     - [x] luaL_getmetafield
     - [x] luaL_getsubtable
+    - [x] luaL_len
     - [x] luaL_newlib
     - [x] luaL_newstate
     - [x] luaL_openlibs
     - [x] luaL_opt
     - [x] luaL_optinteger
     - [x] luaL_optlstring
+    - [x] luaL_pushresult
     - [x] luaL_requiref
     - [x] luaL_setfuncs
     - [x] luaL_tolstring
     - [x] luaL_typename
     - [x] luaL_where
     - [ ] luaL_addchar
-    - [ ] luaL_addlstring
     - [ ] luaL_addsize
-    - [ ] luaL_addstring
-    - [ ] luaL_addvalue
-    - [ ] luaL_buffinit
     - [ ] luaL_buffinitsize
     - [ ] luaL_checknumber
     - [ ] luaL_checkoption
@@ -177,7 +179,6 @@
     - [ ] luaL_fileresult
     - [ ] luaL_getmetatable
     - [ ] luaL_gsub
-    - [ ] luaL_len
     - [ ] luaL_loadbuffer
     - [ ] luaL_loadbufferx
     - [ ] luaL_loadfile
@@ -189,7 +190,6 @@
     - [ ] luaL_optstring
     - [ ] luaL_prepbuffer
     - [ ] luaL_prepbuffsize
-    - [ ] luaL_pushresult
     - [ ] luaL_pushresultsize
     - [ ] luaL_ref
     - [ ] luaL_setmetatable
@@ -203,6 +203,14 @@
         - [ ] loadfile
         - [ ] load
     - [x] Coroutine
+    - [ ] Table
+        - [x] table.concat
+        - [x] table.pack
+        - [ ] table.insert
+        - [ ] table.move
+        - [ ] table.remove
+        - [ ] table.sort
+        - [ ] table.unpack
 - [ ] Debug (errors)
 - [ ] DOM API binding
 - [ ] Parse Lua
diff --git a/src/lapi.js b/src/lapi.js
index 6316326..f34216b 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -355,6 +355,13 @@ const lua_setfield = function(L, idx, k) {
     auxsetstr(L, index2addr(L, idx), k)
 };
 
+const lua_seti = function(L, idx, n) {
+    assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack");
+    let t = index2addr(L, idx);
+    lvm.settable(L, t, n, L.stack[L.top - 1]);
+    L.top--;  /* pop value */
+};
+
 const lua_rawset = function(L, idx) {
     assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack");
     let o = index2addr(L, idx);
@@ -780,6 +787,7 @@ module.exports.lua_remove          = lua_remove;
 module.exports.lua_rotate          = lua_rotate;
 module.exports.lua_setfield        = lua_setfield;
 module.exports.lua_setglobal       = lua_setglobal;
+module.exports.lua_seti            = lua_seti;
 module.exports.lua_setmetatable    = lua_setmetatable;
 module.exports.lua_settable        = lua_settable;
 module.exports.lua_settop          = lua_settop;
diff --git a/src/ltablib.js b/src/ltablib.js
index 8e1f758..ec7c578 100644
--- a/src/ltablib.js
+++ b/src/ltablib.js
@@ -80,8 +80,20 @@ const tconcat = function(L) {
     return 1;
 };
 
+const pack = function(L) {
+    let n = lapi.lua_gettop(L);  /* number of elements to pack */
+    lapi.lua_createtable(L, n, 1);  /* create result table */
+    lapi.lua_insert(L, 1);  /* put it at index 1 */
+    for (let i = n; i >= 1; i--)  /* assign elements */
+        lapi.lua_seti(L, 1, i);
+    lapi.lua_pushinteger(L, n);
+    lapi.lua_setfield(L, 1, "n");  /* t.n = number of elements */
+    return 1;  /* return table */
+};
+
 const tab_funcs = {
-    "concat": tconcat
+    "concat": tconcat,
+    "pack":   pack
 };
 
 const luaopen_table = function(L) {
diff --git a/tests/ltablib.js b/tests/ltablib.js
index 22a6797..28b9ce0 100644
--- a/tests/ltablib.js
+++ b/tests/ltablib.js
@@ -44,4 +44,35 @@ test('table.concat', function (t) {
         "3,4,5",
         "Correct element(s) on the stack"
     );
+});
+
+
+test('table.pack', function (t) {
+    let luaCode = `
+        return table.pack(1, 2, 3)
+    `, 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.pack");
+
+        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') // Filter out the 'n' field
+            .map(e => e[1].value).reverse(),
+        [1, 2, 3],
+        "Correct element(s) on the stack"
+    );
 });
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2