summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lapi.js48
-rw-r--r--src/lauxlib.js21
-rw-r--r--src/ldebug.js2
-rw-r--r--src/ldo.js14
-rw-r--r--src/lobject.js27
-rw-r--r--src/lparser.js7
-rw-r--r--src/lstate.js7
-rw-r--r--src/lstrlib.js5
-rw-r--r--src/luaconf.js11
-rw-r--r--src/lundump.js3
-rw-r--r--src/lvm.js36
11 files changed, 117 insertions, 64 deletions
diff --git a/src/lapi.js b/src/lapi.js
index ca5a8a0..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");
}
};
@@ -181,14 +173,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);
@@ -667,10 +659,13 @@ const lua_toboolean = function(L, idx) {
const lua_tolstring = function(L, idx) {
let o = index2addr(L, idx);
- if ((!o.ttisstring() && !o.ttisnumber()))
- return null;
-
- return o.ttisstring() ? o.svalue() : defs.to_luastring(`${o.value}`);
+ if (!o.ttisstring()) {
+ if (!lvm.cvt2str(o)) { /* not convertible? */
+ return null;
+ }
+ o = lobject.luaO_tostring(L, o);
+ }
+ return o.svalue();
};
const lua_tostring = lua_tolstring;
@@ -678,10 +673,13 @@ const lua_tostring = lua_tolstring;
const lua_toljsstring = function(L, idx) {
let o = index2addr(L, idx);
- if ((!o.ttisstring() && !o.ttisnumber()))
- return null;
-
- return o.ttisstring() ? o.jsstring() : `${o.value}`;
+ if (!o.ttisstring()) {
+ if (!lvm.cvt2str(o)) { /* not convertible? */
+ return null;
+ }
+ o = lobject.luaO_tostring(L, o);
+ }
+ return o.jsstring();
};
const lua_tojsstring = lua_toljsstring;
@@ -872,7 +870,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/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/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/ldo.js b/src/ldo.js
index 83f26cf..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);
@@ -85,10 +85,19 @@ 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);
};
+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.
@@ -272,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 */
};
@@ -653,6 +662,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 41c3a84..8c70985 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -448,8 +448,26 @@ 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);
+ // 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));
+};
+
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) {
@@ -476,8 +494,12 @@ const luaO_pushvfstring = function(L, fmt, argp) {
break;
case char['d']:
case char['I']:
+ ldo.luaD_inctop(L);
+ L.stack[L.top-1] = luaO_tostring(L, new TValue(CT.LUA_TNUMINT, argp[a++]));
+ break;
case char['f']:
- pushstr(L, defs.to_luastring(''+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']:
@@ -616,6 +638,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/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/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;
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;
}
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;
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);
diff --git a/src/lvm.js b/src/lvm.js
index 4804cde..0081376 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;
@@ -958,13 +960,21 @@ const luaV_shiftl = function(x, y) {
}
};
+const cvt2str = function(o) {
+ return o.ttisnumber();
+};
+
+const cvt2num = function(o) {
+ return o.ttisstring();
+};
+
const tostring = function(L, i) {
let o = L.stack[i];
if (o.ttisstring()) return true;
- if (o.ttisnumber() && !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;
}
@@ -985,7 +995,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 +1100,8 @@ module.exports.RB = RB;
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;