From 7e886ba08a443d9653c3033901ae8c83108d3701 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 21:17:26 +1000
Subject: src/lapi.js: Simplify+optimise lua_rotate

---
 src/lapi.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/lapi.js b/src/lapi.js
index ca5a8a0..f06fc65 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -181,14 +181,14 @@ const reverse = function(L, from, to) {
 ** rotate x n === BA. But BA === (A^r . B^r)^r.
 */
 const lua_rotate = function(L, idx, n) {
-    let t = L.stack[L.top - 1];
-    let p = index2addr(L, idx);
+    let t = L.top - 1;
     let pIdx = index2addr_(L, idx);
+    let p = L.stack[pIdx];
 
-    assert(p !== lobject.luaO_nilobject && idx > defs.LUA_REGISTRYINDEX, "index not in the stack");
-    assert((n >= 0 ? n : -n) <= (L.top - idx), "invalid 'n'");
+    assert(isvalid(p) && idx > defs.LUA_REGISTRYINDEX, "index not in the stack");
+    assert((n >= 0 ? n : -n) <= (t - pIdx + 1), "invalid 'n'");
 
-    let m = n >= 0 ? L.top - 1 - n : pIdx - n - 1;  /* end of prefix */
+    let m = n >= 0 ? t - n : pIdx - n - 1;  /* end of prefix */
 
     reverse(L, pIdx, m);
     reverse(L, m + 1, L.top - 1);
-- 
cgit v1.2.3-70-g09d2


From e4c9580d20924a0db1ff7ed0d30da9b71dbb5066 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 21:21:50 +1000
Subject: Introduce lvm.cvt2str

In future this could be configurable
---
 src/lapi.js   | 16 +++++++++++-----
 src/ldebug.js |  2 +-
 src/lvm.js    |  9 +++++++--
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/lapi.js b/src/lapi.js
index f06fc65..f7ef82e 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -667,8 +667,11 @@ const lua_toboolean = function(L, idx) {
 const lua_tolstring = function(L, idx) {
     let o = index2addr(L, idx);
 
-    if ((!o.ttisstring() && !o.ttisnumber()))
-        return null;
+    if (!o.ttisstring()) {
+        if (!lvm.cvt2str(o)) {  /* not convertible? */
+            return null;
+        }
+    }
 
     return o.ttisstring() ? o.svalue() : defs.to_luastring(`${o.value}`);
 };
@@ -678,8 +681,11 @@ const lua_tostring =  lua_tolstring;
 const lua_toljsstring = function(L, idx) {
     let o = index2addr(L, idx);
 
-    if ((!o.ttisstring() && !o.ttisnumber()))
-        return null;
+    if (!o.ttisstring()) {
+        if (!lvm.cvt2str(o)) {  /* not convertible? */
+            return null;
+        }
+    }
 
     return o.ttisstring() ? o.jsstring() : `${o.value}`;
 };
@@ -872,7 +878,7 @@ const lua_isnumber = function(L, idx) {
 
 const lua_isstring = function(L, idx) {
     let o = index2addr(L, idx);
-    return o.ttisstring() || o.ttisnumber();
+    return o.ttisstring() || lvm.cvt2str(o);
 };
 
 const lua_isuserdata = function(L, idx) {
diff --git a/src/ldebug.js b/src/ldebug.js
index 1862e55..74a04db 100644
--- a/src/ldebug.js
+++ b/src/ldebug.js
@@ -546,7 +546,7 @@ const luaG_typeerror = function(L, o, op) {
 };
 
 const luaG_concaterror = function(L, p1, p2) {
-    if (p1.ttisstring() || p1.ttisnumber()) p1 = p2;
+    if (p1.ttisstring() || lvm.cvt2str(p1)) p1 = p2;
     luaG_typeerror(L, p1, defs.to_luastring('concatenate', true));
 };
 
diff --git a/src/lvm.js b/src/lvm.js
index 4804cde..bd370a6 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -958,12 +958,16 @@ const luaV_shiftl = function(x, y) {
     }
 };
 
+const cvt2str = function(o) {
+    return o.ttisnumber();
+};
+
 const tostring = function(L, i) {
     let o = L.stack[i];
 
     if (o.ttisstring()) return true;
 
-    if (o.ttisnumber() && !isNaN(o.value)) {
+    if (cvt2str(o) && !isNaN(o.value)) {
         L.stack[i] = new lobject.TValue(CT.LUA_TLNGSTR, lstring.luaS_bless(L, defs.to_luastring(`${o.value}`)));
         return true;
     }
@@ -985,7 +989,7 @@ const luaV_concat = function(L, total) {
         let top = L.top;
         let n = 2; /* number of elements handled in this pass (at least 2) */
 
-        if (!(L.stack[top-2].ttisstring() || L.stack[top-2].ttisnumber()) || !tostring(L, top - 1)) {
+        if (!(L.stack[top-2].ttisstring() || cvt2str(L.stack[top-2])) || !tostring(L, top - 1)) {
             ltm.luaT_trybinTM(L, L.stack[top-2], L.stack[top-1], top-2, ltm.TMS.TM_CONCAT);
             delete L.stack[top - 1];
         } else if (isemptystr(L.stack[top-1])) {
@@ -1090,6 +1094,7 @@ module.exports.RB                = RB;
 module.exports.RC                = RC;
 module.exports.RKB               = RKB;
 module.exports.RKC               = RKC;
+module.exports.cvt2str           = cvt2str;
 module.exports.dojump            = dojump;
 module.exports.donextjump        = donextjump;
 module.exports.forlimit          = forlimit;
-- 
cgit v1.2.3-70-g09d2


From 4f4e76d8de5fea7e636bdf5b5e271a2216531345 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 21:32:41 +1000
Subject: src/lvm.js: Introduce cvt2num at mirror cvt2str

---
 src/lvm.js | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/lvm.js b/src/lvm.js
index bd370a6..83feb9b 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -804,9 +804,10 @@ const luaV_tointeger = function(obj, mode) {
         return luaconf.lua_numbertointeger(f);
     } else if (obj.ttisinteger()) {
         return obj.value;
-    } else if (obj.ttisstring()) {
-        let n = lobject.luaO_str2num(obj.svalue());
-        return n !== false ? luaV_tointeger(n, mode) : false;
+    } else if (cvt2num(obj)) {
+        let v = lobject.luaO_str2num(obj.svalue());
+        if (v !== false)
+            return luaV_tointeger(v, mode);
     }
 
     return false;
@@ -816,13 +817,14 @@ const tointeger = function(o) {
     return o.ttisinteger() ? o.value : luaV_tointeger(o, 0);
 };
 
-const tonumber = function(v) {
-    if (v.ttnov() === CT.LUA_TNUMBER)
-        return v.value;
+const tonumber = function(o) {
+    if (o.ttnov() === CT.LUA_TNUMBER)
+        return o.value;
 
-    if (v.ttnov() === CT.LUA_TSTRING) {
-        let number = lobject.luaO_str2num(v.svalue());
-        return number ? number.value : false;
+    if (cvt2num(o)) { /* string convertible to number? */
+        let v = lobject.luaO_str2num(o.svalue());
+        if (v !== false)
+            return v.value;
     }
 
     return false;
@@ -962,6 +964,10 @@ const cvt2str = function(o) {
     return o.ttisnumber();
 };
 
+const cvt2num = function(o) {
+    return o.ttisstring();
+};
+
 const tostring = function(L, i) {
     let o = L.stack[i];
 
@@ -1095,6 +1101,7 @@ module.exports.RC                = RC;
 module.exports.RKB               = RKB;
 module.exports.RKC               = RKC;
 module.exports.cvt2str           = cvt2str;
+module.exports.cvt2num           = cvt2num;
 module.exports.dojump            = dojump;
 module.exports.donextjump        = donextjump;
 module.exports.forlimit          = forlimit;
-- 
cgit v1.2.3-70-g09d2


From ac706a718bb39aefdac1a9fa2bb37f94ecc4245c Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:50:15 +1000
Subject: yarn.lock: Update sprintf-js version required

---
 yarn.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/yarn.lock b/yarn.lock
index 7a5150e..ddd4564 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1899,7 +1899,7 @@ spdx-license-ids@^1.0.2:
 
 sprintf-js@giann/sprintf.js:
   version "1.0.3"
-  resolved "https://codeload.github.com/giann/sprintf.js/tar.gz/78f98d4f39ba27579992ea66cbf2b23265c796ba"
+  resolved "https://codeload.github.com/giann/sprintf.js/tar.gz/432783731ee125b6746495beba5b408b14750840"
 
 sprintf@~0.1.3:
   version "0.1.5"
-- 
cgit v1.2.3-70-g09d2


From 7d849c2df476c92a09ed4067117b5d5e3d5d988e Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:08:21 +1000
Subject: src/lstrlib: math.mininteger has to print specially

---
 src/lstrlib.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/lstrlib.js b/src/lstrlib.js
index 8bc2b0e..8e8b58e 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -225,7 +225,10 @@ const addliteral = function(L, b, arg) {
                 checkdp(b);  /* ensure it uses a dot */
             } else {  /* integers */
                 let n = lua.lua_tointeger(L, arg);
-                concat(b, lua.to_luastring(sprintf("%d", n)));
+                let format = (n === llimit.LUA_MININTEGER)  /* corner case? */
+                    ? "0x%" + luaconf.LUA_INTEGER_FRMLEN + "x"  /* use hexa */
+                    : luaconf.LUA_INTEGER_FMT;  /* else use default format */
+                concat(b, lua.to_luastring(sprintf(format, n)));
             }
             break;
         }
-- 
cgit v1.2.3-70-g09d2


From b525c305b524f5b3ffaba3187ccc828d332aa835 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:11:34 +1000
Subject: src/luaconf.js: Implement lua_integer2str and lua_number2str

---
 src/luaconf.js | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/luaconf.js b/src/luaconf.js
index 3d0d18f..c272178 100644
--- a/src/luaconf.js
+++ b/src/luaconf.js
@@ -2,6 +2,7 @@
 "use strict";
 
 const llimit = require('./llimit.js');
+const sprintf = require('sprintf-js').sprintf;
 
 /*
 @@ LUAI_MAXSTACK limits the size of the Lua stack.
@@ -18,6 +19,14 @@ const LUAI_MAXSTACK = 1000000;
 */
 const LUA_IDSIZE = 60;
 
+const lua_integer2str = function(n) {
+    return sprintf(LUA_INTEGER_FMT, n);
+};
+
+const lua_number2str = function(n) {
+    return sprintf(LUA_NUMBER_FMT, n);
+};
+
 const lua_numbertointeger = function(n) {
     return n >= llimit.MIN_INT && n < -llimit.MIN_INT ? n : false;
 };
@@ -64,4 +73,6 @@ module.exports.LUA_INTEGER_FRMLEN    = LUA_INTEGER_FRMLEN;
 module.exports.LUA_NUMBER_FMT        = LUA_NUMBER_FMT;
 module.exports.LUA_NUMBER_FRMLEN     = LUA_NUMBER_FRMLEN;
 module.exports.lua_getlocaledecpoint = lua_getlocaledecpoint;
+module.exports.lua_integer2str       = lua_integer2str;
+module.exports.lua_number2str        = lua_number2str;
 module.exports.lua_numbertointeger   = lua_numbertointeger;
-- 
cgit v1.2.3-70-g09d2


From 128ae8cc451126ee7201de7efb6cc0c39fb1a2b4 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:19:22 +1000
Subject: Introduce luaO_tostring

---
 src/lapi.js    |  8 ++++----
 src/lobject.js | 17 ++++++++++++++++-
 src/lvm.js     |  4 ++--
 3 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/src/lapi.js b/src/lapi.js
index f7ef82e..efc59aa 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -671,9 +671,9 @@ const lua_tolstring = function(L, idx) {
         if (!lvm.cvt2str(o)) {  /* not convertible? */
             return null;
         }
+        o = lobject.luaO_tostring(L, o);
     }
-
-    return o.ttisstring() ? o.svalue() : defs.to_luastring(`${o.value}`);
+    return o.svalue();
 };
 
 const lua_tostring =  lua_tolstring;
@@ -685,9 +685,9 @@ const lua_toljsstring = function(L, idx) {
         if (!lvm.cvt2str(o)) {  /* not convertible? */
             return null;
         }
+        o = lobject.luaO_tostring(L, o);
     }
-
-    return o.ttisstring() ? o.jsstring() : `${o.value}`;
+    return o.jsstring();
 };
 
 const lua_tojsstring =  lua_toljsstring;
diff --git a/src/lobject.js b/src/lobject.js
index 41c3a84..e7b716e 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -448,6 +448,18 @@ const luaO_utf8esc = function(x) {
     };
 };
 
+/* this currently returns new TValue instead of modifying */
+const luaO_tostring = function(L, obj) {
+    let buff;
+    if (obj.ttisinteger())
+        buff = defs.to_luastring(luaconf.lua_integer2str(obj.value));
+    else {
+        let str = luaconf.lua_number2str(obj.value);
+        buff = defs.to_luastring(str);
+    }
+    return new TValue(CT.LUA_TLNGSTR, lstring.luaS_bless(L, buff));
+};
+
 const pushstr = function(L, str) {
     L.stack[L.top++] = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, str));
 };
@@ -476,8 +488,10 @@ const luaO_pushvfstring = function(L, fmt, argp) {
                 break;
             case char['d']:
             case char['I']:
+                L.stack[L.top++] = luaO_tostring(L, new TValue(CT.LUA_TNUMINT, argp[a++]));
+                break;
             case char['f']:
-                pushstr(L, defs.to_luastring(''+argp[a++]));
+                L.stack[L.top++] = luaO_tostring(L, new TValue(CT.LUA_TNUMFLT, argp[a++]));
                 break;
             // case char['p']:
             case char['U']:
@@ -616,6 +630,7 @@ module.exports.luaO_int2fb       = luaO_int2fb;
 module.exports.luaO_pushfstring  = luaO_pushfstring;
 module.exports.luaO_pushvfstring = luaO_pushvfstring;
 module.exports.luaO_str2num      = luaO_str2num;
+module.exports.luaO_tostring     = luaO_tostring;
 module.exports.luaO_utf8desc     = luaO_utf8desc;
 module.exports.luaO_utf8esc      = luaO_utf8esc;
 module.exports.numarith          = numarith;
diff --git a/src/lvm.js b/src/lvm.js
index 83feb9b..0081376 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -973,8 +973,8 @@ const tostring = function(L, i) {
 
     if (o.ttisstring()) return true;
 
-    if (cvt2str(o) && !isNaN(o.value)) {
-        L.stack[i] = new lobject.TValue(CT.LUA_TLNGSTR, lstring.luaS_bless(L, defs.to_luastring(`${o.value}`)));
+    if (cvt2str(o)) {
+        L.stack[i] = lobject.luaO_tostring(L, o);
         return true;
     }
 
-- 
cgit v1.2.3-70-g09d2


From e6639768e4a059aeaf80e232c729dffa3b5e93ba Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:20:02 +1000
Subject: src/lauxlib.js: Use lua_pushfstring for formatting numbers

---
 src/lauxlib.js              | 21 +++------------------
 tests/test-suite/strings.js |  2 +-
 2 files changed, 4 insertions(+), 19 deletions(-)

diff --git a/src/lauxlib.js b/src/lauxlib.js
index 559e1bc..3959817 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -473,24 +473,9 @@ const luaL_tolstring = function(L, idx) {
         switch(t) {
             case lua.LUA_TNUMBER: {
                 if (lua.lua_isinteger(L, idx))
-                    lua.lua_pushstring(L, lua.to_luastring(lua.lua_tointeger(L, idx).toString()));
-                else {
-                    let n = lua.lua_tonumber(L, idx);
-                    let a = Math.abs(n);
-                    let s;
-                    if (Object.is(n, Infinity))
-                        s = 'inf';
-                    else if (Object.is(n, -Infinity))
-                        s = '-inf';
-                    else if (Number.isNaN(n))
-                        s = 'nan';
-                    else if (a >= 100000000000000 || (a > 0 && a < 0.0001))
-                        s = n.toExponential();
-                    else
-                        s = n.toPrecision(16).replace(/(\.[0-9][1-9]*)0+$/, "$1");
-
-                    lua.lua_pushstring(L, lua.to_luastring(s));
-                }
+                    lua.lua_pushfstring(L, lua.to_luastring("%I"), lua.lua_tointeger(L, idx));
+                else
+                    lua.lua_pushfstring(L, lua.to_luastring("%f"), lua.lua_tonumber(L, idx));
                 break;
             }
             case lua.LUA_TSTRING:
diff --git a/tests/test-suite/strings.js b/tests/test-suite/strings.js
index 3584a80..d7b30a8 100644
--- a/tests/test-suite/strings.js
+++ b/tests/test-suite/strings.js
@@ -288,7 +288,7 @@ test('[test-suite] strings: tostring', function (t) {
         end
 
         if tostring(0.0) == "0.0" then   -- "standard" coercion float->string
-          -- assert('' .. 12 == '12' and 12.0 .. '' == '12.0') -- TODO: How to do this in JS ?
+          assert('' .. 12 == '12' and 12.0 .. '' == '12.0')
           assert(tostring(-1203 + 0.0) == "-1203.0")
         else   -- compatible coercion
           assert(tostring(0.0) == "0")
-- 
cgit v1.2.3-70-g09d2


From 13328c5bee9b847317313491c3eb9f6f66766de7 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:26:44 +1000
Subject: Add luaD_inctop calls where appropriate

---
 src/ldo.js     | 6 ++++++
 src/lobject.js | 9 ++++++---
 src/lparser.js | 7 +++++--
 src/lundump.js | 3 ++-
 4 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/src/ldo.js b/src/ldo.js
index 83f26cf..fbef68f 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -89,6 +89,11 @@ const luaD_shrinkstack = function(L) {
         luaD_reallocstack(L, goodsize);
 };
 
+const luaD_inctop = function(L) {
+  luaD_checkstack(L, 1);
+  L.top++;
+};
+
 /*
 ** Prepares a function call: checks the stack, creates a new CallInfo
 ** entry, fills in the relevant information, calls hook if needed.
@@ -653,6 +658,7 @@ module.exports.luaD_callnoyield     = luaD_callnoyield;
 module.exports.luaD_checkstack      = luaD_checkstack;
 module.exports.luaD_growstack       = luaD_growstack;
 module.exports.luaD_hook            = luaD_hook;
+module.exports.luaD_inctop          = luaD_inctop;
 module.exports.luaD_pcall           = luaD_pcall;
 module.exports.luaD_poscall         = luaD_poscall;
 module.exports.luaD_precall         = luaD_precall;
diff --git a/src/lobject.js b/src/lobject.js
index e7b716e..fad3b73 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -461,7 +461,8 @@ const luaO_tostring = function(L, obj) {
 };
 
 const pushstr = function(L, str) {
-    L.stack[L.top++] = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, str));
+    ldo.luaD_inctop(L);
+    L.stack[L.top-1] = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, str));
 };
 
 const luaO_pushvfstring = function(L, fmt, argp) {
@@ -488,10 +489,12 @@ const luaO_pushvfstring = function(L, fmt, argp) {
                 break;
             case char['d']:
             case char['I']:
-                L.stack[L.top++] = luaO_tostring(L, new TValue(CT.LUA_TNUMINT, argp[a++]));
+                ldo.luaD_inctop(L);
+                L.stack[L.top-1] = luaO_tostring(L, new TValue(CT.LUA_TNUMINT, argp[a++]));
                 break;
             case char['f']:
-                L.stack[L.top++] = luaO_tostring(L, new TValue(CT.LUA_TNUMFLT, argp[a++]));
+                ldo.luaD_inctop(L);
+                L.stack[L.top-1] = luaO_tostring(L, new TValue(CT.LUA_TNUMFLT, argp[a++]));
                 break;
             // case char['p']:
             case char['U']:
diff --git a/src/lparser.js b/src/lparser.js
index 100342a..13f75c9 100644
--- a/src/lparser.js
+++ b/src/lparser.js
@@ -4,6 +4,7 @@ const assert = require('assert');
 
 const defs     = require('./defs.js');
 const lcode    = require('./lcode.js');
+const ldo      = require('./ldo.js');
 const lfunc    = require('./lfunc.js');
 const llex     = require('./llex.js');
 const llimit   = require('./llimit.js');
@@ -1563,9 +1564,11 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) {
     let lexstate = new llex.LexState();
     let funcstate = new FuncState();
     let cl = lfunc.luaF_newLclosure(L, 1);  /* create main closure */
-    L.stack[L.top++] = new TValue(defs.CT.LUA_TLCL, cl);
+    ldo.luaD_inctop(L);
+    L.stack[L.top-1] = new TValue(defs.CT.LUA_TLCL, cl);
     lexstate.h = ltable.luaH_new(L);  /* create table for scanner */
-    L.stack[L.top++] = new TValue(defs.CT.LUA_TTABLE, lexstate.h);
+    ldo.luaD_inctop(L);
+    L.stack[L.top-1] = new TValue(defs.CT.LUA_TTABLE, lexstate.h);
     funcstate.f = cl.p = new Proto(L);
     funcstate.f.source = lstring.luaS_new(L, name);
     lexstate.buff = buff;
diff --git a/src/lundump.js b/src/lundump.js
index 1891451..4931fe8 100644
--- a/src/lundump.js
+++ b/src/lundump.js
@@ -265,7 +265,8 @@ const luaU_undump = function(L, Z, name) {
     let S = new BytecodeParser(L, Z, name);
     S.checkHeader();
     let cl = lfunc.luaF_newLclosure(L, S.readByte());
-    L.stack[L.top++] = new lobject.TValue(defs.CT.LUA_TLCL, cl);
+    ldo.luaD_inctop(L);
+    L.stack[L.top-1] = new lobject.TValue(defs.CT.LUA_TLCL, cl);
     cl.p = new lfunc.Proto(L);
     S.readFunction(cl.p, null);
     assert(cl.nupvalues === cl.p.upvalues.length);
-- 
cgit v1.2.3-70-g09d2


From 252284298bce111a7b2e1bea07eef54a7835c422 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:28:59 +1000
Subject: src/lobject.js: Don't assume LUA_COMPAT_FLOATSTRING

---
 src/lobject.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/lobject.js b/src/lobject.js
index fad3b73..8c70985 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -456,6 +456,11 @@ const luaO_tostring = function(L, obj) {
     else {
         let str = luaconf.lua_number2str(obj.value);
         buff = defs.to_luastring(str);
+        // Assume no LUA_COMPAT_FLOATSTRING
+        if (/^[-0123456789]+$/.test(str)) {  /* looks like an int? */
+            buff.push(char[luaconf.lua_getlocaledecpoint()]);
+            buff.push(char['0']);  /* adds '.0' to result */
+        }
     }
     return new TValue(CT.LUA_TLNGSTR, lstring.luaS_bless(L, buff));
 };
-- 
cgit v1.2.3-70-g09d2


From f83115f90039666b9dc19c3ee9972a3aa98d28e7 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:34:25 +1000
Subject: src/lapi.js: Throw errors when attempting to use pseudo-index with
 index2addr_

---
 src/lapi.js | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/src/lapi.js b/src/lapi.js
index efc59aa..8e0c491 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -66,7 +66,7 @@ const index2addr = function(L, idx) {
     }
 };
 
-// Like index2addr but returns the index on stack
+// Like index2addr but returns the index on stack; doesn't allow pseudo indices
 const index2addr_ = function(L, idx) {
     let ci = L.ci;
     if (idx > 0) {
@@ -77,16 +77,8 @@ const index2addr_ = function(L, idx) {
     } else if (idx > defs.LUA_REGISTRYINDEX) {
         assert(idx !== 0 && -idx <= L.top, "invalid index");
         return L.top + idx;
-    } else if (idx === defs.LUA_REGISTRYINDEX) {
-        return null;
-    } else { /* upvalues */
-        idx = defs.LUA_REGISTRYINDEX - idx;
-        assert(idx <= MAXUPVAL + 1, "upvalue index too large");
-        if (ci.func.ttislcf()) /* light C function? */
-            return null; /* it has no upvalues */
-        else {
-            return idx <= ci.func.nupvalues ? idx - 1 : null;
-        }
+    } else { /* registry or upvalue */
+        throw Error("attempt to use pseudo-index");
     }
 };
 
-- 
cgit v1.2.3-70-g09d2


From 69fdbe3590eb2ddfa970888b7b59e8a84fbda101 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:09:21 +1000
Subject: tests/test-suite/strings.js: un-skip fixed test

---
 tests/test-suite/strings.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/tests/test-suite/strings.js b/tests/test-suite/strings.js
index d7b30a8..c501ddd 100644
--- a/tests/test-suite/strings.js
+++ b/tests/test-suite/strings.js
@@ -365,8 +365,7 @@ test('[test-suite] strings: string.format', function (t) {
 });
 
 
-// TODO: http://lua-users.org/lists/lua-l/2016-05/msg00455.html
-test('[test-suite] strings: %q', { skip: true },  function (t) {
+test('[test-suite] strings: %q', function (t) {
     let luaCode = `
         do
           local function checkQ (v)
-- 
cgit v1.2.3-70-g09d2


From ee502076941676ff570866cba36a21bf06c29fc0 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Mon, 22 May 2017 23:54:15 +1000
Subject: Revert "src/lstate.js: Remove useless luaE_freeCI"

This reverts commit 6646bebd474b95a2d4cbb8558c0d1cb5b5353de0.
---
 src/lstate.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/lstate.js b/src/lstate.js
index b71e011..124322d 100644
--- a/src/lstate.js
+++ b/src/lstate.js
@@ -86,6 +86,11 @@ const luaE_extendCI = function(L) {
     return ci;
 };
 
+const luaE_freeCI = function(L) {
+    let ci = L.ci;
+    ci.next = null;
+};
+
 const stack_init = function(L1, L) {
     L1.stack = new Array(BASIC_STACK_SIZE);
     L1.top = 0;
@@ -103,6 +108,7 @@ const stack_init = function(L1, L) {
 
 const freestack = function(L) {
     L.ci = L.base_ci;
+    luaE_freeCI(L);
     L.stack = null;
 };
 
@@ -204,4 +210,5 @@ module.exports.lua_close       = lua_close;
 module.exports.lua_newstate    = lua_newstate;
 module.exports.lua_newthread   = lua_newthread;
 module.exports.luaE_extendCI   = luaE_extendCI;
+module.exports.luaE_freeCI     = luaE_freeCI;
 module.exports.luaE_freethread = luaE_freethread;
-- 
cgit v1.2.3-70-g09d2


From f7bb8409d6c57b5e9319f4f48d7d02f216b4cc32 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:05:13 +1000
Subject: src/ldo.js: free CallInfo to recover from (lua) stack overflow

---
 src/ldo.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/ldo.js b/src/ldo.js
index fbef68f..cda1274 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -85,6 +85,10 @@ const luaD_shrinkstack = function(L) {
     let goodsize = inuse + Math.floor(inuse / 8) + 2*lstate.EXTRA_STACK;
     if (goodsize > luaconf.LUAI_MAXSTACK)
         goodsize = luaconf.LUAI_MAXSTACK;  /* respect stack limit */
+    if (L.stack.length > luaconf.LUAI_MAXSTACK)  /* had been handling stack overflow? */
+        lstate.luaE_freeCI(L);  /* free all CIs (list grew because of an error) */
+    /* if thread is currently not handling a stack overflow and its
+     good size is smaller than current size, shrink its stack */
     if (inuse <= (luaconf.LUAI_MAXSTACK - lstate.EXTRA_STACK) && goodsize < L.stack.length)
         luaD_reallocstack(L, goodsize);
 };
-- 
cgit v1.2.3-70-g09d2


From f6b260d2b97c40f360136d0c1320d8f6468f7e87 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:05:31 +1000
Subject: src/ldo.js: luaG_runerror takes lua strings

---
 src/ldo.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ldo.js b/src/ldo.js
index cda1274..701a211 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -59,7 +59,7 @@ const luaD_growstack = function(L, n) {
         if (newsize < needed) newsize = needed;
         if (newsize > luaconf.LUAI_MAXSTACK) {  /* stack overflow? */
             luaD_reallocstack(L, ERRORSTACKSIZE);
-            ldebug.luaG_runerror(L, "stack overflow");
+            ldebug.luaG_runerror(L, defs.to_luastring("stack overflow", true));
         }
         else
             luaD_reallocstack(L, newsize);
@@ -281,7 +281,7 @@ const tryfuncTM = function(L, off, func) {
 */
 const stackerror = function(L) {
     if (L.nCcalls === llimit.LUAI_MAXCCALLS)
-        ldebug.luaG_runerror(L, "JS stack overflow");
+        ldebug.luaG_runerror(L, defs.to_luastring("JS stack overflow", true));
     else if (L.nCcalls >= llimit.LUAI_MAXCCALLS + (llimit.LUAI_MAXCCALLS >> 3))
         luaD_throw(L, TS.LUA_ERRERR);  /* error while handing stack error */
 };
-- 
cgit v1.2.3-70-g09d2


From 1188498c1f714c32c287dfb657894d51c77e2c1b Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:06:43 +1000
Subject: tests/test-suite/errors.js: un-skip test as we can now recover from a
 stack overflow

---
 tests/test-suite/errors.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test-suite/errors.js b/tests/test-suite/errors.js
index c18adeb..47b4b2a 100644
--- a/tests/test-suite/errors.js
+++ b/tests/test-suite/errors.js
@@ -836,7 +836,7 @@ test("[test-suite] errors: testing line error", function (t) {
 });
 
 
-test("[test-suite] errors: several tests that exhaust the Lua stack", { skip: true }, function (t) {
+test("[test-suite] errors: several tests that exhaust the Lua stack", function (t) {
     let luaCode = `
         C = 0
         local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end
-- 
cgit v1.2.3-70-g09d2


From 2aaf4a458734a46cbd3a4bfd8890206ed3c12594 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:07:22 +1000
Subject: tests/test-suite/nextvar.js: un-skip passing test

---
 tests/test-suite/nextvar.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/tests/test-suite/nextvar.js b/tests/test-suite/nextvar.js
index d119d97..28a54e7 100644
--- a/tests/test-suite/nextvar.js
+++ b/tests/test-suite/nextvar.js
@@ -907,8 +907,7 @@ test("[test-suite] nextvar: next", function (t) {
 });
 
 
-// TODO: infinite loop ?
-test("[test-suite] nextvar: testing floats in numeric for", { skip: true }, function (t) {
+test("[test-suite] nextvar: testing floats in numeric for", function (t) {
     let luaCode = `
         do
           local a
-- 
cgit v1.2.3-70-g09d2


From 56a72b0c1ce00b4de0b25318c3eabd6c48deab2e Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:10:52 +1000
Subject: tests/test-suite/math.js: un-skip passing test

---
 tests/test-suite/math.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test-suite/math.js b/tests/test-suite/math.js
index e79281b..b92d304 100644
--- a/tests/test-suite/math.js
+++ b/tests/test-suite/math.js
@@ -746,7 +746,7 @@ test("[test-suite] math: 'tonumber' with strings", function (t) {
 });
 
 
-test("[test-suite] math: tests with very long numerals", { skip: true }, function (t) {
+test("[test-suite] math: tests with very long numerals", function (t) {
     let luaCode = `
         assert(tonumber("0x"..string.rep("f", 13)..".0") == 2.0^(4*13) - 1)
         assert(tonumber("0x"..string.rep("f", 150)..".0") == 2.0^(4*150) - 1)
-- 
cgit v1.2.3-70-g09d2


From 0085399fa4b4a6e9450ab454a4ac33dd26db003e Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:16:59 +1000
Subject: tests/test-suite/errors.js: un-skip passing test

---
 tests/test-suite/errors.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/test-suite/errors.js b/tests/test-suite/errors.js
index 47b4b2a..432ee35 100644
--- a/tests/test-suite/errors.js
+++ b/tests/test-suite/errors.js
@@ -950,7 +950,7 @@ test("[test-suite] errors: error in error handling", function (t) {
 });
 
 
-test("[test-suite] errors: too many results", { skip: true }, function (t) {
+test("[test-suite] errors: too many results", function (t) {
     let luaCode = `
         local function loop (x,y,z) return 1 + loop(x, y, z) end
 
-- 
cgit v1.2.3-70-g09d2


From 275c497e20df141160b92db6503da0b98f611bc0 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:23:54 +1000
Subject: tests/test-suite/errors.js: copy setup from previous test to get a
 skipped test passing

---
 tests/test-suite/errors.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/test-suite/errors.js b/tests/test-suite/errors.js
index 432ee35..5980724 100644
--- a/tests/test-suite/errors.js
+++ b/tests/test-suite/errors.js
@@ -871,9 +871,10 @@ test("[test-suite] errors: several tests that exhaust the Lua stack", function (
 });
 
 
-test("[test-suite] errors: error lines in stack overflow", { skip: true }, function (t) {
+test("[test-suite] errors: error lines in stack overflow", function (t) {
     let luaCode = `
         C = 0
+        local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end
         local l1
         local function g(x)
           l1 = debug.getinfo(x, "l").currentline; y()
-- 
cgit v1.2.3-70-g09d2


From 8a439e5563f12335e3d35dd63b4f8cbcc25a9bd8 Mon Sep 17 00:00:00 2001
From: daurnimator <quae@daurnimator.com>
Date: Tue, 23 May 2017 00:27:09 +1000
Subject: tests/test-suite/events.js: un-skip fixed tests

---
 tests/test-suite/events.js | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/tests/test-suite/events.js b/tests/test-suite/events.js
index d5ed5ae..0f94f36 100644
--- a/tests/test-suite/events.js
+++ b/tests/test-suite/events.js
@@ -301,7 +301,6 @@ test("[test-suite] events: test comparison", function (t) {
 });
 
 
-// TODO: uncomment asserts when next is fixed for cleared table entries
 test("[test-suite] events: test 'partial order'", function (t) {
     let luaCode = `
         t = {}
@@ -327,9 +326,9 @@ test("[test-suite] events: test 'partial order'", function (t) {
         t.__le = nil
 
         assert(Set{1,2,3} < Set{1,2,3,4})
-        -- assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
-        -- assert((Set{1,2,3,4} <= Set{1,2,3,4}))
-        -- assert((Set{1,2,3,4} >= Set{1,2,3,4}))
+        assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
+        assert((Set{1,2,3,4} <= Set{1,2,3,4}))
+        assert((Set{1,2,3,4} >= Set{1,2,3,4}))
         assert((Set{1,3} <= Set{3,5}))   -- wrong!! model needs a 'le' method ;-)
 
         t.__le = function (a,b)
@@ -352,11 +351,11 @@ test("[test-suite] events: test 'partial order'", function (t) {
         end
 
         local s = Set{1,3,5}
-        -- assert(s == Set{3,5,1})
+        assert(s == Set{3,5,1})
         assert(not rawequal(s, Set{3,5,1}))
         assert(rawequal(s, s))
-        -- assert(Set{1,3,5,1} == rawSet{3,5,1})
-        -- assert(rawSet{1,3,5,1} == Set{3,5,1})
+        assert(Set{1,3,5,1} == rawSet{3,5,1})
+        assert(rawSet{1,3,5,1} == Set{3,5,1})
         assert(Set{1,3,5} ~= Set{3,5,1,6})
 
         -- '__eq' is not used for table accesses
-- 
cgit v1.2.3-70-g09d2