summaryrefslogtreecommitdiff
path: root/src/lobject.c
diff options
context:
space:
mode:
authorLua Team <team@lua.org>2013-07-06 12:00:00 +0000
committerrepogen <>2013-07-06 12:00:00 +0000
commit87cc247b6b22184fba47184c218a642ea7a49e96 (patch)
tree299ba8b72b95aa32336b5c810b7133f8efc4fb29 /src/lobject.c
parentdc27609467d2699ac9252e89d632432ac5f798f2 (diff)
downloadlua-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.c161
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': {