diff options
author | Lua Team <team@lua.org> | 2013-07-06 12:00:00 +0000 |
---|---|---|
committer | repogen <> | 2013-07-06 12:00:00 +0000 |
commit | 87cc247b6b22184fba47184c218a642ea7a49e96 (patch) | |
tree | 299ba8b72b95aa32336b5c810b7133f8efc4fb29 /src/lobject.c | |
parent | dc27609467d2699ac9252e89d632432ac5f798f2 (diff) | |
download | lua-github-5.3.0-work1.tar.gz |
Lua 5.3.0-work15.3.0-work1
Diffstat (limited to 'src/lobject.c')
-rw-r--r-- | src/lobject.c | 161 |
1 files changed, 131 insertions, 30 deletions
diff --git a/src/lobject.c b/src/lobject.c index c152785a..edb0efeb 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.58 2013/02/20 14:08:56 roberto Exp $ +** $Id: lobject.c,v 2.67 2013/06/25 18:58:32 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -70,7 +70,21 @@ int luaO_ceillog2 (unsigned int x) { } -lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { + switch (op) { + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPPOW: return luaV_pow(v1, v2); + case LUA_OPUNM: return -v1; + default: lua_assert(0); return 0; + } +} + + +static lua_Number numarith (int op, lua_Number v1, lua_Number v2) { switch (op) { case LUA_OPADD: return luai_numadd(NULL, v1, v2); case LUA_OPSUB: return luai_numsub(NULL, v1, v2); @@ -84,17 +98,41 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { } +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + if (op == LUA_OPIDIV) { /* operates only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) { + setivalue(res, luaV_div(L, i1, i2)); + return; + } + /* else go to the end */ + } + else { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2) && op != LUA_OPDIV && + (op != LUA_OPPOW || ivalue(p2) >= 0)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setnvalue(res, numarith(op, n1, n2)); + return; + } + /* else go to the end */ + } + /* could not perform raw operation; try metmethod */ + lua_assert(L != NULL); /* cannot fail when folding (compile time) */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD)); +} + + int luaO_hexavalue (int c) { if (lisdigit(c)) return c - '0'; else return ltolower(c) - 'a' + 10; } -#if !defined(lua_strx2number) - -#include <math.h> - - static int isneg (const char **s) { if (**s == '-') { (*s)++; return 1; } else if (**s == '+') (*s)++; @@ -102,52 +140,81 @@ static int isneg (const char **s) { } -static lua_Number readhexa (const char **s, lua_Number r, int *count) { - for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ - r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); - (*count)++; - } - return r; -} +/* +** lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' does both conversions. C89, however, has no function +** to convert floating hexadecimal strings to numbers. For these +** systems, you can leave 'lua_strx2number' undefined and Lua will +** provide its own implementation. +*/ +#if defined(LUA_USE_STRTODHEX) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif + + +#if !defined(lua_strx2number) + +#include <math.h> +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 + /* ** convert an hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { - lua_Number r = 0.0; - int e = 0, i = 0; + lua_Number r = 0.0; /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ int neg = 0; /* 1 if number is negative */ + int dot = 0; /* true after seen a dot */ *endptr = cast(char *, s); /* nothing is valid yet */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check signal */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ return 0.0; /* invalid format (no '0x') */ - s += 2; /* skip '0x' */ - r = readhexa(&s, r, &i); /* read integer part */ - if (*s == '.') { - s++; /* skip dot */ - r = readhexa(&s, r, &e); /* read fractional part */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == '.') { + if (dot) break; /* second dot? stop loop */ + else dot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') { /* non-significant zero? */ + nosigdig++; + if (dot) e--; /* zero after dot? correct exponent */ + } + else { + if (++sigdig <= MAXSIGDIG) { /* can read it without overflow? */ + r = (r * cast_num(16.0)) + luaO_hexavalue(cast_uchar(*s)); + if (dot) e--; /* decimal digit */ + } + else /* too many digits; ignore */ + if (!dot) e++; /* still count it for exponent */ + } + } + else break; /* neither a dot nor a digit */ } - if (i == 0 && e == 0) - return 0.0; /* invalid format (no digit) */ - e *= -4; /* each fractional digit divides value by 2^-4 */ + if (nosigdig + sigdig == 0) /* no digits? */ + return 0.0; /* invalid format */ *endptr = cast(char *, s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; - int neg1; + int exp1 = 0; /* exponent value */ + int neg1; /* exponent signal */ s++; /* skip 'p' */ neg1 = isneg(&s); /* signal */ if (!lisdigit(cast_uchar(*s))) - goto ret; /* must have at least one digit */ + return 0.0; /* invalid; must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; e += exp1; + *endptr = cast(char *, s); /* valid up to here */ } - *endptr = cast(char *, s); /* valid up to here */ - ret: if (neg) r = -r; return l_mathop(ldexp)(r, e); } @@ -169,6 +236,36 @@ int luaO_str2d (const char *s, size_t len, lua_Number *result) { } +int luaO_str2int (const char *s, size_t len, lua_Integer *result) { + const char *ends = s + len; + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hexa? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(cast_uchar(*s)); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + a = a * 10 + luaO_hexavalue(cast_uchar(*s)); + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || s != ends) return 0; /* something wrong in the numeral */ + else { + if (neg) *result = -cast(lua_Integer, a); + else *result = cast(lua_Integer, a); + return 1; + } +} + static void pushstr (lua_State *L, const char *str, size_t l) { setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); @@ -197,7 +294,11 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } case 'd': { - setnvalue(L->top++, cast_num(va_arg(argp, int))); + setivalue(L->top++, cast_int(va_arg(argp, int))); + break; + } + case 'I': { + setivalue(L->top++, cast_integer(va_arg(argp, lua_Integer))); break; } case 'f': { |