openwrt/package/utils/lua/patches/010-lua-5.1.3-lnum-full-260308.patch
Kevin Darbyshire-Bryant 4e800716ac lua: clean up patch fuzz
Refresh patches to tidy up fuzz.  No functional changes

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2018-01-05 10:42:34 +01:00

3738 lines
115 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--- a/src/Makefile
+++ b/src/Makefile
@@ -25,7 +25,7 @@ PLATS= aix ansi bsd freebsd generic linu
LUA_A= liblua.a
CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \
- lundump.o lvm.o lzio.o
+ lundump.o lvm.o lzio.o lnum.o
LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
lstrlib.o loadlib.o linit.o
@@ -148,6 +148,7 @@ llex.o: llex.c lua.h luaconf.h ldo.h lob
lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h ldo.h
+lnum.o: lnum.c lua.h llex.h lnum.h
loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h
@@ -179,4 +180,18 @@ lzio.o: lzio.c lua.h luaconf.h llimits.h
print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \
ltm.h lzio.h lmem.h lopcodes.h lundump.h
+luaconf.h: lnum_config.h
+lapi.c: lnum.h
+lauxlib.c: llimits.h
+lbaselib.c: llimits.h lobject.h lapi.h
+lcode.c: lnum.h
+liolib.c: lnum.h llex.h
+llex.c: lnum.h
+lnum.h: lobject.h
+lobject.c: llex.h lnum.h
+ltable.c: lnum.h
+lua.c: llimits.h
+lvm.c: llex.h lnum.h
+print.c: lnum.h
+
# (end of Makefile)
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -28,7 +28,7 @@
#include "ltm.h"
#include "lundump.h"
#include "lvm.h"
-
+#include "lnum.h"
const char lua_ident[] =
@@ -241,12 +241,13 @@ LUA_API void lua_pushvalue (lua_State *L
LUA_API int lua_type (lua_State *L, int idx) {
StkId o = index2adr(L, idx);
- return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
+ return (o == luaO_nilobject) ? LUA_TNONE : ttype_ext(o);
}
LUA_API const char *lua_typename (lua_State *L, int t) {
UNUSED(L);
+ lua_assert( t!= LUA_TINT );
return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
}
@@ -264,6 +265,14 @@ LUA_API int lua_isnumber (lua_State *L,
}
+LUA_API int lua_isinteger (lua_State *L, int idx) {
+ TValue tmp;
+ lua_Integer dum;
+ const TValue *o = index2adr(L, idx);
+ return tonumber(o,&tmp) && (ttisint(o) || tt_integer_valued(o,&dum));
+}
+
+
LUA_API int lua_isstring (lua_State *L, int idx) {
int t = lua_type(L, idx);
return (t == LUA_TSTRING || t == LUA_TNUMBER);
@@ -309,31 +318,66 @@ LUA_API int lua_lessthan (lua_State *L,
}
-
LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
TValue n;
const TValue *o = index2adr(L, idx);
- if (tonumber(o, &n))
+ if (tonumber(o, &n)) {
+#ifdef LNUM_COMPLEX
+ if (nvalue_img(o) != 0)
+ luaG_runerror(L, "expecting a real number");
+#endif
return nvalue(o);
- else
- return 0;
+ }
+ return 0;
}
LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
TValue n;
+ /* Lua 5.1 documented behaviour is to return nonzero for non-integer:
+ * "If the number is not an integer, it is truncated in some non-specified way."
+ * I would suggest to change this, to return 0 for anything that would
+ * not fit in 'lua_Integer'.
+ */
+#ifdef LUA_COMPAT_TOINTEGER
+ /* Lua 5.1 compatible */
const TValue *o = index2adr(L, idx);
if (tonumber(o, &n)) {
- lua_Integer res;
- lua_Number num = nvalue(o);
- lua_number2integer(res, num);
- return res;
+ lua_Integer i;
+ lua_Number d;
+ if (ttisint(o)) return ivalue(o);
+ d= nvalue_fast(o);
+# ifdef LNUM_COMPLEX
+ if (nvalue_img_fast(o) != 0)
+ luaG_runerror(L, "expecting a real number");
+# endif
+ lua_number2integer(i, d);
+ return i;
}
- else
- return 0;
+#else
+ /* New suggestion */
+ const TValue *o = index2adr(L, idx);
+ if (tonumber(o, &n)) {
+ lua_Integer i;
+ if (ttisint(o)) return ivalue(o);
+ if (tt_integer_valued(o,&i)) return i;
+ }
+#endif
+ return 0;
}
+#ifdef LNUM_COMPLEX
+LUA_API lua_Complex lua_tocomplex (lua_State *L, int idx) {
+ TValue tmp;
+ const TValue *o = index2adr(L, idx);
+ if (tonumber(o, &tmp))
+ return nvalue_complex(o);
+ return 0;
+}
+#endif
+
+
LUA_API int lua_toboolean (lua_State *L, int idx) {
const TValue *o = index2adr(L, idx);
return !l_isfalse(o);
@@ -364,6 +408,7 @@ LUA_API size_t lua_objlen (lua_State *L,
case LUA_TSTRING: return tsvalue(o)->len;
case LUA_TUSERDATA: return uvalue(o)->len;
case LUA_TTABLE: return luaH_getn(hvalue(o));
+ case LUA_TINT:
case LUA_TNUMBER: {
size_t l;
lua_lock(L); /* `luaV_tostring' may create a new string */
@@ -426,6 +471,8 @@ LUA_API void lua_pushnil (lua_State *L)
}
+/* 'lua_pushnumber()' may lose accuracy on integers, 'lua_pushinteger' will not.
+ */
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
setnvalue(L->top, n);
@@ -434,12 +481,22 @@ LUA_API void lua_pushnumber (lua_State *
}
-LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
+LUA_API void lua_pushinteger (lua_State *L, lua_Integer i) {
+ lua_lock(L);
+ setivalue(L->top, i);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+#ifdef LNUM_COMPLEX
+LUA_API void lua_pushcomplex (lua_State *L, lua_Complex v) {
lua_lock(L);
- setnvalue(L->top, cast_num(n));
+ setnvalue_complex( L->top, v );
api_incr_top(L);
lua_unlock(L);
}
+#endif
LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
@@ -569,7 +626,7 @@ LUA_API void lua_rawgeti (lua_State *L,
lua_lock(L);
o = index2adr(L, idx);
api_check(L, ttistable(o));
- setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
+ setobj2s(L, L->top, luaH_getint(hvalue(o), n));
api_incr_top(L);
lua_unlock(L);
}
@@ -597,6 +654,9 @@ LUA_API int lua_getmetatable (lua_State
case LUA_TUSERDATA:
mt = uvalue(obj)->metatable;
break;
+ case LUA_TINT:
+ mt = G(L)->mt[LUA_TNUMBER];
+ break;
default:
mt = G(L)->mt[ttype(obj)];
break;
@@ -687,7 +747,7 @@ LUA_API void lua_rawseti (lua_State *L,
api_checknelems(L, 1);
o = index2adr(L, idx);
api_check(L, ttistable(o));
- setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
+ setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1);
luaC_barriert(L, hvalue(o), L->top-1);
L->top--;
lua_unlock(L);
@@ -721,7 +781,7 @@ LUA_API int lua_setmetatable (lua_State
break;
}
default: {
- G(L)->mt[ttype(obj)] = mt;
+ G(L)->mt[ttype_ext(obj)] = mt;
break;
}
}
@@ -1085,3 +1145,32 @@ LUA_API const char *lua_setupvalue (lua_
return name;
}
+
+/* Help function for 'luaB_tonumber()', avoids multiple str->number
+ * conversions for Lua "tonumber()".
+ *
+ * Also pushes floating point numbers with integer value as integer, which
+ * can be used by 'tonumber()' in scripts to bring values back to integer
+ * realm.
+ *
+ * Note: The 'back to integer realm' is _not_ to affect string conversions:
+ * 'tonumber("4294967295.1")' should give a floating point value, although
+ * the value would be 4294967296 (and storable in int64 realm).
+ */
+int lua_pushvalue_as_number (lua_State *L, int idx)
+{
+ const TValue *o = index2adr(L, idx);
+ TValue tmp;
+ lua_Integer i;
+ if (ttisnumber(o)) {
+ if ( (!ttisint(o)) && tt_integer_valued(o,&i)) {
+ lua_pushinteger( L, i );
+ return 1;
+ }
+ } else if (!tonumber(o, &tmp)) {
+ return 0;
+ }
+ if (ttisint(o)) lua_pushinteger( L, ivalue(o) );
+ else lua_pushnumber( L, nvalue_fast(o) );
+ return 1;
+}
--- a/src/lapi.h
+++ b/src/lapi.h
@@ -13,4 +13,6 @@
LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
+int lua_pushvalue_as_number (lua_State *L, int idx);
+
#endif
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -23,7 +23,7 @@
#include "lua.h"
#include "lauxlib.h"
-
+#include "llimits.h"
#define FREELIST_REF 0 /* free list of references */
@@ -66,7 +66,7 @@ LUALIB_API int luaL_typerror (lua_State
static void tag_error (lua_State *L, int narg, int tag) {
- luaL_typerror(L, narg, lua_typename(L, tag));
+ luaL_typerror(L, narg, tag==LUA_TINT ? "integer" : lua_typename(L, tag));
}
@@ -188,8 +188,8 @@ LUALIB_API lua_Number luaL_optnumber (lu
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
lua_Integer d = lua_tointeger(L, narg);
- if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
- tag_error(L, narg, LUA_TNUMBER);
+ if (d == 0 && !lua_isinteger(L, narg)) /* avoid extra test when d is not 0 */
+ tag_error(L, narg, LUA_TINT);
return d;
}
@@ -200,6 +200,16 @@ LUALIB_API lua_Integer luaL_optinteger (
}
+#ifdef LNUM_COMPLEX
+LUALIB_API lua_Complex luaL_checkcomplex (lua_State *L, int narg) {
+ lua_Complex c = lua_tocomplex(L, narg);
+ if (c == 0 && !lua_isnumber(L, narg)) /* avoid extra test when c is not 0 */
+ tag_error(L, narg, LUA_TNUMBER);
+ return c;
+}
+#endif
+
+
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
if (!lua_getmetatable(L, obj)) /* no metatable? */
return 0;
--- a/src/lauxlib.h
+++ b/src/lauxlib.h
@@ -57,6 +57,12 @@ LUALIB_API lua_Number (luaL_optnumber) (
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
+#define luaL_checkint32(L,narg) ((int)luaL_checkinteger(L,narg))
+#define luaL_optint32(L,narg,def) ((int)luaL_optinteger(L,narg,def))
+
+#ifdef LNUM_COMPLEX
+ LUALIB_API lua_Complex (luaL_checkcomplex) (lua_State *L, int narg);
+#endif
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -18,7 +18,9 @@
#include "lauxlib.h"
#include "lualib.h"
-
+#include "llimits.h"
+#include "lobject.h"
+#include "lapi.h"
@@ -54,20 +56,25 @@ static int luaB_tonumber (lua_State *L)
int base = luaL_optint(L, 2, 10);
if (base == 10) { /* standard conversion */
luaL_checkany(L, 1);
- if (lua_isnumber(L, 1)) {
- lua_pushnumber(L, lua_tonumber(L, 1));
+ if (lua_isnumber(L, 1)) { /* numeric string, or a number */
+ lua_pushvalue_as_number(L,1); /* API extension (not to lose accuracy here) */
return 1;
- }
+ }
}
else {
const char *s1 = luaL_checkstring(L, 1);
char *s2;
- unsigned long n;
+ unsigned LUA_INTEGER n;
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
- n = strtoul(s1, &s2, base);
+ n = lua_str2ul(s1, &s2, base);
if (s1 != s2) { /* at least one valid digit? */
while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
if (*s2 == '\0') { /* no invalid trailing characters? */
+
+ /* Push as number, there needs to be separate 'luaB_tointeger' for
+ * when the caller wants to preserve the bits (matters if unsigned
+ * values are used).
+ */
lua_pushnumber(L, (lua_Number)n);
return 1;
}
@@ -144,7 +151,7 @@ static int luaB_setfenv (lua_State *L) {
luaL_checktype(L, 2, LUA_TTABLE);
getfunc(L, 0);
lua_pushvalue(L, 2);
- if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
+ if (lua_isnumber(L, 1) && lua_tointeger(L, 1) == 0) {
/* change environment of current thread */
lua_pushthread(L);
lua_insert(L, -2);
@@ -209,7 +216,7 @@ static int luaB_collectgarbage (lua_Stat
return 1;
}
default: {
- lua_pushnumber(L, res);
+ lua_pushinteger(L, res);
return 1;
}
}
@@ -631,6 +638,8 @@ static void base_open (lua_State *L) {
luaL_register(L, "_G", base_funcs);
lua_pushliteral(L, LUA_VERSION);
lua_setglobal(L, "_VERSION"); /* set global _VERSION */
+ lua_pushliteral(L, LUA_LNUM);
+ lua_setglobal(L, "_LNUM"); /* "[complex] double|float|ldouble int32|int64" */
/* `ipairs' and `pairs' need auxiliary functions as upvalues */
auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
auxopen(L, "pairs", luaB_pairs, luaB_next);
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -22,13 +22,18 @@
#include "lopcodes.h"
#include "lparser.h"
#include "ltable.h"
+#include "lnum.h"
#define hasjumps(e) ((e)->t != (e)->f)
-
static int isnumeral(expdesc *e) {
- return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
+ int ek=
+#ifdef LNUM_COMPLEX
+ (e->k == VKNUM2) ||
+#endif
+ (e->k == VKINT) || (e->k == VKNUM);
+ return (ek && e->t == NO_JUMP && e->f == NO_JUMP);
}
@@ -231,12 +236,16 @@ static int addk (FuncState *fs, TValue *
TValue *idx = luaH_set(L, fs->h, k);
Proto *f = fs->f;
int oldsize = f->sizek;
- if (ttisnumber(idx)) {
- lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
- return cast_int(nvalue(idx));
+ if (ttype(idx)==LUA_TNUMBER) {
+ luai_normalize(idx);
+ lua_assert( ttype(idx)==LUA_TINT ); /* had no fraction */
+ }
+ if (ttisint(idx)) {
+ lua_assert(luaO_rawequalObj(&fs->f->k[ivalue(idx)], v));
+ return cast_int(ivalue(idx));
}
else { /* constant not found; create a new entry */
- setnvalue(idx, cast_num(fs->nk));
+ setivalue(idx, fs->nk);
luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
MAXARG_Bx, "constant table overflow");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
@@ -261,6 +270,21 @@ int luaK_numberK (FuncState *fs, lua_Num
}
+int luaK_integerK (FuncState *fs, lua_Integer r) {
+ TValue o;
+ setivalue(&o, r);
+ return addk(fs, &o, &o);
+}
+
+
+#ifdef LNUM_COMPLEX
+static int luaK_imagK (FuncState *fs, lua_Number r) {
+ TValue o;
+ setnvalue_complex(&o, r*I);
+ return addk(fs, &o, &o);
+}
+#endif
+
static int boolK (FuncState *fs, int b) {
TValue o;
setbvalue(&o, b);
@@ -359,6 +383,16 @@ static void discharge2reg (FuncState *fs
luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
break;
}
+ case VKINT: {
+ luaK_codeABx(fs, OP_LOADK, reg, luaK_integerK(fs, e->u.ival));
+ break;
+ }
+#ifdef LNUM_COMPLEX
+ case VKNUM2: {
+ luaK_codeABx(fs, OP_LOADK, reg, luaK_imagK(fs, e->u.nval));
+ break;
+ }
+#endif
case VRELOCABLE: {
Instruction *pc = &getcode(fs, e);
SETARG_A(*pc, reg);
@@ -444,6 +478,10 @@ void luaK_exp2val (FuncState *fs, expdes
int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
switch (e->k) {
+#ifdef LNUM_COMPLEX
+ case VKNUM2:
+#endif
+ case VKINT:
case VKNUM:
case VTRUE:
case VFALSE:
@@ -451,6 +489,10 @@ int luaK_exp2RK (FuncState *fs, expdesc
if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */
e->u.s.info = (e->k == VNIL) ? nilK(fs) :
(e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
+ (e->k == VKINT) ? luaK_integerK(fs, e->u.ival) :
+#ifdef LNUM_COMPLEX
+ (e->k == VKNUM2) ? luaK_imagK(fs, e->u.nval) :
+#endif
boolK(fs, (e->k == VTRUE));
e->k = VK;
return RKASK(e->u.s.info);
@@ -540,7 +582,10 @@ void luaK_goiftrue (FuncState *fs, expde
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
- case VK: case VKNUM: case VTRUE: {
+#ifdef LNUM_COMPLEX
+ case VKNUM2:
+#endif
+ case VKINT: case VK: case VKNUM: case VTRUE: {
pc = NO_JUMP; /* always true; do nothing */
break;
}
@@ -590,7 +635,10 @@ static void codenot (FuncState *fs, expd
e->k = VTRUE;
break;
}
- case VK: case VKNUM: case VTRUE: {
+#ifdef LNUM_COMPLEX
+ case VKNUM2:
+#endif
+ case VKINT: case VK: case VKNUM: case VTRUE: {
e->k = VFALSE;
break;
}
@@ -626,25 +674,70 @@ void luaK_indexed (FuncState *fs, expdes
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
lua_Number v1, v2, r;
+ int vkres= VKNUM;
if (!isnumeral(e1) || !isnumeral(e2)) return 0;
- v1 = e1->u.nval;
- v2 = e2->u.nval;
+
+ /* real and imaginary parts don't mix. */
+#ifdef LNUM_COMPLEX
+ if (e1->k == VKNUM2) {
+ if ((op != OP_UNM) && (e2->k != VKNUM2)) return 0;
+ vkres= VKNUM2; }
+ else if (e2->k == VKNUM2) { return 0; }
+#endif
+ if ((e1->k == VKINT) && (e2->k == VKINT)) {
+ lua_Integer i1= e1->u.ival, i2= e2->u.ival;
+ lua_Integer rr;
+ int done= 0;
+ /* Integer/integer calculations (may end up producing floating point) */
+ switch (op) {
+ case OP_ADD: done= try_addint( &rr, i1, i2 ); break;
+ case OP_SUB: done= try_subint( &rr, i1, i2 ); break;
+ case OP_MUL: done= try_mulint( &rr, i1, i2 ); break;
+ case OP_DIV: done= try_divint( &rr, i1, i2 ); break;
+ case OP_MOD: done= try_modint( &rr, i1, i2 ); break;
+ case OP_POW: done= try_powint( &rr, i1, i2 ); break;
+ case OP_UNM: done= try_unmint( &rr, i1 ); break;
+ default: done= 0; break;
+ }
+ if (done) {
+ e1->u.ival = rr; /* remained within integer range */
+ return 1;
+ }
+ }
+ v1 = (e1->k == VKINT) ? ((lua_Number)e1->u.ival) : e1->u.nval;
+ v2 = (e2->k == VKINT) ? ((lua_Number)e2->u.ival) : e2->u.nval;
+
switch (op) {
case OP_ADD: r = luai_numadd(v1, v2); break;
case OP_SUB: r = luai_numsub(v1, v2); break;
- case OP_MUL: r = luai_nummul(v1, v2); break;
+ case OP_MUL:
+#ifdef LNUM_COMPLEX
+ if (vkres==VKNUM2) return 0; /* leave to runtime (could do here, but not worth it?) */
+#endif
+ r = luai_nummul(v1, v2); break;
case OP_DIV:
if (v2 == 0) return 0; /* do not attempt to divide by 0 */
- r = luai_numdiv(v1, v2); break;
+#ifdef LNUM_COMPLEX
+ if (vkres==VKNUM2) return 0; /* leave to runtime */
+#endif
+ r = luai_numdiv(v1, v2); break;
case OP_MOD:
if (v2 == 0) return 0; /* do not attempt to divide by 0 */
+#ifdef LNUM_COMPLEX
+ if (vkres==VKNUM2) return 0; /* leave to runtime */
+#endif
r = luai_nummod(v1, v2); break;
- case OP_POW: r = luai_numpow(v1, v2); break;
+ case OP_POW:
+#ifdef LNUM_COMPLEX
+ if (vkres==VKNUM2) return 0; /* leave to runtime */
+#endif
+ r = luai_numpow(v1, v2); break;
case OP_UNM: r = luai_numunm(v1); break;
case OP_LEN: return 0; /* no constant folding for 'len' */
default: lua_assert(0); r = 0; break;
}
if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */
+ e1->k = cast(expkind,vkres);
e1->u.nval = r;
return 1;
}
@@ -688,7 +781,8 @@ static void codecomp (FuncState *fs, OpC
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
expdesc e2;
- e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
+ e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
+
switch (op) {
case OPR_MINUS: {
if (!isnumeral(e))
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -71,6 +71,6 @@ LUAI_FUNC void luaK_prefix (FuncState *f
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
-
+LUAI_FUNC int luaK_integerK (FuncState *fs, lua_Integer r);
#endif
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -183,7 +183,7 @@ static void collectvalidlines (lua_State
int *lineinfo = f->l.p->lineinfo;
int i;
for (i=0; i<f->l.p->sizelineinfo; i++)
- setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
+ setbvalue(luaH_setint(L, t, lineinfo[i]), 1);
sethvalue(L, L->top, t);
}
incr_top(L);
@@ -566,7 +566,7 @@ static int isinstack (CallInfo *ci, cons
void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *name = NULL;
- const char *t = luaT_typenames[ttype(o)];
+ const char *t = luaT_typenames[ttype_ext(o)];
const char *kind = (isinstack(L->ci, o)) ?
getobjname(L, L->ci, cast_int(o - L->base), &name) :
NULL;
@@ -594,8 +594,8 @@ void luaG_aritherror (lua_State *L, cons
int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
- const char *t1 = luaT_typenames[ttype(p1)];
- const char *t2 = luaT_typenames[ttype(p2)];
+ const char *t1 = luaT_typenames[ttype_ext(p1)];
+ const char *t2 = luaT_typenames[ttype_ext(p2)];
if (t1[2] == t2[2])
luaG_runerror(L, "attempt to compare two %s values", t1);
else
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -220,9 +220,9 @@ static StkId adjust_varargs (lua_State *
luaD_checkstack(L, p->maxstacksize);
htab = luaH_new(L, nvar, 1); /* create `arg' table */
for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
- setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
+ setobj2n(L, luaH_setint(L, htab, i+1), L->top - nvar + i);
/* store counter in field `n' */
- setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
+ setivalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), nvar);
}
#endif
/* move fixed parameters to final position */
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -52,6 +52,11 @@ static void DumpNumber(lua_Number x, Dum
DumpVar(x,D);
}
+static void DumpInteger(lua_Integer x, DumpState* D)
+{
+ DumpVar(x,D);
+}
+
static void DumpVector(const void* b, int n, size_t size, DumpState* D)
{
DumpInt(n,D);
@@ -93,8 +98,11 @@ static void DumpConstants(const Proto* f
DumpChar(bvalue(o),D);
break;
case LUA_TNUMBER:
- DumpNumber(nvalue(o),D);
+ DumpNumber(nvalue_fast(o),D);
break;
+ case LUA_TINT:
+ DumpInteger(ivalue(o),D);
+ break;
case LUA_TSTRING:
DumpString(rawtsvalue(o),D);
break;
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#define liolib_c
#define LUA_LIB
@@ -18,7 +19,8 @@
#include "lauxlib.h"
#include "lualib.h"
-
+#include "lnum.h"
+#include "llex.h"
#define IO_INPUT 1
#define IO_OUTPUT 2
@@ -269,6 +271,13 @@ static int io_lines (lua_State *L) {
** =======================================================
*/
+/*
+* Many problems if we intend the same 'n' format specifier (see 'file:read()')
+* to work for both FP and integer numbers, without losing their accuracy. So
+* we don't. 'n' reads numbers as floating points, 'i' as integers. Old code
+* remains valid, but won't provide full integer accuracy (this only matters
+* with float FP and/or 64-bit integers).
+*/
static int read_number (lua_State *L, FILE *f) {
lua_Number d;
@@ -282,6 +291,43 @@ static int read_number (lua_State *L, FI
}
}
+static int read_integer (lua_State *L, FILE *f) {
+ lua_Integer i;
+ if (fscanf(f, LUA_INTEGER_SCAN, &i) == 1) {
+ lua_pushinteger(L, i);
+ return 1;
+ }
+ else return 0; /* read fails */
+}
+
+#ifdef LNUM_COMPLEX
+static int read_complex (lua_State *L, FILE *f) {
+ /* NNN / NNNi / NNN+MMMi / NNN-MMMi */
+ lua_Number a,b;
+ if (fscanf(f, LUA_NUMBER_SCAN, &a) == 1) {
+ int c=fgetc(f);
+ switch(c) {
+ case 'i':
+ lua_pushcomplex(L, a*I);
+ return 1;
+ case '+':
+ case '-':
+ /* "i" is consumed if at the end; just 'NNN+MMM' will most likely
+ * behave as if "i" was there? (TBD: test)
+ */
+ if (fscanf(f, LUA_NUMBER_SCAN "i", &b) == 1) {
+ lua_pushcomplex(L, a+ (c=='+' ? b:-b)*I);
+ return 1;
+ }
+ }
+ ungetc( c,f );
+ lua_pushnumber(L,a); /*real part only*/
+ return 1;
+ }
+ return 0; /* read fails */
+}
+#endif
+
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
@@ -355,6 +401,14 @@ static int g_read (lua_State *L, FILE *f
case 'n': /* number */
success = read_number(L, f);
break;
+ case 'i': /* integer (full accuracy) */
+ success = read_integer(L, f);
+ break;
+#ifdef LNUM_COMPLEX
+ case 'c': /* complex */
+ success = read_complex(L, f);
+ break;
+#endif
case 'l': /* line */
success = read_line(L, f);
break;
@@ -415,9 +469,10 @@ static int g_write (lua_State *L, FILE *
int status = 1;
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
- /* optimization: could be done exactly as for strings */
- status = status &&
- fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
+ if (lua_isinteger(L,arg))
+ status = status && fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) > 0;
+ else
+ status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
}
else {
size_t l;
@@ -460,7 +515,7 @@ static int f_setvbuf (lua_State *L) {
static const char *const modenames[] = {"no", "full", "line", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames);
- lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
+ size_t sz = luaL_optint32(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
return pushresult(L, res == 0, NULL);
}
--- a/src/llex.c
+++ b/src/llex.c
@@ -22,6 +22,7 @@
#include "lstring.h"
#include "ltable.h"
#include "lzio.h"
+#include "lnum.h"
@@ -34,13 +35,17 @@
/* ORDER RESERVED */
-const char *const luaX_tokens [] = {
+static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=",
"<number>", "<name>", "<string>", "<eof>",
+ "<integer>",
+#ifdef LNUM_COMPLEX
+ "<number2>",
+#endif
NULL
};
@@ -90,7 +95,11 @@ static const char *txtToken (LexState *l
switch (token) {
case TK_NAME:
case TK_STRING:
+ case TK_INT:
case TK_NUMBER:
+#ifdef LNUM_COMPLEX
+ case TK_NUMBER2:
+#endif
save(ls, '\0');
return luaZ_buffer(ls->buff);
default:
@@ -175,23 +184,27 @@ static void buffreplace (LexState *ls, c
if (p[n] == from) p[n] = to;
}
-
-static void trydecpoint (LexState *ls, SemInfo *seminfo) {
+/* TK_NUMBER (/ TK_NUMBER2) */
+static int trydecpoint (LexState *ls, SemInfo *seminfo) {
/* format error: try to update decimal point separator */
struct lconv *cv = localeconv();
char old = ls->decpoint;
+ int ret;
ls->decpoint = (cv ? cv->decimal_point[0] : '.');
buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */
- if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
+ ret= luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r, NULL);
+ if (!ret) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
luaX_lexerror(ls, "malformed number", TK_NUMBER);
}
+ return ret;
}
-/* LUA_NUMBER */
-static void read_numeral (LexState *ls, SemInfo *seminfo) {
+/* TK_NUMBER / TK_INT (/TK_NUMBER2) */
+static int read_numeral (LexState *ls, SemInfo *seminfo) {
+ int ret;
lua_assert(isdigit(ls->current));
do {
save_and_next(ls);
@@ -202,8 +215,9 @@ static void read_numeral (LexState *ls,
save_and_next(ls);
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
- if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */
- trydecpoint(ls, seminfo); /* try to update decimal point separator */
+ ret= luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r, &seminfo->i );
+ if (!ret) return trydecpoint(ls, seminfo); /* try to update decimal point separator */
+ return ret;
}
@@ -331,6 +345,7 @@ static void read_string (LexState *ls, i
}
+/* char / TK_* */
static int llex (LexState *ls, SemInfo *seminfo) {
luaZ_resetbuffer(ls->buff);
for (;;) {
@@ -402,8 +417,7 @@ static int llex (LexState *ls, SemInfo *
}
else if (!isdigit(ls->current)) return '.';
else {
- read_numeral(ls, seminfo);
- return TK_NUMBER;
+ return read_numeral(ls, seminfo);
}
}
case EOZ: {
@@ -416,8 +430,7 @@ static int llex (LexState *ls, SemInfo *
continue;
}
else if (isdigit(ls->current)) {
- read_numeral(ls, seminfo);
- return TK_NUMBER;
+ return read_numeral(ls, seminfo);
}
else if (isalpha(ls->current) || ls->current == '_') {
/* identifier or reserved word */
--- a/src/llex.h
+++ b/src/llex.h
@@ -29,19 +29,22 @@ enum RESERVED {
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
- TK_NAME, TK_STRING, TK_EOS
+ TK_NAME, TK_STRING, TK_EOS, TK_INT
+#ifdef LNUM_COMPLEX
+ , TK_NUMBER2 /* imaginary constants: Ni */
+#endif
};
/* number of reserved words */
#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
-/* array with token `names' */
-LUAI_DATA const char *const luaX_tokens [];
-
-
+/* SemInfo is a local data structure of 'llex.c', used for carrying a string
+ * or a number. A separate token (TK_*) will tell, how to interpret the data.
+ */
typedef union {
lua_Number r;
+ lua_Integer i;
TString *ts;
} SemInfo; /* semantics information */
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -49,6 +49,7 @@ typedef LUAI_USER_ALIGNMENT_T L_Umaxalig
/* result of a `usual argument conversion' over lua_Number */
typedef LUAI_UACNUMBER l_uacNumber;
+typedef LUAI_UACINTEGER l_uacInteger;
/* internal assertions for in-house debugging */
@@ -80,7 +81,6 @@ typedef LUAI_UACNUMBER l_uacNumber;
#define cast_int(i) cast(int, (i))
-
/*
** type for virtual-machine instructions
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
--- a/src/lmathlib.c
+++ b/src/lmathlib.c
@@ -4,7 +4,6 @@
** See Copyright Notice in lua.h
*/
-
#include <stdlib.h>
#include <math.h>
@@ -16,113 +15,210 @@
#include "lauxlib.h"
#include "lualib.h"
+/* 'luai_vectpow()' as a replacement for 'cpow()'. Defined in the header; we
+ * don't intrude the code libs internal functions.
+ */
+#ifdef LNUM_COMPLEX
+# include "lnum.h"
+#endif
#undef PI
-#define PI (3.14159265358979323846)
-#define RADIANS_PER_DEGREE (PI/180.0)
-
-
+#ifdef LNUM_FLOAT
+# define PI (3.14159265358979323846F)
+#elif defined(M_PI)
+# define PI M_PI
+#else
+# define PI (3.14159265358979323846264338327950288)
+#endif
+#define RADIANS_PER_DEGREE (PI/180)
+
+#undef HUGE
+#ifdef LNUM_FLOAT
+# define HUGE HUGE_VALF
+#elif defined(LNUM_LDOUBLE)
+# define HUGE HUGE_VALL
+#else
+# define HUGE HUGE_VAL
+#endif
static int math_abs (lua_State *L) {
- lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushnumber(L, _LF(cabs) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(fabs) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_sin (lua_State *L) {
- lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(csin) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(sin) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_sinh (lua_State *L) {
- lua_pushnumber(L, sinh(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(csinh) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(sinh) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_cos (lua_State *L) {
- lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(ccos) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(cos) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_cosh (lua_State *L) {
- lua_pushnumber(L, cosh(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(ccosh) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(cosh) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_tan (lua_State *L) {
- lua_pushnumber(L, tan(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(ctan) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(tan) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_tanh (lua_State *L) {
- lua_pushnumber(L, tanh(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(ctanh) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(tanh) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_asin (lua_State *L) {
- lua_pushnumber(L, asin(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(casin) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(asin) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_acos (lua_State *L) {
- lua_pushnumber(L, acos(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(cacos) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(acos) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_atan (lua_State *L) {
- lua_pushnumber(L, atan(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(catan) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(atan) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_atan2 (lua_State *L) {
- lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+ /* scalars only */
+ lua_pushnumber(L, _LF(atan2) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
return 1;
}
static int math_ceil (lua_State *L) {
- lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_Complex v= luaL_checkcomplex(L, 1);
+ lua_pushcomplex(L, _LF(ceil) (_LF(creal)(v)) + _LF(ceil) (_LF(cimag)(v))*I);
+#else
+ lua_pushnumber(L, _LF(ceil) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_floor (lua_State *L) {
- lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_Complex v= luaL_checkcomplex(L, 1);
+ lua_pushcomplex(L, _LF(floor) (_LF(creal)(v)) + _LF(floor) (_LF(cimag)(v))*I);
+#else
+ lua_pushnumber(L, _LF(floor) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
-static int math_fmod (lua_State *L) {
- lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+static int math_fmod (lua_State *L) {
+ /* scalars only */
+ lua_pushnumber(L, _LF(fmod) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
return 1;
}
static int math_modf (lua_State *L) {
- double ip;
- double fp = modf(luaL_checknumber(L, 1), &ip);
+ /* scalars only */
+ lua_Number ip;
+ lua_Number fp = _LF(modf) (luaL_checknumber(L, 1), &ip);
lua_pushnumber(L, ip);
lua_pushnumber(L, fp);
return 2;
}
static int math_sqrt (lua_State *L) {
- lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(csqrt) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(sqrt) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_pow (lua_State *L) {
- lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+#ifdef LNUM_COMPLEX
+ /* C99 'cpow' gives somewhat inaccurate results (i.e. (-1)^2 = -1+1.2246467991474e-16i).
+ * 'luai_vectpow' smoothens such, reusing it is the reason we need to #include "lnum.h".
+ */
+ lua_pushcomplex(L, luai_vectpow(luaL_checkcomplex(L,1), luaL_checkcomplex(L,2)));
+#else
+ lua_pushnumber(L, _LF(pow) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+#endif
return 1;
}
static int math_log (lua_State *L) {
- lua_pushnumber(L, log(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(clog) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(log) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_log10 (lua_State *L) {
- lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ /* Not in standard <complex.h> , but easy to calculate: log_a(x) = log_b(x) / log_b(a)
+ */
+ lua_pushcomplex(L, _LF(clog) (luaL_checkcomplex(L,1)) / _LF(log) (10));
+#else
+ lua_pushnumber(L, _LF(log10) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
static int math_exp (lua_State *L) {
- lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
+#ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(cexp) (luaL_checkcomplex(L,1)));
+#else
+ lua_pushnumber(L, _LF(exp) (luaL_checknumber(L, 1)));
+#endif
return 1;
}
@@ -138,19 +234,20 @@ static int math_rad (lua_State *L) {
static int math_frexp (lua_State *L) {
int e;
- lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
+ lua_pushnumber(L, _LF(frexp) (luaL_checknumber(L, 1), &e));
lua_pushinteger(L, e);
return 2;
}
static int math_ldexp (lua_State *L) {
- lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
+ lua_pushnumber(L, _LF(ldexp) (luaL_checknumber(L, 1), luaL_checkint(L, 2)));
return 1;
}
static int math_min (lua_State *L) {
+ /* scalars only */
int n = lua_gettop(L); /* number of arguments */
lua_Number dmin = luaL_checknumber(L, 1);
int i;
@@ -165,6 +262,7 @@ static int math_min (lua_State *L) {
static int math_max (lua_State *L) {
+ /* scalars only */
int n = lua_gettop(L); /* number of arguments */
lua_Number dmax = luaL_checknumber(L, 1);
int i;
@@ -182,25 +280,20 @@ static int math_random (lua_State *L) {
/* the `%' avoids the (rare) case of r==1, and is needed also because on
some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
- switch (lua_gettop(L)) { /* check number of arguments */
- case 0: { /* no arguments */
- lua_pushnumber(L, r); /* Number between 0 and 1 */
- break;
- }
- case 1: { /* only upper limit */
- int u = luaL_checkint(L, 1);
- luaL_argcheck(L, 1<=u, 1, "interval is empty");
- lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */
- break;
- }
- case 2: { /* lower and upper limits */
- int l = luaL_checkint(L, 1);
- int u = luaL_checkint(L, 2);
- luaL_argcheck(L, l<=u, 2, "interval is empty");
- lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */
- break;
- }
- default: return luaL_error(L, "wrong number of arguments");
+ int n= lua_gettop(L); /* number of arguments */
+ if (n==0) { /* no arguments: range [0,1) */
+ lua_pushnumber(L, r);
+ } else if (n<=2) { /* int range [1,u] or [l,u] */
+ int l= n==1 ? 1 : luaL_checkint(L, 1);
+ int u = luaL_checkint(L, n);
+ int tmp;
+ lua_Number d;
+ luaL_argcheck(L, l<=u, n, "interval is empty");
+ d= _LF(floor)(r*(u-l+1));
+ lua_number2int(tmp,d);
+ lua_pushinteger(L, l+tmp);
+ } else {
+ return luaL_error(L, "wrong number of arguments");
}
return 1;
}
@@ -211,6 +304,66 @@ static int math_randomseed (lua_State *L
return 0;
}
+/*
+* Lua 5.1 does not have acosh, asinh, atanh for scalars (not ANSI C)
+*/
+#if __STDC_VERSION__ >= 199901L
+static int math_acosh (lua_State *L) {
+# ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(cacosh) (luaL_checkcomplex(L,1)));
+# else
+ lua_pushnumber(L, _LF(acosh) (luaL_checknumber(L,1)));
+# endif
+ return 1;
+}
+static int math_asinh (lua_State *L) {
+# ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(casinh) (luaL_checkcomplex(L,1)));
+# else
+ lua_pushnumber(L, _LF(asinh) (luaL_checknumber(L,1)));
+# endif
+ return 1;
+}
+static int math_atanh (lua_State *L) {
+# ifdef LNUM_COMPLEX
+ lua_pushcomplex(L, _LF(catanh) (luaL_checkcomplex(L,1)));
+# else
+ lua_pushnumber(L, _LF(atanh) (luaL_checknumber(L,1)));
+# endif
+ return 1;
+}
+#endif
+
+/*
+ * C99 complex functions, not covered above.
+*/
+#ifdef LNUM_COMPLEX
+static int math_arg (lua_State *L) {
+ lua_pushnumber(L, _LF(carg) (luaL_checkcomplex(L,1)));
+ return 1;
+}
+
+static int math_imag (lua_State *L) {
+ lua_pushnumber(L, _LF(cimag) (luaL_checkcomplex(L,1)));
+ return 1;
+}
+
+static int math_real (lua_State *L) {
+ lua_pushnumber(L, _LF(creal) (luaL_checkcomplex(L,1)));
+ return 1;
+}
+
+static int math_conj (lua_State *L) {
+ lua_pushcomplex(L, _LF(conj) (luaL_checkcomplex(L,1)));
+ return 1;
+}
+
+static int math_proj (lua_State *L) {
+ lua_pushcomplex(L, _LF(cproj) (luaL_checkcomplex(L,1)));
+ return 1;
+}
+#endif
+
static const luaL_Reg mathlib[] = {
{"abs", math_abs},
@@ -241,6 +394,18 @@ static const luaL_Reg mathlib[] = {
{"sqrt", math_sqrt},
{"tanh", math_tanh},
{"tan", math_tan},
+#if __STDC_VERSION__ >= 199901L
+ {"acosh", math_acosh},
+ {"asinh", math_asinh},
+ {"atanh", math_atanh},
+#endif
+#ifdef LNUM_COMPLEX
+ {"arg", math_arg},
+ {"imag", math_imag},
+ {"real", math_real},
+ {"conj", math_conj},
+ {"proj", math_proj},
+#endif
{NULL, NULL}
};
@@ -252,8 +417,10 @@ LUALIB_API int luaopen_math (lua_State *
luaL_register(L, LUA_MATHLIBNAME, mathlib);
lua_pushnumber(L, PI);
lua_setfield(L, -2, "pi");
- lua_pushnumber(L, HUGE_VAL);
+ lua_pushnumber(L, HUGE);
lua_setfield(L, -2, "huge");
+ lua_pushinteger(L, LUA_INTEGER_MAX );
+ lua_setfield(L, -2, "hugeint");
#if defined(LUA_COMPAT_MOD)
lua_getfield(L, -1, "fmod");
lua_setfield(L, -2, "mod");
--- /dev/null
+++ b/src/lnum.c
@@ -0,0 +1,312 @@
+/*
+** $Id: lnum.c,v ... $
+** Internal number model
+** See Copyright Notice in lua.h
+*/
+
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define lnum_c
+#define LUA_CORE
+
+#include "lua.h"
+#include "llex.h"
+#include "lnum.h"
+
+/*
+** lua_real2str converts a (non-complex) number to a string.
+** lua_str2real converts a string to a (non-complex) number.
+*/
+#define lua_real2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
+
+/*
+* Note: Only 'strtod()' is part of ANSI C; others are C99 and
+* may need '--std=c99' compiler setting (at least on Ubuntu 7.10).
+*
+* Visual C++ 2008 Express does not have 'strtof()', nor 'strtold()'.
+* References to '_strtold()' exist but don't compile. It seems best
+* to leave Windows users with DOUBLE only (or compile with MinGW).
+*
+* In practise, using '(long double)strtod' is a risky thing, since
+* it will cause accuracy loss in reading in numbers, and such losses
+* will pile up in later processing. Get a real 'strtold()' or don't
+* use that mode at all.
+*/
+#ifdef LNUM_DOUBLE
+# define lua_str2real strtod
+#elif defined(LNUM_FLOAT)
+# define lua_str2real strtof
+#elif defined(LNUM_LDOUBLE)
+# define lua_str2real strtold
+#endif
+
+#define lua_integer2str(s,v) sprintf((s), LUA_INTEGER_FMT, (v))
+
+/* 's' is expected to be LUAI_MAXNUMBER2STR long (enough for any number)
+*/
+void luaO_num2buf( char *s, const TValue *o )
+{
+ lua_Number n;
+ lua_assert( ttisnumber(o) );
+
+ /* Reason to handle integers differently is not only speed, but accuracy as
+ * well. We want to make any integer tostring() without roundings, at all.
+ */
+ if (ttisint(o)) {
+ lua_integer2str( s, ivalue(o) );
+ return;
+ }
+ n= nvalue_fast(o);
+ lua_real2str(s, n);
+
+#ifdef LNUM_COMPLEX
+ lua_Number n2= nvalue_img_fast(o);
+ if (n2!=0) { /* Postfix with +-Ni */
+ int re0= (n == 0);
+ char *s2= re0 ? s : strchr(s,'\0');
+ if ((!re0) && (n2>0)) *s2++= '+';
+ lua_real2str( s2, n2 );
+ strcat(s2,"i");
+ }
+#endif
+}
+
+/*
+* If a LUA_TNUMBER has integer value, give it.
+*/
+int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref ) {
+ lua_Number d;
+ lua_Integer i;
+
+ lua_assert( ttype(o)==LUA_TNUMBER );
+ lua_assert( ref );
+#ifdef LNUM_COMPLEX
+ if (nvalue_img_fast(o)!=0) return 0;
+#endif
+ d= nvalue_fast(o);
+ lua_number2integer(i, d);
+ if (cast_num(i) == d) {
+ *ref= i; return 1;
+ }
+ return 0;
+}
+
+/*
+ * Lua 5.1.3 (using 'strtod()') allows 0x+hex but not 0+octal. This is good,
+ * and we should NOT use 'autobase' 0 with 'strtoul[l]()' for this reason.
+ *
+ * Lua 5.1.3 allows '0x...' numbers to overflow and lose precision; this is not
+ * good. On Visual C++ 2008, 'strtod()' does not even take them in. Better to
+ * require hex values to fit 'lua_Integer' or give an error that they don't?
+ *
+ * Full hex range (0 .. 0xff..ff) is stored as integers, not to lose any bits.
+ * Numerical value of 0xff..ff will be -1, if used in calculations.
+ *
+ * Returns: TK_INT for a valid integer, '*endptr_ref' updated
+ * TK_NUMBER for seemingly numeric, to be parsed as floating point
+ * 0 for bad characters, not a number (or '0x' out of range)
+ */
+static int luaO_str2i (const char *s, lua_Integer *res, char **endptr_ref) {
+ char *endptr;
+ /* 'v' gets ULONG_MAX on possible overflow (which is > LUA_INTEGER_MAX);
+ * we don't have to check 'errno' here.
+ */
+ unsigned LUA_INTEGER v= lua_str2ul(s, &endptr, 10);
+ if (endptr == s) return 0; /* nothing numeric */
+ if (v==0 && *endptr=='x') {
+ errno= 0; /* needs to be set, 'strtoul[l]' does not clear it */
+ v= lua_str2ul(endptr+1, &endptr, 16); /* retry as hex, unsigned range */
+ if (errno==ERANGE) { /* clamped to 0xff..ff */
+#if (defined(LNUM_INT32) && !defined(LNUM_FLOAT)) || defined(LNUM_LDOUBLE)
+ return TK_NUMBER; /* Allow to be read as floating point (has more integer range) */
+#else
+ return 0; /* Reject the number */
+#endif
+ }
+ } else if ((v > LUA_INTEGER_MAX) || (*endptr && (!isspace(*endptr)))) {
+ return TK_NUMBER; /* not in signed range, or has '.', 'e' etc. trailing */
+ }
+ *res= (lua_Integer)v;
+ *endptr_ref= endptr;
+ return TK_INT;
+}
+
+/* 0 / TK_NUMBER / TK_INT (/ TK_NUMBER2) */
+int luaO_str2d (const char *s, lua_Number *res_n, lua_Integer *res_i) {
+ char *endptr;
+ int ret= TK_NUMBER;
+ /* Check integers first, if caller is allowing.
+ * If 'res2'==NULL, they're only looking for floating point.
+ */
+ if (res_i) {
+ ret= luaO_str2i(s,res_i,&endptr);
+ if (ret==0) return 0;
+ }
+ if (ret==TK_NUMBER) {
+ lua_assert(res_n);
+ /* Note: Visual C++ 2008 Express 'strtod()' does not read in "0x..."
+ * numbers; it will read '0' and spit 'x' as endptr.
+ * This means hex constants not fitting in 'lua_Integer' won't
+ * be read in at all. What to do?
+ */
+ *res_n = lua_str2real(s, &endptr);
+ if (endptr == s) return 0; /* conversion failed */
+ /* Visual C++ 2008 'strtod()' does not allow "0x..." input. */
+#if defined(_MSC_VER) && !defined(LNUM_FLOAT) && !defined(LNUM_INT64)
+ if (*res_n==0 && *endptr=='x') {
+ /* Hex constant too big for 'lua_Integer' but that could fit in 'lua_Number'
+ * integer bits
+ */
+ unsigned __int64 v= _strtoui64( s, &endptr, 16 );
+ /* We just let > 64 bit values be clamped to _UI64_MAX (MSDN does not say 'errno'==ERANGE would be set) */
+ *res_n= cast_num(v);
+ if (*res_n != v) return 0; /* Would have lost accuracy */
+ }
+#endif
+#ifdef LNUM_COMPLEX
+ if (*endptr == 'i') { endptr++; ret= TK_NUMBER2; }
+#endif
+ }
+ if (*endptr) {
+ while (isspace(cast(unsigned char, *endptr))) endptr++;
+ if (*endptr) return 0; /* invalid trail */
+ }
+ return ret;
+}
+
+
+/* Functions for finding out, when integer operations remain in range
+ * (and doing them).
+ */
+int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
+ lua_Integer v= ib+ic; /* may overflow */
+ if (ib>0 && ic>0) { if (v < 0) return 0; /*overflow, use floats*/ }
+ else if (ib<0 && ic<0) { if (v >= 0) return 0; }
+ *r= v;
+ return 1;
+}
+
+int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
+ lua_Integer v= ib-ic; /* may overflow */
+ if (ib>=0 && ic<0) { if (v < 0) return 0; /*overflow, use floats*/ }
+ else if (ib<0 && ic>0) { if (v >= 0) return 0; }
+ *r= v;
+ return 1;
+}
+
+int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
+ if (ib!=LUA_INTEGER_MIN && ic!=LUA_INTEGER_MIN) {
+ lua_Integer b= luai_abs(ib), c= luai_abs(ic);
+ if ( (ib==0) || (LUA_INTEGER_MAX/b >= c) ) {
+ *r= ib*ic; /* no overflow */
+ return 1;
+ }
+ } else if (ib==0 || ic==0) {
+ *r= 0; return 1;
+ }
+
+ /* Result can be LUA_INTEGER_MIN; if it is, calculating it using floating
+ * point will not cause accuracy loss.
+ */
+ if ( luai_nummul( cast_num(ib), cast_num(ic) ) == LUA_INTEGER_MIN ) {
+ *r= LUA_INTEGER_MIN;
+ return 1;
+ }
+ return 0;
+}
+
+int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
+ /* N/0: leave to float side, to give an error
+ */
+ if (ic==0) return 0;
+
+ /* N/LUA_INTEGER_MIN: always non-integer results, or 0 or +1
+ */
+ if (ic==LUA_INTEGER_MIN) {
+ if (ib==LUA_INTEGER_MIN) { *r=1; return 1; }
+ if (ib==0) { *r=0; return 1; }
+
+ /* LUA_INTEGER_MIN (-2^31|63)/N: calculate using float side (either the division
+ * causes non-integer results, or there is no accuracy loss in int->fp->int
+ * conversions (N=2,4,8,..,256 and N=2^30,2^29,..2^23).
+ */
+ } else if (ib==LUA_INTEGER_MIN) {
+ lua_Number d= luai_numdiv( cast_num(LUA_INTEGER_MIN), cast_num(ic) );
+ lua_Integer i; lua_number2integer(i,d);
+ if (cast_num(i)==d) { *r= i; return 1; }
+
+ } else {
+ /* Note: We _can_ use ANSI C mod here, even on negative values, since
+ * we only test for == 0 (the sign would be implementation dependent).
+ */
+ if (ib%ic == 0) { *r= ib/ic; return 1; }
+ }
+
+ return 0;
+}
+
+int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
+ if (ic!=0) {
+ /* ANSI C can be trusted when b%c==0, or when values are non-negative.
+ * b - (floor(b/c) * c)
+ * -->
+ * + +: b - (b/c) * c (b % c can be used)
+ * - -: b - (b/c) * c (b % c could work, but not defined by ANSI C)
+ * 0 -: b - (b/c) * c (=0, b % c could work, but not defined by ANSI C)
+ * - +: b - (b/c-1) * c (when b!=-c)
+ * + -: b - (b/c-1) * c (when b!=-c)
+ *
+ * o MIN%MIN ends up 0, via overflow in calcs but that does not matter.
+ * o MIN%MAX ends up MAX-1 (and other such numbers), also after overflow,
+ * but that does not matter, results do.
+ */
+ lua_Integer v= ib % ic;
+ if ( v!=0 && (ib<0 || ic<0) ) {
+ v= ib - ((ib/ic) - ((ib<=0 && ic<0) ? 0:1)) * ic;
+ }
+ /* Result should always have same sign as 2nd argument. (PIL2) */
+ lua_assert( (v<0) ? (ic<0) : (v>0) ? (ic>0) : 1 );
+ *r= v;
+ return 1;
+ }
+ return 0; /* let float side return NaN */
+}
+
+int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
+
+ /* In FLOAT/INT32 or FLOAT|DOUBLE/INT64 modes, calculating integer powers
+ * via FP realm may lose accuracy (i.e. 7^11 = 1977326743, which fits int32
+ * but not 23-bit float mantissa).
+ *
+ * The current solution is dumb, but it works and uses little code. Use of
+ * integer powers is not anticipated to be very frequent (apart from 2^x,
+ * which is separately optimized).
+ */
+ if (ib==0) *r=0;
+ else if (ic<0) return 0; /* FP realm */
+ else if (ib==2 && ic < (int)sizeof(lua_Integer)*8-1) *r= ((lua_Integer)1)<<ic; /* 1,2,4,...2^30 | 2^62 optimization */
+ else if (ic==0) *r=1;
+ else if (luai_abs(ib)==1) *r= (ic%2) ? ib:1;
+ else {
+ lua_Integer x= ib;
+ while( --ic ) {
+ if (!try_mulint( &x, x, ib ))
+ return 0; /* FP realm */
+ }
+ *r= x;
+ }
+ return 1;
+}
+
+int try_unmint( lua_Integer *r, lua_Integer ib ) {
+ /* Negating LUA_INTEGER_MIN leaves the range. */
+ if ( ib != LUA_INTEGER_MIN )
+ { *r= -ib; return 1; }
+ return 0;
+}
+
--- /dev/null
+++ b/src/lnum.h
@@ -0,0 +1,116 @@
+/*
+** $Id: lnum.h,v ... $
+** Internal Number model
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lnum_h
+#define lnum_h
+
+#include <math.h>
+
+#include "lobject.h"
+
+/*
+** The luai_num* macros define the primitive operations over 'lua_Number's
+** (not 'lua_Integer's, not 'lua_Complex').
+*/
+#define luai_numadd(a,b) ((a)+(b))
+#define luai_numsub(a,b) ((a)-(b))
+#define luai_nummul(a,b) ((a)*(b))
+#define luai_numdiv(a,b) ((a)/(b))
+#define luai_nummod(a,b) ((a) - _LF(floor)((a)/(b))*(b))
+#define luai_numpow(a,b) (_LF(pow)(a,b))
+#define luai_numunm(a) (-(a))
+#define luai_numeq(a,b) ((a)==(b))
+#define luai_numlt(a,b) ((a)<(b))
+#define luai_numle(a,b) ((a)<=(b))
+#define luai_numisnan(a) (!luai_numeq((a), (a)))
+
+int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
+int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
+int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
+int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
+int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
+int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
+int try_unmint( lua_Integer *r, lua_Integer ib );
+
+#ifdef LNUM_COMPLEX
+ static inline lua_Complex luai_vectunm( lua_Complex a ) { return -a; }
+ static inline lua_Complex luai_vectadd( lua_Complex a, lua_Complex b ) { return a+b; }
+ static inline lua_Complex luai_vectsub( lua_Complex a, lua_Complex b ) { return a-b; }
+ static inline lua_Complex luai_vectmul( lua_Complex a, lua_Complex b ) { return a*b; }
+ static inline lua_Complex luai_vectdiv( lua_Complex a, lua_Complex b ) { return a/b; }
+
+/*
+ * C99 does not provide modulus for complex numbers. It most likely is not
+ * meaningful at all.
+ */
+
+/*
+ * Complex power
+ *
+ * C99 'cpow' gives inaccurate results for many common cases s.a. (1i)^2 ->
+ * -1+1.2246467991474e-16i (OS X 10.4, gcc 4.0.1 build 5367)
+ *
+ * [(a+bi)^(c+di)] = (r^c) * exp(-d*t) * cos(c*t + d*ln(r)) +
+ * = (r^c) * exp(-d*t) * sin(c*t + d*ln(r)) *i
+ * r = sqrt(a^2+b^2), t = arctan( b/a )
+ *
+ * Reference: <http://home.att.net/~srschmitt/complexnumbers.html>
+ * Could also be calculated using: x^y = exp(ln(x)*y)
+ *
+ * Note: Defined here (and not in .c) so 'lmathlib.c' can share the
+ * implementation.
+ */
+ static inline
+ lua_Complex luai_vectpow( lua_Complex a, lua_Complex b )
+ {
+# if 1
+ lua_Number ar= _LF(creal)(a), ai= _LF(cimag)(a);
+ lua_Number br= _LF(creal)(b), bi= _LF(cimag)(b);
+
+ if (ai==0 && bi==0) { /* a^c (real) */
+ return luai_numpow( ar, br );
+ }
+
+ int br_int= (int)br;
+
+ if ( ai!=0 && bi==0 && br_int==br && br_int!=0 && br_int!=INT_MIN ) {
+ /* (a+bi)^N, N = { +-1,+-2, ... +-INT_MAX }
+ */
+ lua_Number k= luai_numpow( _LF(sqrt) (ar*ar + ai*ai), br );
+ lua_Number cos_z, sin_z;
+
+ /* Situation depends upon c (N) in the following manner:
+ *
+ * N%4==0 => cos(c*t)=1, sin(c*t)=0
+ * (N*sign(b))%4==1 or (N*sign(b))%4==-3 => cos(c*t)=0, sin(c*t)=1
+ * N%4==2 or N%4==-2 => cos(c*t)=-1, sin(c*t)=0
+ * (N*sign(b))%4==-1 or (N*sign(b))%4==3 => cos(c*t)=0, sin(c*t)=-1
+ */
+ int br_int_abs = br_int<0 ? -br_int:br_int;
+
+ switch( (br_int_abs%4) * (br_int<0 ? -1:1) * (ai<0 ? -1:1) ) {
+ case 0: cos_z=1, sin_z=0; break;
+ case 2: case -2: cos_z=-1, sin_z=0; break;
+ case 1: case -3: cos_z=0, sin_z=1; break;
+ case 3: case -1: cos_z=0, sin_z=-1; break;
+ default: lua_assert(0); return 0;
+ }
+ return k*cos_z + (k*sin_z)*I;
+ }
+# endif
+ return _LF(cpow) ( a, b );
+ }
+#endif
+
+LUAI_FUNC int luaO_str2d (const char *s, lua_Number *res1, lua_Integer *res2);
+LUAI_FUNC void luaO_num2buf( char *s, const TValue *o );
+
+LUAI_FUNC int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref );
+
+#define luai_normalize(o) \
+{ lua_Integer _i; if (tt_integer_valued(o,&_i)) setivalue(o,_i); }
+
+#endif
--- /dev/null
+++ b/src/lnum_config.h
@@ -0,0 +1,221 @@
+/*
+** $Id: lnum_config.h,v ... $
+** Internal Number model
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lnum_config_h
+#define lnum_config_h
+
+/*
+** Default number modes
+*/
+#if (!defined LNUM_DOUBLE) && (!defined LNUM_FLOAT) && (!defined LNUM_LDOUBLE)
+# define LNUM_FLOAT
+#endif
+#if (!defined LNUM_INT16) && (!defined LNUM_INT32) && (!defined LNUM_INT64)
+# define LNUM_INT32
+#endif
+
+/*
+** Require C99 mode for COMPLEX, FLOAT and LDOUBLE (only DOUBLE is ANSI C).
+*/
+#if defined(LNUM_COMPLEX) && (__STDC_VERSION__ < 199901L)
+# error "Need C99 for complex (use '--std=c99' or similar)"
+#elif defined(LNUM_LDOUBLE) && (__STDC_VERSION__ < 199901L) && !defined(_MSC_VER)
+# error "Need C99 for 'long double' (use '--std=c99' or similar)"
+#elif defined(LNUM_FLOAT) && (__STDC_VERSION__ < 199901L)
+/* LNUM_FLOAT not supported on Windows */
+# error "Need C99 for 'float' (use '--std=c99' or similar)"
+#endif
+
+/*
+** Number mode identifier to accompany the version string.
+*/
+#ifdef LNUM_COMPLEX
+# define _LNUM1 "complex "
+#else
+# define _LNUM1 ""
+#endif
+#ifdef LNUM_DOUBLE
+# define _LNUM2 "double"
+#elif defined(LNUM_FLOAT)
+# define _LNUM2 "float"
+#elif defined(LNUM_LDOUBLE)
+# define _LNUM2 "ldouble"
+#endif
+#ifdef LNUM_INT32
+# define _LNUM3 "int32"
+#elif defined(LNUM_INT64)
+# define _LNUM3 "int64"
+#elif defined(LNUM_INT16)
+# define _LNUM3 "int16"
+#endif
+#define LUA_LNUM _LNUM1 _LNUM2 " " _LNUM3
+
+/*
+** LUA_NUMBER is the type of floating point number in Lua
+** LUA_NUMBER_SCAN is the format for reading numbers.
+** LUA_NUMBER_FMT is the format for writing numbers.
+*/
+#ifdef LNUM_FLOAT
+# define LUA_NUMBER float
+# define LUA_NUMBER_SCAN "%f"
+# define LUA_NUMBER_FMT "%g"
+#elif (defined LNUM_DOUBLE)
+# define LUA_NUMBER double
+# define LUA_NUMBER_SCAN "%lf"
+# define LUA_NUMBER_FMT "%.14g"
+#elif (defined LNUM_LDOUBLE)
+# define LUA_NUMBER long double
+# define LUA_NUMBER_SCAN "%Lg"
+# define LUA_NUMBER_FMT "%.20Lg"
+#endif
+
+
+/*
+** LUAI_MAXNUMBER2STR: size of a buffer fitting any number->string result.
+**
+** double: 24 (sign, x.xxxxxxxxxxxxxxe+nnnn, and \0)
+** int64: 21 (19 digits, sign, and \0)
+** long double: 43 for 128-bit (sign, x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe+nnnn, and \0)
+** 30 for 80-bit (sign, x.xxxxxxxxxxxxxxxxxxxxe+nnnn, and \0)
+*/
+#ifdef LNUM_LDOUBLE
+# define _LUAI_MN2S 44
+#else
+# define _LUAI_MN2S 24
+#endif
+
+#ifdef LNUM_COMPLEX
+# define LUAI_MAXNUMBER2STR (2*_LUAI_MN2S)
+#else
+# define LUAI_MAXNUMBER2STR _LUAI_MN2S
+#endif
+
+/*
+** LUA_INTEGER is the integer type used by lua_pushinteger/lua_tointeger/lua_isinteger.
+** LUA_INTEGER_SCAN is the format for reading integers
+** LUA_INTEGER_FMT is the format for writing integers
+**
+** Note: Visual C++ 2005 does not have 'strtoull()', use '_strtoui64()' instead.
+*/
+#ifdef LNUM_INT32
+# if LUAI_BITSINT > 16
+# define LUA_INTEGER int
+# define LUA_INTEGER_SCAN "%d"
+# define LUA_INTEGER_FMT "%d"
+# else
+/* Note: 'LUA_INTEGER' being 'ptrdiff_t' (as in Lua 5.1) causes problems with
+ * 'printf()' operations. Also 'unsigned ptrdiff_t' is invalid.
+ */
+# define LUA_INTEGER long
+# define LUA_INTEGER_SCAN "%ld"
+# define LUA_INTEGER_FMT "%ld"
+# endif
+# define LUA_INTEGER_MAX 0x7FFFFFFF /* 2^31-1 */
+/* */
+#elif defined(LNUM_INT64)
+# define LUA_INTEGER long long
+# ifdef _MSC_VER
+# define lua_str2ul _strtoui64
+# else
+# define lua_str2ul strtoull
+# endif
+# define LUA_INTEGER_SCAN "%lld"
+# define LUA_INTEGER_FMT "%lld"
+# define LUA_INTEGER_MAX 0x7fffffffffffffffLL /* 2^63-1 */
+# define LUA_INTEGER_MIN (-LUA_INTEGER_MAX - 1LL) /* -2^63 */
+/* */
+#elif defined(LNUM_INT16)
+# if LUAI_BITSINT > 16
+# define LUA_INTEGER short
+# define LUA_INTEGER_SCAN "%hd"
+# define LUA_INTEGER_FMT "%hd"
+# else
+# define LUA_INTEGER int
+# define LUA_INTEGER_SCAN "%d"
+# define LUA_INTEGER_FMT "%d"
+# endif
+# define LUA_INTEGER_MAX 0x7FFF /* 2^16-1 */
+#endif
+
+#ifndef lua_str2ul
+# define lua_str2ul (unsigned LUA_INTEGER)strtoul
+#endif
+#ifndef LUA_INTEGER_MIN
+# define LUA_INTEGER_MIN (-LUA_INTEGER_MAX -1) /* -2^16|32 */
+#endif
+
+/*
+@@ lua_number2int is a macro to convert lua_Number to int.
+@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
+** CHANGE them if you know a faster way to convert a lua_Number to
+** int (with any rounding method and without throwing errors) in your
+** system. In Pentium machines, a naive typecast from double to int
+** in C is extremely slow, so any alternative is worth trying.
+*/
+
+/* On a Pentium, resort to a trick */
+#if defined(LNUM_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
+ (defined(__i386) || defined (_M_IX86) || defined(__i386__))
+
+/* On a Microsoft compiler, use assembler */
+# if defined(_MSC_VER)
+# define lua_number2int(i,d) __asm fld d __asm fistp i
+# else
+
+/* the next trick should work on any Pentium, but sometimes clashes
+ with a DirectX idiosyncrasy */
+union luai_Cast { double l_d; long l_l; };
+# define lua_number2int(i,d) \
+ { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
+# endif
+
+# ifndef LNUM_INT64
+# define lua_number2integer lua_number2int
+# endif
+
+/* this option always works, but may be slow */
+#else
+# define lua_number2int(i,d) ((i)=(int)(d))
+#endif
+
+/* Note: Some compilers (OS X gcc 4.0?) may choke on double->long long conversion
+ * since it can lose precision. Others do require 'long long' there.
+ */
+#ifndef lua_number2integer
+# define lua_number2integer(i,d) ((i)=(lua_Integer)(d))
+#endif
+
+/*
+** 'luai_abs()' to give absolute value of 'lua_Integer'
+*/
+#ifdef LNUM_INT32
+# define luai_abs abs
+#elif defined(LNUM_INT64) && (__STDC_VERSION__ >= 199901L)
+# define luai_abs llabs
+#else
+# define luai_abs(v) ((v) >= 0 ? (v) : -(v))
+#endif
+
+/*
+** LUAI_UACNUMBER is the result of an 'usual argument conversion' over a number.
+** LUAI_UACINTEGER the same, over an integer.
+*/
+#define LUAI_UACNUMBER double
+#define LUAI_UACINTEGER long
+
+/* ANSI C only has math funcs for 'double. C99 required for float and long double
+ * variants.
+ */
+#ifdef LNUM_DOUBLE
+# define _LF(name) name
+#elif defined(LNUM_FLOAT)
+# define _LF(name) name ## f
+#elif defined(LNUM_LDOUBLE)
+# define _LF(name) name ## l
+#endif
+
+#endif
+
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -21,7 +21,8 @@
#include "lstate.h"
#include "lstring.h"
#include "lvm.h"
-
+#include "llex.h"
+#include "lnum.h"
const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL};
@@ -70,12 +71,31 @@ int luaO_log2 (unsigned int x) {
int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
- if (ttype(t1) != ttype(t2)) return 0;
+ if (!ttype_ext_same(t1,t2)) return 0;
else switch (ttype(t1)) {
case LUA_TNIL:
return 1;
+ case LUA_TINT:
+ if (ttype(t2)==LUA_TINT)
+ return ivalue(t1) == ivalue(t2);
+ else { /* t1:int, t2:num */
+#ifdef LNUM_COMPLEX
+ if (nvalue_img_fast(t2) != 0) return 0;
+#endif
+ /* Avoid doing accuracy losing cast, if possible. */
+ lua_Integer tmp;
+ if (tt_integer_valued(t2,&tmp))
+ return ivalue(t1) == tmp;
+ else
+ return luai_numeq( cast_num(ivalue(t1)), nvalue_fast(t2) );
+ }
case LUA_TNUMBER:
- return luai_numeq(nvalue(t1), nvalue(t2));
+ if (ttype(t2)==LUA_TINT)
+ return luaO_rawequalObj(t2, t1); /* swap LUA_TINT to left */
+#ifdef LNUM_COMPLEX
+ if (!luai_numeq(nvalue_img_fast(t1), nvalue_img_fast(t2))) return 0;
+#endif
+ return luai_numeq(nvalue_fast(t1), nvalue_fast(t2));
case LUA_TBOOLEAN:
return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */
case LUA_TLIGHTUSERDATA:
@@ -86,21 +106,6 @@ int luaO_rawequalObj (const TValue *t1,
}
}
-
-int luaO_str2d (const char *s, lua_Number *result) {
- char *endptr;
- *result = lua_str2number(s, &endptr);
- if (endptr == s) return 0; /* conversion failed */
- if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */
- *result = cast_num(strtoul(s, &endptr, 16));
- if (*endptr == '\0') return 1; /* most common case */
- while (isspace(cast(unsigned char, *endptr))) endptr++;
- if (*endptr != '\0') return 0; /* invalid trailing characters? */
- return 1;
-}
-
-
-
static void pushstr (lua_State *L, const char *str) {
setsvalue2s(L, L->top, luaS_new(L, str));
incr_top(L);
@@ -131,7 +136,11 @@ const char *luaO_pushvfstring (lua_State
break;
}
case 'd': {
- setnvalue(L->top, cast_num(va_arg(argp, int)));
+ /* This is tricky for 64-bit integers; maybe they even cannot be
+ * supported on all compilers; depends on the conversions applied to
+ * variable argument lists. TBD: test!
+ */
+ setivalue(L->top, (lua_Integer) va_arg(argp, l_uacInteger));
incr_top(L);
break;
}
@@ -212,3 +221,4 @@ void luaO_chunkid (char *out, const char
}
}
}
+
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -17,7 +17,11 @@
/* tags for values visible from Lua */
-#define LAST_TAG LUA_TTHREAD
+#if LUA_TINT > LUA_TTHREAD
+# define LAST_TAG LUA_TINT
+#else
+# define LAST_TAG LUA_TTHREAD
+#endif
#define NUM_TAGS (LAST_TAG+1)
@@ -59,7 +63,12 @@ typedef struct GCheader {
typedef union {
GCObject *gc;
void *p;
+#ifdef LNUM_COMPLEX
+ lua_Complex n;
+#else
lua_Number n;
+#endif
+ lua_Integer i;
int b;
} Value;
@@ -77,7 +86,11 @@ typedef struct lua_TValue {
/* Macros to test type */
#define ttisnil(o) (ttype(o) == LUA_TNIL)
-#define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
+#define ttisint(o) (ttype(o) == LUA_TINT)
+#define ttisnumber(o) ((ttype(o) == LUA_TINT) || (ttype(o) == LUA_TNUMBER))
+#ifdef LNUM_COMPLEX
+# define ttiscomplex(o) ((ttype(o) == LUA_TNUMBER) && (nvalue_img_fast(o)!=0))
+#endif
#define ttisstring(o) (ttype(o) == LUA_TSTRING)
#define ttistable(o) (ttype(o) == LUA_TTABLE)
#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
@@ -90,7 +103,25 @@ typedef struct lua_TValue {
#define ttype(o) ((o)->tt)
#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
-#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
+
+#define ttype_ext(o) ( ttype(o) == LUA_TINT ? LUA_TNUMBER : ttype(o) )
+#define ttype_ext_same(o1,o2) ( (ttype(o1)==ttype(o2)) || (ttisnumber(o1) && ttisnumber(o2)) )
+
+/* '_fast' variants are for cases where 'ttype(o)' is known to be LUA_TNUMBER.
+ */
+#ifdef LNUM_COMPLEX
+# define nvalue_complex_fast(o) check_exp( ttype(o)==LUA_TNUMBER, (o)->value.n )
+# define nvalue_fast(o) ( _LF(creal) ( nvalue_complex_fast(o) ) )
+# define nvalue_img_fast(o) ( _LF(cimag) ( nvalue_complex_fast(o) ) )
+# define nvalue_complex(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? (o)->value.i : (o)->value.n )
+# define nvalue_img(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? 0 : _LF(cimag)( (o)->value.n ) )
+# define nvalue(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? cast_num((o)->value.i) : _LF(creal)((o)->value.n) )
+#else
+# define nvalue(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? cast_num((o)->value.i) : (o)->value.n )
+# define nvalue_fast(o) check_exp( ttype(o)==LUA_TNUMBER, (o)->value.n )
+#endif
+#define ivalue(o) check_exp( ttype(o)==LUA_TINT, (o)->value.i )
+
#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
#define tsvalue(o) (&rawtsvalue(o)->tsv)
#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u)
@@ -116,8 +147,27 @@ typedef struct lua_TValue {
/* Macros to set values */
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
-#define setnvalue(obj,x) \
- { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
+/* Must not have side effects, 'x' may be expression.
+*/
+#define setivalue(obj,x) \
+ { TValue *i_o=(obj); i_o->value.i=(x); i_o->tt=LUA_TINT; }
+
+# define setnvalue(obj,x) \
+ { TValue *i_o=(obj); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; }
+
+/* Note: Complex always has "inline", both are C99.
+*/
+#ifdef LNUM_COMPLEX
+ static inline void setnvalue_complex_fast( TValue *obj, lua_Complex x ) {
+ lua_assert( _LF(cimag)(x) != 0 );
+ obj->value.n= x; obj->tt= LUA_TNUMBER;
+ }
+ static inline void setnvalue_complex( TValue *obj, lua_Complex x ) {
+ if (_LF(cimag)(x) == 0) { setnvalue(obj, _LF(creal)(x)); }
+ else { obj->value.n= x; obj->tt= LUA_TNUMBER; }
+ }
+#endif
+
#define setpvalue(obj,x) \
{ TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
@@ -155,9 +205,6 @@ typedef struct lua_TValue {
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
checkliveness(G(L),i_o); }
-
-
-
#define setobj(L,obj1,obj2) \
{ const TValue *o2=(obj2); TValue *o1=(obj1); \
o1->value = o2->value; o1->tt=o2->tt; \
@@ -185,8 +232,11 @@ typedef struct lua_TValue {
#define setttype(obj, tt) (ttype(obj) = (tt))
-
-#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
+#if LUA_TINT >= LUA_TSTRING
+# define iscollectable(o) ((ttype(o) >= LUA_TSTRING) && (ttype(o) != LUA_TINT))
+#else
+# define iscollectable(o) (ttype(o) >= LUA_TSTRING)
+#endif
@@ -370,12 +420,10 @@ LUAI_FUNC int luaO_log2 (unsigned int x)
LUAI_FUNC int luaO_int2fb (unsigned int x);
LUAI_FUNC int luaO_fb2int (int x);
LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
-LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
va_list argp);
LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
-
#endif
--- a/src/loslib.c
+++ b/src/loslib.c
@@ -186,15 +186,30 @@ static int os_time (lua_State *L) {
}
if (t == (time_t)(-1))
lua_pushnil(L);
- else
- lua_pushnumber(L, (lua_Number)t);
+ else {
+ /* On float systems the pushed value must be an integer, NOT a number.
+ * Otherwise, accuracy is lost in the time_t->float conversion.
+ */
+#ifdef LNUM_FLOAT
+ lua_pushinteger(L, (lua_Integer) t);
+#else
+ lua_pushnumber(L, (lua_Number) t);
+#endif
+ }
return 1;
}
static int os_difftime (lua_State *L) {
+#ifdef LNUM_FLOAT
+ lua_Integer i= (lua_Integer)
+ difftime( (time_t)(luaL_checkinteger(L, 1)),
+ (time_t)(luaL_optinteger(L, 2, 0)));
+ lua_pushinteger(L, i);
+#else
lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
(time_t)(luaL_optnumber(L, 2, 0))));
+#endif
return 1;
}
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -33,7 +33,6 @@
#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m)
-
/*
** nodes for block list (list of active blocks)
*/
@@ -72,7 +71,7 @@ static void errorlimit (FuncState *fs, i
const char *msg = (fs->f->linedefined == 0) ?
luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
- fs->f->linedefined, limit, what);
+ (fs->f->linedefined), limit, what);
luaX_lexerror(fs->ls, msg, 0);
}
@@ -733,6 +732,18 @@ static void simpleexp (LexState *ls, exp
v->u.nval = ls->t.seminfo.r;
break;
}
+ case TK_INT: {
+ init_exp(v, VKINT, 0);
+ v->u.ival = ls->t.seminfo.i;
+ break;
+ }
+#ifdef LNUM_COMPLEX
+ case TK_NUMBER2: {
+ init_exp(v, VKNUM2, 0);
+ v->u.nval = ls->t.seminfo.r;
+ break;
+ }
+#endif
case TK_STRING: {
codestring(ls, v, ls->t.seminfo.ts);
break;
@@ -1079,7 +1090,7 @@ static void fornum (LexState *ls, TStrin
if (testnext(ls, ','))
exp1(ls); /* optional step */
else { /* default step = 1 */
- luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
+ luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_integerK(fs, 1));
luaK_reserveregs(fs, 1);
}
forbody(ls, base, line, 1, 1);
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -31,7 +31,11 @@ typedef enum {
VRELOCABLE, /* info = instruction pc */
VNONRELOC, /* info = result register */
VCALL, /* info = instruction pc */
- VVARARG /* info = instruction pc */
+ VVARARG, /* info = instruction pc */
+ VKINT /* ival = integer value */
+#ifdef LNUM_COMPLEX
+ ,VKNUM2 /* nval = imaginary value */
+#endif
} expkind;
typedef struct expdesc {
@@ -39,6 +43,7 @@ typedef struct expdesc {
union {
struct { int info, aux; } s;
lua_Number nval;
+ lua_Integer ival;
} u;
int t; /* patch list of `exit when true' */
int f; /* patch list of `exit when false' */
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -43,8 +43,8 @@ static ptrdiff_t posrelat (ptrdiff_t pos
static int str_sub (lua_State *L) {
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
- ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
- ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
+ ptrdiff_t start = posrelat(luaL_checkint32(L, 2), l);
+ ptrdiff_t end = posrelat(luaL_optint32(L, 3, -1), l);
if (start < 1) start = 1;
if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
if (start <= end)
@@ -106,8 +106,8 @@ static int str_rep (lua_State *L) {
static int str_byte (lua_State *L) {
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
- ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
- ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
+ ptrdiff_t posi = posrelat(luaL_optint32(L, 2, 1), l);
+ ptrdiff_t pose = posrelat(luaL_optint32(L, 3, posi), l);
int n, i;
if (posi <= 0) posi = 1;
if ((size_t)pose > l) pose = l;
@@ -496,7 +496,7 @@ static int str_find_aux (lua_State *L, i
size_t l1, l2;
const char *s = luaL_checklstring(L, 1, &l1);
const char *p = luaL_checklstring(L, 2, &l2);
- ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
+ ptrdiff_t init = posrelat(luaL_optint32(L, 3, 1), l1) - 1;
if (init < 0) init = 0;
else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
if (find && (lua_toboolean(L, 4) || /* explicit request? */
@@ -690,7 +690,7 @@ static int str_gsub (lua_State *L) {
** maximum size of each format specification (such as '%-099.99d')
** (+10 accounts for %99.99x plus margin of error)
*/
-#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
+#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTEGER_FMT)-2 + 10)
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
@@ -747,9 +747,9 @@ static const char *scanformat (lua_State
static void addintlen (char *form) {
size_t l = strlen(form);
char spec = form[l - 1];
- strcpy(form + l - 1, LUA_INTFRMLEN);
- form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
- form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
+ const char *tmp= LUA_INTEGER_FMT; /* "%lld" or "%ld" */
+ strcpy(form + l - 1, tmp+1);
+ form[l + sizeof(LUA_INTEGER_FMT)-4] = spec;
}
@@ -779,12 +779,12 @@ static int str_format (lua_State *L) {
}
case 'd': case 'i': {
addintlen(form);
- sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
+ sprintf(buff, form, luaL_checkinteger(L, arg));
break;
}
case 'o': case 'u': case 'x': case 'X': {
addintlen(form);
- sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
+ sprintf(buff, form, (unsigned LUA_INTEGER)luaL_checkinteger(L, arg));
break;
}
case 'e': case 'E': case 'f':
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -33,6 +33,7 @@
#include "lobject.h"
#include "lstate.h"
#include "ltable.h"
+#include "lnum.h"
/*
@@ -51,25 +52,15 @@
#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
#define hashboolean(t,p) hashpow2(t, p)
-
+#define hashint(t,i) hashpow2(t,i)
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
-
-
#define hashpointer(t,p) hashmod(t, IntPoint(p))
-
-/*
-** number of ints inside a lua_Number
-*/
-#define numints cast_int(sizeof(lua_Number)/sizeof(int))
-
-
-
#define dummynode (&dummynode_)
static const Node dummynode_ = {
@@ -80,27 +71,46 @@ static const Node dummynode_ = {
/*
** hash for lua_Numbers
+**
+** for non-complex modes, never called with 'lua_Integer' value range (s.a. 0)
*/
static Node *hashnum (const Table *t, lua_Number n) {
- unsigned int a[numints];
- int i;
- if (luai_numeq(n, 0)) /* avoid problems with -0 */
- return gnode(t, 0);
- memcpy(a, &n, sizeof(a));
- for (i = 1; i < numints; i++) a[0] += a[i];
- return hashmod(t, a[0]);
+ const unsigned int *p= cast(const unsigned int *,&n);
+ unsigned int sum= *p;
+ unsigned int m= sizeof(lua_Number)/sizeof(int);
+ unsigned int i;
+ /* OS X Intel has 'm'==4 and gives "Bus error" if the last integer of
+ * 'n' is read; the actual size of long double is only 80 bits = 10 bytes.
+ * Linux x86 has 'm'==3, and does not require reduction.
+ */
+#if defined(LNUM_LDOUBLE) && defined(__i386__)
+ if (m>3) m--;
+#endif
+ for (i = 1; i < m; i++) sum += p[i];
+ return hashmod(t, sum);
}
-
/*
** returns the `main' position of an element in a table (that is, the index
** of its hash value)
+**
+** Floating point numbers with integer value give the hash position of the
+** integer (so they use the same table position).
*/
static Node *mainposition (const Table *t, const TValue *key) {
+ lua_Integer i;
switch (ttype(key)) {
case LUA_TNUMBER:
- return hashnum(t, nvalue(key));
+ if (tt_integer_valued(key,&i))
+ return hashint(t, i);
+#ifdef LNUM_COMPLEX
+ if (nvalue_img_fast(key)!=0 && luai_numeq(nvalue_fast(key),0))
+ return gnode(t, 0); /* 0 and -0 to give same hash */
+#endif
+ return hashnum(t, nvalue_fast(key));
+ case LUA_TINT:
+ return hashint(t, ivalue(key));
case LUA_TSTRING:
return hashstr(t, rawtsvalue(key));
case LUA_TBOOLEAN:
@@ -116,16 +126,20 @@ static Node *mainposition (const Table *
/*
** returns the index for `key' if `key' is an appropriate key to live in
** the array part of the table, -1 otherwise.
+**
+** Anything <=0 is taken as not being in the array part.
*/
-static int arrayindex (const TValue *key) {
- if (ttisnumber(key)) {
- lua_Number n = nvalue(key);
- int k;
- lua_number2int(k, n);
- if (luai_numeq(cast_num(k), n))
- return k;
+static int arrayindex (const TValue *key, int max) {
+ lua_Integer k;
+ switch( ttype(key) ) {
+ case LUA_TINT:
+ k= ivalue(key); break;
+ case LUA_TNUMBER:
+ if (tt_integer_valued(key,&k)) break;
+ default:
+ return -1; /* not to be used as array index */
}
- return -1; /* `key' did not match some condition */
+ return ((k>0) && (k <= max)) ? cast_int(k) : -1;
}
@@ -137,8 +151,8 @@ static int arrayindex (const TValue *key
static int findindex (lua_State *L, Table *t, StkId key) {
int i;
if (ttisnil(key)) return -1; /* first iteration */
- i = arrayindex(key);
- if (0 < i && i <= t->sizearray) /* is `key' inside array part? */
+ i = arrayindex(key, t->sizearray);
+ if (i>0) /* inside array part? */
return i-1; /* yes; that's the index (corrected to C) */
else {
Node *n = mainposition(t, key);
@@ -163,7 +177,7 @@ int luaH_next (lua_State *L, Table *t, S
int i = findindex(L, t, key); /* find original element */
for (i++; i < t->sizearray; i++) { /* try first array part */
if (!ttisnil(&t->array[i])) { /* a non-nil value? */
- setnvalue(key, cast_num(i+1));
+ setivalue(key, i+1);
setobj2s(L, key+1, &t->array[i]);
return 1;
}
@@ -209,8 +223,8 @@ static int computesizes (int nums[], int
static int countint (const TValue *key, int *nums) {
- int k = arrayindex(key);
- if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */
+ int k = arrayindex(key,MAXASIZE);
+ if (k>0) { /* appropriate array index? */
nums[ceillog2(k)]++; /* count as such */
return 1;
}
@@ -308,7 +322,7 @@ static void resize (lua_State *L, Table
/* re-insert elements from vanishing slice */
for (i=nasize; i<oldasize; i++) {
if (!ttisnil(&t->array[i]))
- setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
+ setobjt2t(L, luaH_setint(L, t, i+1), &t->array[i]);
}
/* shrink array */
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
@@ -409,7 +423,9 @@ static TValue *newkey (lua_State *L, Tab
othern = mainposition(t, key2tval(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
- while (gnext(othern) != mp) othern = gnext(othern); /* find previous */
+ while (gnext(othern) != mp) {
+ othern = gnext(othern); /* find previous */
+ }
gnext(othern) = n; /* redo the chain with `n' in place of `mp' */
*n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
gnext(mp) = NULL; /* now `mp' is free */
@@ -432,17 +448,18 @@ static TValue *newkey (lua_State *L, Tab
/*
** search function for integers
*/
-const TValue *luaH_getnum (Table *t, int key) {
+const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */
if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
return &t->array[key-1];
else {
- lua_Number nk = cast_num(key);
- Node *n = hashnum(t, nk);
+ Node *n = hashint(t, key);
do { /* check whether `key' is somewhere in the chain */
- if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
+ if (ttisint(gkey(n)) && (ivalue(gkey(n)) == key)) {
return gval(n); /* that's it */
- else n = gnext(n);
+ } else {
+ n = gnext(n);
+ }
} while (n);
return luaO_nilobject;
}
@@ -470,14 +487,12 @@ const TValue *luaH_get (Table *t, const
switch (ttype(key)) {
case LUA_TNIL: return luaO_nilobject;
case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
+ case LUA_TINT: return luaH_getint(t, ivalue(key));
case LUA_TNUMBER: {
- int k;
- lua_Number n = nvalue(key);
- lua_number2int(k, n);
- if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
- return luaH_getnum(t, k); /* use specialized version */
- /* else go through */
- }
+ lua_Integer i;
+ if (tt_integer_valued(key,&i))
+ return luaH_getint(t,i);
+ } /* pass through */
default: {
Node *n = mainposition(t, key);
do { /* check whether `key' is somewhere in the chain */
@@ -498,20 +513,25 @@ TValue *luaH_set (lua_State *L, Table *t
return cast(TValue *, p);
else {
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
- else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
- luaG_runerror(L, "table index is NaN");
+ else if (ttype(key)==LUA_TNUMBER) {
+ lua_Integer k;
+ if (luai_numisnan(nvalue_fast(key)))
+ luaG_runerror(L, "table index is NaN");
+ if (tt_integer_valued(key,&k))
+ return luaH_setint(L, t, k);
+ }
return newkey(L, t, key);
}
}
-TValue *luaH_setnum (lua_State *L, Table *t, int key) {
- const TValue *p = luaH_getnum(t, key);
+TValue *luaH_setint (lua_State *L, Table *t, lua_Integer key) {
+ const TValue *p = luaH_getint(t, key);
if (p != luaO_nilobject)
return cast(TValue *, p);
else {
TValue k;
- setnvalue(&k, cast_num(key));
+ setivalue(&k, key);
return newkey(L, t, &k);
}
}
@@ -533,20 +553,21 @@ static int unbound_search (Table *t, uns
unsigned int i = j; /* i is zero or a present index */
j++;
/* find `i' and `j' such that i is present and j is not */
- while (!ttisnil(luaH_getnum(t, j))) {
+ while (!ttisnil(luaH_getint(t, j))) {
i = j;
j *= 2;
if (j > cast(unsigned int, MAX_INT)) { /* overflow? */
/* table was built with bad purposes: resort to linear search */
- i = 1;
- while (!ttisnil(luaH_getnum(t, i))) i++;
- return i - 1;
+ for( i = 1; i<MAX_INT+1; i++ ) {
+ if (ttisnil(luaH_getint(t, i))) break;
+ }
+ return i - 1; /* up to MAX_INT */
}
}
/* now do a binary search between them */
while (j - i > 1) {
unsigned int m = (i+j)/2;
- if (ttisnil(luaH_getnum(t, m))) j = m;
+ if (ttisnil(luaH_getint(t, m))) j = m;
else i = m;
}
return i;
--- a/src/ltable.h
+++ b/src/ltable.h
@@ -18,8 +18,8 @@
#define key2tval(n) (&(n)->i_key.tvk)
-LUAI_FUNC const TValue *luaH_getnum (Table *t, int key);
-LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
+LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
+LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, lua_Integer key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -19,7 +19,6 @@
#include "ltm.h"
-
const char *const luaT_typenames[] = {
"nil", "boolean", "userdata", "number",
"string", "table", "function", "userdata", "thread",
@@ -67,6 +66,9 @@ const TValue *luaT_gettmbyobj (lua_State
case LUA_TUSERDATA:
mt = uvalue(o)->metatable;
break;
+ case LUA_TINT:
+ mt = G(L)->mt[LUA_TNUMBER];
+ break;
default:
mt = G(L)->mt[ttype(o)];
}
--- a/src/lua.c
+++ b/src/lua.c
@@ -16,7 +16,7 @@
#include "lauxlib.h"
#include "lualib.h"
-
+#include "llimits.h"
static lua_State *globalL = NULL;
@@ -382,6 +382,15 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
+ /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
+ */
+#ifdef LNUM_INT16
+ lua_assert( sizeof(lua_Integer) == 2 );
+#elif defined(LNUM_INT32)
+ lua_assert( sizeof(lua_Integer) == 4 );
+#elif defined(LNUM_INT64)
+ lua_assert( sizeof(lua_Integer) == 8 );
+#endif
s.argc = argc;
s.argv = argv;
status = lua_cpcall(L, &pmain, &s);
--- a/src/lua.h
+++ b/src/lua.h
@@ -19,7 +19,7 @@
#define LUA_VERSION "Lua 5.1"
#define LUA_RELEASE "Lua 5.1.5"
#define LUA_VERSION_NUM 501
-#define LUA_COPYRIGHT "Copyright (C) 1994-2012 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT "Copyright (C) 1994-2012 Lua.org, PUC-Rio" " (" LUA_LNUM ")"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
@@ -71,6 +71,16 @@ typedef void * (*lua_Alloc) (void *ud, v
*/
#define LUA_TNONE (-1)
+/* LUA_TINT is an internal type, not visible to applications. There are three
+ * potential values where it can be tweaked to (code autoadjusts to these):
+ *
+ * -2: not 'usual' type value; good since 'LUA_TINT' is not part of the API
+ * LUA_TNUMBER+1: shifts other type values upwards, breaking binary compatibility
+ * not acceptable for 5.1, maybe 5.2 onwards?
+ * 9: greater than existing (5.1) type values.
+*/
+#define LUA_TINT (-2)
+
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
@@ -139,6 +149,8 @@ LUA_API int (lua_isuserdata)
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
+LUA_API int (lua_isinteger) (lua_State *L, int idx);
+
LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2);
@@ -244,6 +256,19 @@ LUA_API lua_Alloc (lua_getallocf) (lua_S
LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+/*
+* It is unnecessary to break Lua C API 'lua_tonumber()' compatibility, just
+* because the Lua number type is complex. Most C modules would use scalars
+* only. We'll introduce new 'lua_tocomplex' and 'lua_pushcomplex' for when
+* the module really wants to use them.
+*/
+#ifdef LNUM_COMPLEX
+ #include <complex.h>
+ typedef LUA_NUMBER complex lua_Complex;
+ LUA_API lua_Complex (lua_tocomplex) (lua_State *L, int idx);
+ LUA_API void (lua_pushcomplex) (lua_State *L, lua_Complex v);
+#endif
+
/*
** ===============================================================
@@ -268,7 +293,12 @@ LUA_API void lua_setallocf (lua_State *L
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
-#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+
+#if LUA_TINT < 0
+# define lua_isnoneornil(L, n) ( (lua_type(L,(n)) <= 0) && (lua_type(L,(n)) != LUA_TINT) )
+#else
+# define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+#endif
#define lua_pushliteral(L, s) \
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
@@ -386,3 +416,4 @@ struct lua_Debug {
#endif
+
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -10,7 +10,9 @@
#include <limits.h>
#include <stddef.h>
-
+#ifdef lua_assert
+# include <assert.h>
+#endif
/*
** ==================================================================
@@ -136,14 +138,38 @@
/*
-@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
-** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
-** machines, ptrdiff_t gives a good choice between int or long.)
+@@ LUAI_BITSINT defines the number of bits in an int.
+** CHANGE here if Lua cannot automatically detect the number of bits of
+** your machine. Probably you do not need to change this.
*/
-#define LUA_INTEGER ptrdiff_t
+/* avoid overflows in comparison */
+#if INT_MAX-20 < 32760
+#define LUAI_BITSINT 16
+#elif INT_MAX > 2147483640L
+/* int has at least 32 bits */
+#define LUAI_BITSINT 32
+#else
+#error "you must define LUA_BITSINT with number of bits in an integer"
+#endif
/*
+@@ LNUM_DOUBLE | LNUM_FLOAT | LNUM_LDOUBLE: Generic Lua number mode
+@@ LNUM_INT32 | LNUM_INT64: Integer type
+@@ LNUM_COMPLEX: Define for using 'a+bi' numbers
+@@
+@@ You can combine LNUM_xxx but only one of each group. I.e. '-DLNUM_FLOAT
+@@ -DLNUM_INT32 -DLNUM_COMPLEX' gives float range complex numbers, with
+@@ 32-bit scalar integer range optimized.
+**
+** These are kept in a separate configuration file mainly for ease of patching
+** (can be changed if integerated to Lua proper).
+*/
+/*#define LNUM_DOUBLE*/
+/*#define LNUM_INT32*/
+#include "lnum_config.h"
+
+/*
@@ LUA_API is a mark for all core API functions.
@@ LUALIB_API is a mark for all standard library functions.
** CHANGE them if you need to define those functions in some special way.
@@ -383,22 +409,6 @@
/*
-@@ LUAI_BITSINT defines the number of bits in an int.
-** CHANGE here if Lua cannot automatically detect the number of bits of
-** your machine. Probably you do not need to change this.
-*/
-/* avoid overflows in comparison */
-#if INT_MAX-20 < 32760
-#define LUAI_BITSINT 16
-#elif INT_MAX > 2147483640L
-/* int has at least 32 bits */
-#define LUAI_BITSINT 32
-#else
-#error "you must define LUA_BITSINT with number of bits in an integer"
-#endif
-
-
-/*
@@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
@@ LUAI_INT32 is an signed integer with at least 32 bits.
@@ LUAI_UMEM is an unsigned integer big enough to count the total
@@ -425,6 +435,15 @@
#define LUAI_MEM long
#endif
+/*
+@@ LUAI_BOOL carries 0 and nonzero (normally 1). It may be defined as 'char'
+** (to save memory), 'int' (for speed), 'bool' (for C++) or '_Bool' (C99)
+*/
+#ifdef __cplusplus
+# define LUAI_BOOL bool
+#else
+# define LUAI_BOOL int
+#endif
/*
@@ LUAI_MAXCALLS limits the number of nested calls.
@@ -490,101 +509,6 @@
/* }================================================================== */
-
-
-/*
-** {==================================================================
-@@ LUA_NUMBER is the type of numbers in Lua.
-** CHANGE the following definitions only if you want to build Lua
-** with a number type different from double. You may also need to
-** change lua_number2int & lua_number2integer.
-** ===================================================================
-*/
-
-#define LUA_NUMBER_DOUBLE
-#define LUA_NUMBER double
-
-/*
-@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
-@* over a number.
-*/
-#define LUAI_UACNUMBER double
-
-
-/*
-@@ LUA_NUMBER_SCAN is the format for reading numbers.
-@@ LUA_NUMBER_FMT is the format for writing numbers.
-@@ lua_number2str converts a number to a string.
-@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
-@@ lua_str2number converts a string to a number.
-*/
-#define LUA_NUMBER_SCAN "%lf"
-#define LUA_NUMBER_FMT "%.14g"
-#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
-#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
-#define lua_str2number(s,p) strtod((s), (p))
-
-
-/*
-@@ The luai_num* macros define the primitive operations over numbers.
-*/
-#if defined(LUA_CORE)
-#include <math.h>
-#define luai_numadd(a,b) ((a)+(b))
-#define luai_numsub(a,b) ((a)-(b))
-#define luai_nummul(a,b) ((a)*(b))
-#define luai_numdiv(a,b) ((a)/(b))
-#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
-#define luai_numpow(a,b) (pow(a,b))
-#define luai_numunm(a) (-(a))
-#define luai_numeq(a,b) ((a)==(b))
-#define luai_numlt(a,b) ((a)<(b))
-#define luai_numle(a,b) ((a)<=(b))
-#define luai_numisnan(a) (!luai_numeq((a), (a)))
-#endif
-
-
-/*
-@@ lua_number2int is a macro to convert lua_Number to int.
-@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
-** CHANGE them if you know a faster way to convert a lua_Number to
-** int (with any rounding method and without throwing errors) in your
-** system. In Pentium machines, a naive typecast from double to int
-** in C is extremely slow, so any alternative is worth trying.
-*/
-
-/* On a Pentium, resort to a trick */
-#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
- (defined(__i386) || defined (_M_IX86) || defined(__i386__))
-
-/* On a Microsoft compiler, use assembler */
-#if defined(_MSC_VER)
-
-#define lua_number2int(i,d) __asm fld d __asm fistp i
-#define lua_number2integer(i,n) lua_number2int(i, n)
-
-/* the next trick should work on any Pentium, but sometimes clashes
- with a DirectX idiosyncrasy */
-#else
-
-union luai_Cast { double l_d; long l_l; };
-#define lua_number2int(i,d) \
- { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
-#define lua_number2integer(i,n) lua_number2int(i, n)
-
-#endif
-
-
-/* this option always works, but may be slow */
-#else
-#define lua_number2int(i,d) ((i)=(int)(d))
-#define lua_number2integer(i,d) ((i)=(lua_Integer)(d))
-
-#endif
-
-/* }================================================================== */
-
-
/*
@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
** CHANGE it if your system requires alignments larger than double. (For
@@ -728,28 +652,6 @@ union luai_Cast { double l_d; long l_l;
#define luai_userstateyield(L,n) ((void)L)
-/*
-@@ LUA_INTFRMLEN is the length modifier for integer conversions
-@* in 'string.format'.
-@@ LUA_INTFRM_T is the integer type correspoding to the previous length
-@* modifier.
-** CHANGE them if your system supports long long or does not support long.
-*/
-
-#if defined(LUA_USELONGLONG)
-
-#define LUA_INTFRMLEN "ll"
-#define LUA_INTFRM_T long long
-
-#else
-
-#define LUA_INTFRMLEN "l"
-#define LUA_INTFRM_T long
-
-#endif
-
-
-
/* =================================================================== */
/*
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -73,6 +73,13 @@ static lua_Number LoadNumber(LoadState*
return x;
}
+static lua_Integer LoadInteger(LoadState* S)
+{
+ lua_Integer x;
+ LoadVar(S,x);
+ return x;
+}
+
static TString* LoadString(LoadState* S)
{
size_t size;
@@ -119,6 +126,9 @@ static void LoadConstants(LoadState* S,
case LUA_TNUMBER:
setnvalue(o,LoadNumber(S));
break;
+ case LUA_TINT: /* Integer type saved in bytecode (see lcode.c) */
+ setivalue(o,LoadInteger(S));
+ break;
case LUA_TSTRING:
setsvalue2n(S->L,o,LoadString(S));
break;
@@ -223,5 +233,22 @@ void luaU_header (char* h)
*h++=(char)sizeof(size_t);
*h++=(char)sizeof(Instruction);
*h++=(char)sizeof(lua_Number);
- *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */
+
+ /*
+ * Last byte of header (0/1 in unpatched Lua 5.1.3):
+ *
+ * 0: lua_Number is float or double, lua_Integer not used. (nonpatched only)
+ * 1: lua_Number is integer (nonpatched only)
+ *
+ * +2: LNUM_INT16: sizeof(lua_Integer)
+ * +4: LNUM_INT32: sizeof(lua_Integer)
+ * +8: LNUM_INT64: sizeof(lua_Integer)
+ *
+ * +0x80: LNUM_COMPLEX
+ */
+ *h++ = (char)(sizeof(lua_Integer)
+#ifdef LNUM_COMPLEX
+ | 0x80
+#endif
+ );
}
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -25,22 +25,35 @@
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"
-
-
+#include "llex.h"
+#include "lnum.h"
/* limit for table tag-method chains (to avoid loops) */
#define MAXTAGLOOP 100
-const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
- lua_Number num;
+/*
+ * If 'obj' is a string, it is tried to be interpreted as a number.
+ */
+const TValue *luaV_tonumber ( const TValue *obj, TValue *n) {
+ lua_Number d;
+ lua_Integer i;
+
if (ttisnumber(obj)) return obj;
- if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
- setnvalue(n, num);
- return n;
- }
- else
- return NULL;
+
+ if (ttisstring(obj)) {
+ switch( luaO_str2d( svalue(obj), &d, &i ) ) {
+ case TK_INT:
+ setivalue(n,i); return n;
+ case TK_NUMBER:
+ setnvalue(n,d); return n;
+#ifdef LNUM_COMPLEX
+ case TK_NUMBER2: /* "N.NNNi", != 0 */
+ setnvalue_complex_fast(n, d*I); return n;
+#endif
+ }
+ }
+ return NULL;
}
@@ -49,8 +62,7 @@ int luaV_tostring (lua_State *L, StkId o
return 0;
else {
char s[LUAI_MAXNUMBER2STR];
- lua_Number n = nvalue(obj);
- lua_number2str(s, n);
+ luaO_num2buf(s,obj);
setsvalue2s(L, obj, luaS_new(L, s));
return 1;
}
@@ -222,59 +234,127 @@ static int l_strcmp (const TString *ls,
}
+#ifdef LNUM_COMPLEX
+void error_complex( lua_State *L, const TValue *l, const TValue *r )
+{
+ char buf1[ LUAI_MAXNUMBER2STR ];
+ char buf2[ LUAI_MAXNUMBER2STR ];
+ luaO_num2buf( buf1, l );
+ luaO_num2buf( buf2, r );
+ luaG_runerror( L, "unable to compare: %s with %s", buf1, buf2 );
+ /* no return */
+}
+#endif
+
+
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
- if (ttype(l) != ttype(r))
+ int tl,tr;
+ lua_Integer tmp;
+
+ if (!ttype_ext_same(l,r))
return luaG_ordererror(L, l, r);
- else if (ttisnumber(l))
- return luai_numlt(nvalue(l), nvalue(r));
- else if (ttisstring(l))
- return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
- else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+#ifdef LNUM_COMPLEX
+ if ( (nvalue_img(l)!=0) || (nvalue_img(r)!=0) )
+ error_complex( L, l, r );
+#endif
+ tl= ttype(l); tr= ttype(r);
+ if (tl==tr) { /* clear arithmetics */
+ switch(tl) {
+ case LUA_TINT: return ivalue(l) < ivalue(r);
+ case LUA_TNUMBER: return luai_numlt(nvalue_fast(l), nvalue_fast(r));
+ case LUA_TSTRING: return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
+ }
+ } else if (tl==LUA_TINT) { /* l:int, r:num */
+ /* Avoid accuracy losing casts: if 'r' is integer by value, do comparisons
+ * in integer realm. Only otherwise cast 'l' to FP (which might change its
+ * value).
+ */
+ if (tt_integer_valued(r,&tmp))
+ return ivalue(l) < tmp;
+ else
+ return luai_numlt( cast_num(ivalue(l)), nvalue_fast(r) );
+
+ } else if (tl==LUA_TNUMBER) { /* l:num, r:int */
+ if (tt_integer_valued(l,&tmp))
+ return tmp < ivalue(r);
+ else
+ return luai_numlt( nvalue_fast(l), cast_num(ivalue(r)) );
+
+ } else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
return res;
+
return luaG_ordererror(L, l, r);
}
static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
- if (ttype(l) != ttype(r))
+ int tl, tr;
+ lua_Integer tmp;
+
+ if (!ttype_ext_same(l,r))
return luaG_ordererror(L, l, r);
- else if (ttisnumber(l))
- return luai_numle(nvalue(l), nvalue(r));
- else if (ttisstring(l))
- return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
- else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
+#ifdef LNUM_COMPLEX
+ if ( (nvalue_img(l)!=0) || (nvalue_img(r)!=0) )
+ error_complex( L, l, r );
+#endif
+ tl= ttype(l); tr= ttype(r);
+ if (tl==tr) { /* clear arithmetics */
+ switch(tl) {
+ case LUA_TINT: return ivalue(l) <= ivalue(r);
+ case LUA_TNUMBER: return luai_numle(nvalue_fast(l), nvalue_fast(r));
+ case LUA_TSTRING: return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
+ }
+ }
+ if (tl==LUA_TINT) { /* l:int, r:num */
+ if (tt_integer_valued(r,&tmp))
+ return ivalue(l) <= tmp;
+ else
+ return luai_numle( cast_num(ivalue(l)), nvalue_fast(r) );
+
+ } else if (tl==LUA_TNUMBER) { /* l:num, r:int */
+ if (tt_integer_valued(l,&tmp))
+ return tmp <= ivalue(r);
+ else
+ return luai_numle( nvalue_fast(l), cast_num(ivalue(r)) );
+
+ } else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
return res;
else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */
return !res;
+
return luaG_ordererror(L, l, r);
}
-int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
+/* Note: 'luaV_equalval()' and 'luaO_rawequalObj()' have largely overlapping
+ * implementation. LUA_TNIL..LUA_TLIGHTUSERDATA cases could be handled
+ * simply by the 'default' case here.
+ */
+int luaV_equalval (lua_State *L, const TValue *l, const TValue *r) {
const TValue *tm;
- lua_assert(ttype(t1) == ttype(t2));
- switch (ttype(t1)) {
+ lua_assert(ttype_ext_same(l,r));
+ switch (ttype(l)) {
case LUA_TNIL: return 1;
- case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
- case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
- case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
+ case LUA_TINT:
+ case LUA_TNUMBER: return luaO_rawequalObj(l,r);
+ case LUA_TBOOLEAN: return bvalue(l) == bvalue(r); /* true must be 1 !! */
+ case LUA_TLIGHTUSERDATA: return pvalue(l) == pvalue(r);
case LUA_TUSERDATA: {
- if (uvalue(t1) == uvalue(t2)) return 1;
- tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
- TM_EQ);
+ if (uvalue(l) == uvalue(r)) return 1;
+ tm = get_compTM(L, uvalue(l)->metatable, uvalue(r)->metatable, TM_EQ);
break; /* will try TM */
}
case LUA_TTABLE: {
- if (hvalue(t1) == hvalue(t2)) return 1;
- tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
+ if (hvalue(l) == hvalue(r)) return 1;
+ tm = get_compTM(L, hvalue(l)->metatable, hvalue(r)->metatable, TM_EQ);
break; /* will try TM */
}
- default: return gcvalue(t1) == gcvalue(t2);
+ default: return gcvalue(l) == gcvalue(r);
}
if (tm == NULL) return 0; /* no TM? */
- callTMres(L, L->top, tm, t1, t2); /* call TM */
+ callTMres(L, L->top, tm, l, r); /* call TM */
return !l_isfalse(L->top);
}
@@ -314,30 +394,6 @@ void luaV_concat (lua_State *L, int tota
}
-static void Arith (lua_State *L, StkId ra, const TValue *rb,
- const TValue *rc, TMS op) {
- TValue tempb, tempc;
- const TValue *b, *c;
- if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
- (c = luaV_tonumber(rc, &tempc)) != NULL) {
- lua_Number nb = nvalue(b), nc = nvalue(c);
- switch (op) {
- case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
- case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
- case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
- case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
- case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
- case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
- case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
- default: lua_assert(0); break;
- }
- }
- else if (!call_binTM(L, rb, rc, ra, op))
- luaG_aritherror(L, rb, rc);
-}
-
-
-
/*
** some macros for common tasks in `luaV_execute'
*/
@@ -361,17 +417,154 @@ static void Arith (lua_State *L, StkId r
#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; }
-#define arith_op(op,tm) { \
- TValue *rb = RKB(i); \
- TValue *rc = RKC(i); \
- if (ttisnumber(rb) && ttisnumber(rc)) { \
- lua_Number nb = nvalue(rb), nc = nvalue(rc); \
- setnvalue(ra, op(nb, nc)); \
- } \
- else \
- Protect(Arith(L, ra, rb, rc, tm)); \
+/* Note: if called for unary operations, 'rc'=='rb'.
+ */
+static void Arith (lua_State *L, StkId ra, const TValue *rb,
+ const TValue *rc, TMS op) {
+ TValue tempb, tempc;
+ const TValue *b, *c;
+ lua_Number nb,nc;
+
+ if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
+ (c = luaV_tonumber(rc, &tempc)) != NULL) {
+
+ /* Keep integer arithmetics in the integer realm, if possible.
+ */
+ if (ttisint(b) && ttisint(c)) {
+ lua_Integer ib = ivalue(b), ic = ivalue(c);
+ lua_Integer *ri = &ra->value.i;
+ ra->tt= LUA_TINT; /* part of 'setivalue(ra)' */
+ switch (op) {
+ case TM_ADD: if (try_addint( ri, ib, ic)) return; break;
+ case TM_SUB: if (try_subint( ri, ib, ic)) return; break;
+ case TM_MUL: if (try_mulint( ri, ib, ic)) return; break;
+ case TM_DIV: if (try_divint( ri, ib, ic)) return; break;
+ case TM_MOD: if (try_modint( ri, ib, ic)) return; break;
+ case TM_POW: if (try_powint( ri, ib, ic)) return; break;
+ case TM_UNM: if (try_unmint( ri, ib)) return; break;
+ default: lua_assert(0);
}
+ }
+ /* Fallback to floating point, when leaving range. */
+#ifdef LNUM_COMPLEX
+ if ((nvalue_img(b)!=0) || (nvalue_img(c)!=0)) {
+ lua_Complex r;
+ if (op==TM_UNM) {
+ r= -nvalue_complex_fast(b); /* never an integer (or scalar) */
+ setnvalue_complex_fast( ra, r );
+ } else {
+ lua_Complex bb= nvalue_complex(b), cc= nvalue_complex(c);
+ switch (op) {
+ case TM_ADD: r= bb + cc; break;
+ case TM_SUB: r= bb - cc; break;
+ case TM_MUL: r= bb * cc; break;
+ case TM_DIV: r= bb / cc; break;
+ case TM_MOD:
+ luaG_runerror(L, "attempt to use %% on complex numbers"); /* no return */
+ case TM_POW: r= luai_vectpow( bb, cc ); break;
+ default: lua_assert(0); r=0;
+ }
+ setnvalue_complex( ra, r );
+ }
+ return;
+ }
+#endif
+ nb = nvalue(b); nc = nvalue(c);
+ switch (op) {
+ case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); return;
+ case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); return;
+ case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); return;
+ case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); return;
+ case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); return;
+ case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); return;
+ case TM_UNM: setnvalue(ra, luai_numunm(nb)); return;
+ default: lua_assert(0);
+ }
+ }
+
+ /* Either operand not a number */
+ if (!call_binTM(L, rb, rc, ra, op))
+ luaG_aritherror(L, rb, rc);
+}
+
+/* Helper macro to sort arithmetic operations into four categories:
+ * TK_INT: integer - integer operands
+ * TK_NUMBER: number - number (non complex, either may be integer)
+ * TK_NUMBER2: complex numbers (at least the other)
+ * 0: non-numeric (at least the other)
+*/
+#ifdef LNUM_COMPLEX
+static inline int arith_mode( const TValue *rb, const TValue *rc ) {
+ if (ttisint(rb) && ttisint(rc)) return TK_INT;
+ if (ttiscomplex(rb) || ttiscomplex(rc)) return TK_NUMBER2;
+ if (ttisnumber(rb) && ttisnumber(rc)) return TK_NUMBER;
+ return 0;
+}
+#else
+# define arith_mode(rb,rc) \
+ ( (ttisint(rb) && ttisint(rc)) ? TK_INT : \
+ (ttisnumber(rb) && ttisnumber(rc)) ? TK_NUMBER : 0 )
+#endif
+
+/* arith_op macro for two operators:
+ * automatically chooses, which function (number, integer, complex) to use
+ */
+#define ARITH_OP2_START( op_num, op_int ) \
+ int failed= 0; \
+ switch( arith_mode(rb,rc) ) { \
+ case TK_INT: \
+ if (op_int ( &(ra)->value.i, ivalue(rb), ivalue(rc) )) \
+ { ra->tt= LUA_TINT; break; } /* else flow through */ \
+ case TK_NUMBER: \
+ setnvalue(ra, op_num ( nvalue(rb), nvalue(rc) )); break;
+
+#define ARITH_OP2_END \
+ default: \
+ failed= 1; break; \
+ } if (!failed) continue;
+
+#define arith_op_continue_scalar( op_num, op_int ) \
+ ARITH_OP2_START( op_num, op_int ) \
+ ARITH_OP2_END
+
+#ifdef LNUM_COMPLEX
+# define arith_op_continue( op_num, op_int, op_complex ) \
+ ARITH_OP2_START( op_num, op_int ) \
+ case TK_NUMBER2: \
+ setnvalue_complex( ra, op_complex ( nvalue_complex(rb), nvalue_complex(rc) ) ); break; \
+ ARITH_OP2_END
+#else
+# define arith_op_continue(op_num,op_int,_) arith_op_continue_scalar(op_num,op_int)
+#endif
+
+/* arith_op macro for one operator:
+ */
+#define ARITH_OP1_START( op_num, op_int ) \
+ int failed= 0; \
+ switch( arith_mode(rb,rb) ) { \
+ case TK_INT: \
+ if (op_int ( &(ra)->value.i, ivalue(rb) )) \
+ { ra->tt= LUA_TINT; break; } /* else flow through */ \
+ case TK_NUMBER: \
+ setnvalue(ra, op_num (nvalue(rb))); break; \
+
+#define ARITH_OP1_END \
+ default: \
+ failed= 1; break; \
+ } if (!failed) continue;
+
+#ifdef LNUM_COMPLEX
+# define arith_op1_continue( op_num, op_int, op_complex ) \
+ ARITH_OP1_START( op_num, op_int ) \
+ case TK_NUMBER2: \
+ setnvalue_complex( ra, op_complex ( nvalue_complex_fast(rb) )); break; \
+ ARITH_OP1_END
+#else
+# define arith_op1_continue( op_num, op_int, _ ) \
+ ARITH_OP1_START( op_num, op_int ) \
+ ARITH_OP1_END
+#endif
void luaV_execute (lua_State *L, int nexeccalls) {
@@ -472,38 +665,45 @@ void luaV_execute (lua_State *L, int nex
continue;
}
case OP_ADD: {
- arith_op(luai_numadd, TM_ADD);
+ TValue *rb = RKB(i), *rc= RKC(i);
+ arith_op_continue( luai_numadd, try_addint, luai_vectadd );
+ Protect(Arith(L, ra, rb, rc, TM_ADD)); \
continue;
}
case OP_SUB: {
- arith_op(luai_numsub, TM_SUB);
+ TValue *rb = RKB(i), *rc= RKC(i);
+ arith_op_continue( luai_numsub, try_subint, luai_vectsub );
+ Protect(Arith(L, ra, rb, rc, TM_SUB));
continue;
}
case OP_MUL: {
- arith_op(luai_nummul, TM_MUL);
+ TValue *rb = RKB(i), *rc= RKC(i);
+ arith_op_continue(luai_nummul, try_mulint, luai_vectmul);
+ Protect(Arith(L, ra, rb, rc, TM_MUL));
continue;
}
case OP_DIV: {
- arith_op(luai_numdiv, TM_DIV);
+ TValue *rb = RKB(i), *rc= RKC(i);
+ arith_op_continue(luai_numdiv, try_divint, luai_vectdiv);
+ Protect(Arith(L, ra, rb, rc, TM_DIV));
continue;
}
case OP_MOD: {
- arith_op(luai_nummod, TM_MOD);
+ TValue *rb = RKB(i), *rc= RKC(i);
+ arith_op_continue_scalar(luai_nummod, try_modint); /* scalars only */
+ Protect(Arith(L, ra, rb, rc, TM_MOD));
continue;
}
case OP_POW: {
- arith_op(luai_numpow, TM_POW);
+ TValue *rb = RKB(i), *rc= RKC(i);
+ arith_op_continue(luai_numpow, try_powint, luai_vectpow);
+ Protect(Arith(L, ra, rb, rc, TM_POW));
continue;
}
case OP_UNM: {
TValue *rb = RB(i);
- if (ttisnumber(rb)) {
- lua_Number nb = nvalue(rb);
- setnvalue(ra, luai_numunm(nb));
- }
- else {
- Protect(Arith(L, ra, rb, rb, TM_UNM));
- }
+ arith_op1_continue(luai_numunm, try_unmint, luai_vectunm);
+ Protect(Arith(L, ra, rb, rb, TM_UNM));
continue;
}
case OP_NOT: {
@@ -515,11 +715,11 @@ void luaV_execute (lua_State *L, int nex
const TValue *rb = RB(i);
switch (ttype(rb)) {
case LUA_TTABLE: {
- setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
+ setivalue(ra, luaH_getn(hvalue(rb)));
break;
}
case LUA_TSTRING: {
- setnvalue(ra, cast_num(tsvalue(rb)->len));
+ setivalue(ra, tsvalue(rb)->len);
break;
}
default: { /* try metamethod */
@@ -652,14 +852,30 @@ void luaV_execute (lua_State *L, int nex
}
}
case OP_FORLOOP: {
- lua_Number step = nvalue(ra+2);
- lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
- lua_Number limit = nvalue(ra+1);
- if (luai_numlt(0, step) ? luai_numle(idx, limit)
- : luai_numle(limit, idx)) {
- dojump(L, pc, GETARG_sBx(i)); /* jump back */
- setnvalue(ra, idx); /* update internal index... */
- setnvalue(ra+3, idx); /* ...and external index */
+ /* If start,step and limit are all integers, we don't need to check
+ * against overflow in the looping.
+ */
+ if (ttisint(ra) && ttisint(ra+1) && ttisint(ra+2)) {
+ lua_Integer step = ivalue(ra+2);
+ lua_Integer idx = ivalue(ra) + step; /* increment index */
+ lua_Integer limit = ivalue(ra+1);
+ if (step > 0 ? (idx <= limit) : (limit <= idx)) {
+ dojump(L, pc, GETARG_sBx(i)); /* jump back */
+ setivalue(ra, idx); /* update internal index... */
+ setivalue(ra+3, idx); /* ...and external index */
+ }
+ } else {
+ /* non-integer looping (don't use 'nvalue_fast', some may be integer!)
+ */
+ lua_Number step = nvalue(ra+2);
+ lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
+ lua_Number limit = nvalue(ra+1);
+ if (luai_numlt(0, step) ? luai_numle(idx, limit)
+ : luai_numle(limit, idx)) {
+ dojump(L, pc, GETARG_sBx(i)); /* jump back */
+ setnvalue(ra, idx); /* update internal index... */
+ setnvalue(ra+3, idx); /* ...and external index */
+ }
}
continue;
}
@@ -668,13 +884,21 @@ void luaV_execute (lua_State *L, int nex
const TValue *plimit = ra+1;
const TValue *pstep = ra+2;
L->savedpc = pc; /* next steps may throw errors */
+ /* Using same location for tonumber's both arguments, effectively does
+ * in-place modification (string->number). */
if (!tonumber(init, ra))
luaG_runerror(L, LUA_QL("for") " initial value must be a number");
else if (!tonumber(plimit, ra+1))
luaG_runerror(L, LUA_QL("for") " limit must be a number");
else if (!tonumber(pstep, ra+2))
luaG_runerror(L, LUA_QL("for") " step must be a number");
- setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
+ /* Step back one value (keep within integers if we can)
+ */
+ if (!( ttisint(ra) && ttisint(pstep) &&
+ try_subint( &ra->value.i, ivalue(ra), ivalue(pstep) ) )) {
+ /* don't use 'nvalue_fast()', values may be integer */
+ setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
+ }
dojump(L, pc, GETARG_sBx(i));
continue;
}
@@ -711,7 +935,7 @@ void luaV_execute (lua_State *L, int nex
luaH_resizearray(L, h, last); /* pre-alloc it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
- setobj2t(L, luaH_setnum(L, h, last--), val);
+ setobj2t(L, luaH_setint(L, h, last--), val);
luaC_barriert(L, h, val);
}
continue;
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -15,11 +15,9 @@
#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
-#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \
- (((o) = luaV_tonumber(o,n)) != NULL))
+#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL))
-#define equalobj(L,o1,o2) \
- (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
+#define equalobj(L,o1,o2) (ttype_ext_same(o1,o2) && luaV_equalval(L, o1, o2))
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
--- a/src/print.c
+++ b/src/print.c
@@ -14,6 +14,7 @@
#include "lobject.h"
#include "lopcodes.h"
#include "lundump.h"
+#include "lnum.h"
#define PrintFunction luaU_print
@@ -59,8 +60,16 @@ static void PrintConstant(const Proto* f
case LUA_TBOOLEAN:
printf(bvalue(o) ? "true" : "false");
break;
+ case LUA_TINT:
+ printf(LUA_INTEGER_FMT,ivalue(o));
+ break;
case LUA_TNUMBER:
- printf(LUA_NUMBER_FMT,nvalue(o));
+#ifdef LNUM_COMPLEX
+ // TBD: Do we get complex values here?
+ { lua_Number b= nvalue_img_fast(o);
+ printf( LUA_NUMBER_FMT "%s" LUA_NUMBER_FMT "i", nvalue_fast(o), b>=0 ? "+":"", b ); }
+#endif
+ printf(LUA_NUMBER_FMT,nvalue_fast(o));
break;
case LUA_TSTRING:
PrintString(rawtsvalue(o));