| --- 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 ) { |
| + /* Signed int overflow is undefined behavior, so catch it without causing it. */ |
| + if (ic>0) { if (ib > LUA_INTEGER_MAX - ic) return 0; /*overflow, use floats*/ } |
| + else { if (ib < LUA_INTEGER_MIN - ic) return 0; } |
| + *r = ib + ic; |
| + return 1; |
| +} |
| + |
| +int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { |
| + /* Signed int overflow is undefined behavior, so catch it without causing it. */ |
| + if (ic>0) { if (ib < LUA_INTEGER_MIN + ic) return 0; /*overflow, use floats*/ } |
| + else { if (ib > LUA_INTEGER_MAX + ic) return 0; } |
| + *r = ib - ic; |
| + 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)); |