commit 26679ea35bf261f2b5edc2fb2f5cc4df483fd50d
parent c3e5946fb2b7b5781d9bca9d303967abe6263482
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 8 Nov 2017 12:49:56 -0200
new function 'luaV_flttointeger' to convert floats to integers (without
string coercions) + string operands to bitwise operations handled
by string metamethods
Diffstat:
8 files changed, 126 insertions(+), 48 deletions(-)
diff --git a/lcode.c b/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.130 2017/10/04 21:56:32 roberto Exp roberto $
+** $Id: lcode.c,v 2.131 2017/11/07 17:20:42 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -611,7 +611,7 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) {
TValue v;
lua_Integer fi;
setfltvalue(&v, f);
- if (luaV_tointeger(&v, &fi, 0) &&
+ if (luaV_flttointeger(&v, &fi, 0) &&
l_castS2U(fi) + MAXARG_sBx <= l_castS2U(MAXARG_Bx))
luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
else
@@ -1146,7 +1146,7 @@ static int validop (int op, TValue *v1, TValue *v2) {
case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */
lua_Integer i;
- return (tointeger(v1, &i) && tointeger(v2, &i));
+ return (tointegerns(v1, &i) && tointegerns(v2, &i));
}
case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */
return (nvalue(v2) != 0);
diff --git a/ldebug.c b/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.140 2017/11/07 13:25:26 roberto Exp roberto $
+** $Id: ldebug.c,v 2.141 2017/11/07 17:20:42 roberto Exp roberto $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -670,7 +670,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1,
*/
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
lua_Integer temp;
- if (!tointeger(p1, &temp))
+ if (!tointegerns(p1, &temp))
p2 = p1;
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
}
diff --git a/lobject.c b/lobject.c
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.117 2017/07/07 16:34:32 roberto Exp roberto $
+** $Id: lobject.c,v 2.118 2017/10/10 20:05:40 roberto Exp roberto $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -127,7 +127,7 @@ int luaO_rawarith (lua_State *L, int op, const TValue *p1, const TValue *p2,
case LUA_OPSHL: case LUA_OPSHR:
case LUA_OPBNOT: { /* operate only on integers */
lua_Integer i1; lua_Integer i2;
- if (tointeger(p1, &i1) && tointeger(p2, &i2)) {
+ if (tointegerns(p1, &i1) && tointegerns(p2, &i2)) {
setivalue(res, intarith(L, op, i1, i2));
return 1;
}
diff --git a/lstrlib.c b/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.256 2017/05/19 16:29:40 roberto Exp roberto $
+** $Id: lstrlib.c,v 1.257 2017/07/07 16:34:32 roberto Exp roberto $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -220,17 +220,49 @@ static int tonum (lua_State *L, int arg) {
}
+static int toint (lua_State *L, int arg) {
+ if (!tonum(L, arg))
+ return 0; /* not coercible to a number */
+ else if (lua_isinteger(L, arg))
+ return 1; /* already an integer */
+ else { /* a float */
+ int ok;
+ lua_Integer n = lua_tointegerx(L, arg, &ok);
+ if (!ok)
+ return 0;
+ else {
+ lua_pop(L, 1); /* remove the float */
+ lua_pushinteger(L, n); /* push an integer */
+ return 1;
+ }
+ }
+}
+
+
+static void trymt (lua_State *L, const char *mtname) {
+ lua_settop(L, 2); /* back to the original arguments */
+ if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname))
+ luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
+ luaL_typename(L, -2), luaL_typename(L, -1));
+ lua_insert(L, -3); /* put metamethod before arguments */
+ lua_call(L, 2, 1); /* call metamethod */
+}
+
+
static int arith (lua_State *L, int op, const char *mtname) {
if (tonum(L, 1) && tonum(L, 2))
lua_arith(L, op); /* result will be on the top */
- else {
- lua_settop(L, 2); /* back to the original arguments */
- if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname))
- return luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
- luaL_typename(L, -2), luaL_typename(L, -1));
- lua_insert(L, -3); /* put metamethod before arguments */
- lua_call(L, 2, 1); /* call metamethod */
- }
+ else
+ trymt(L, mtname);
+ return 1;
+}
+
+
+static int bitwise (lua_State *L, int op, const char *mtname) {
+ if (toint(L, 1) && toint(L, 2))
+ lua_arith(L, op); /* result will be on the top */
+ else
+ trymt(L, mtname);
return 1;
}
@@ -267,6 +299,30 @@ static int arith_unm (lua_State *L) {
return arith(L, LUA_OPUNM, "__unm");
}
+static int bitwise_band (lua_State *L) {
+ return bitwise(L, LUA_OPBAND, "__band");
+}
+
+static int bitwise_bor (lua_State *L) {
+ return bitwise(L, LUA_OPBOR, "__bor");
+}
+
+static int bitwise_bxor (lua_State *L) {
+ return bitwise(L, LUA_OPBXOR, "__bxor");
+}
+
+static int bitwise_shl (lua_State *L) {
+ return bitwise(L, LUA_OPSHL, "__shl");
+}
+
+static int bitwise_shr (lua_State *L) {
+ return bitwise(L, LUA_OPSHR, "__shr");
+}
+
+static int bitwise_bnot (lua_State *L) {
+ return bitwise(L, LUA_OPBNOT, "__bnot");
+}
+
static const luaL_Reg stringmetamethods[] = {
{"__add", arith_add},
@@ -277,6 +333,12 @@ static const luaL_Reg stringmetamethods[] = {
{"__div", arith_div},
{"__idiv", arith_idiv},
{"__unm", arith_unm},
+ {"__band", bitwise_band},
+ {"__bor", bitwise_bor},
+ {"__bxor", bitwise_bxor},
+ {"__shl", bitwise_shl},
+ {"__shr", bitwise_shr},
+ {"__bnot", bitwise_bnot},
{"__index", NULL}, /* placeholder */
{NULL, NULL}
};
diff --git a/ltable.c b/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.124 2017/06/12 14:21:44 roberto Exp roberto $
+** $Id: ltable.c,v 2.125 2017/06/29 15:06:44 roberto Exp roberto $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -495,7 +495,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
lua_Integer k;
- if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */
+ if (luaV_flttointeger(key, &k, 0)) { /* does index fit in an integer? */
setivalue(&aux, k);
key = &aux; /* insert it as an integer */
}
@@ -604,7 +604,7 @@ const TValue *luaH_get (Table *t, const TValue *key) {
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMFLT: {
lua_Integer k;
- if (luaV_tointeger(key, &k, 0)) /* index is int? */
+ if (luaV_flttointeger(key, &k, 0)) /* index is an integral? */
return luaH_getint(t, k); /* use specialized version */
/* else... */
} /* FALLTHROUGH */
diff --git a/ltm.c b/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.45 2017/10/04 15:49:05 roberto Exp $
+** $Id: ltm.c,v 2.47 2017/11/07 13:25:26 roberto Exp roberto $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -153,8 +153,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
/* call never returns, but to avoid warnings: *//* FALLTHROUGH */
case TM_BAND: case TM_BOR: case TM_BXOR:
case TM_SHL: case TM_SHR: case TM_BNOT: {
- lua_Number dummy;
- if (tonumber(p1, &dummy) && tonumber(p2, &dummy))
+ if (ttisnumber(p1) && ttisnumber(p2))
luaG_tointerror(L, p1, p2);
else
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
diff --git a/lvm.c b/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.306 2017/11/07 13:25:26 roberto Exp roberto $
+** $Id: lvm.c,v 2.307 2017/11/07 17:20:42 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -74,7 +74,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
*n = cast_num(ivalue(obj));
return 1;
}
- else if (cvt2num(obj) && /* string convertible to number? */
+ else if (cvt2num(obj) && /* string coercible to number? */
luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
return 1;
@@ -85,15 +85,15 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
/*
-** try to convert a value to an integer, rounding according to 'mode':
+** try to convert a float to an integer, rounding according to 'mode':
** mode == 0: accepts only integral values
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
-int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
- TValue v;
- again:
- if (ttisfloat(obj)) {
+int luaV_flttointeger (const TValue *obj, lua_Integer *p, int mode) {
+ if (!ttisfloat(obj))
+ return 0;
+ else {
lua_Number n = fltvalue(obj);
lua_Number f = l_floor(n);
if (n != f) { /* not an integral value? */
@@ -103,16 +103,23 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
}
return lua_numbertointeger(f, p);
}
- else if (ttisinteger(obj)) {
+}
+
+
+/*
+** try to convert a value to an integer. ("Fast track" is handled
+** by macro 'tointeger'.)
+*/
+int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
+ TValue v;
+ if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1)
+ obj = &v; /* change string to its corresponding number */
+ if (ttisinteger(obj)) {
*p = ivalue(obj);
return 1;
}
- else if (cvt2num(obj) &&
- luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
- obj = &v;
- goto again; /* convert result from 'luaO_str2num' to an integer */
- }
- return 0; /* conversion failed */
+ else
+ return luaV_flttointeger(obj, p, mode);
}
@@ -120,9 +127,9 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
** Try to convert a 'for' limit to an integer, preserving the semantics
** of the loop. (The following explanation assumes a non-negative step;
** it is valid for negative steps mutatis mutandis.)
-** If the limit can be converted to an integer, rounding down, that is
-** it.
-** Otherwise, check whether the limit can be converted to a number. If
+** If the limit is an integer or can be converted to an integer,
+** rounding down, that is it.
+** Otherwise, check whether the limit can be converted to a float. If
** the number is too large, it is OK to set the limit as LUA_MAXINTEGER,
** which means no limit. If the number is too negative, the loop
** should not run, because any initial integer value is larger than the
@@ -133,7 +140,10 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
int *stopnow) {
*stopnow = 0; /* usually, let loops run */
- if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
+ if (ttisinteger(obj))
+ *p = ivalue(obj);
+ else if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) {
+ /* not coercible to in integer */
lua_Number n; /* try to convert to float */
if (!tonumber(obj, &n)) /* cannot convert to float? */
return 0; /* not a number */
@@ -411,7 +421,7 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */
lua_Integer i1, i2; /* compare them as integers */
- return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
+ return (tointegerns(t1, &i1) && tointegerns(t2, &i2) && i1 == i2);
}
}
/* values have same type and same variant */
@@ -1144,7 +1154,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lua_Integer ib; lua_Integer ic;
- if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
setivalue(s2v(ra), intop(&, ib, ic));
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); }
@@ -1154,7 +1164,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lua_Integer ib; lua_Integer ic;
- if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
setivalue(s2v(ra), intop(|, ib, ic));
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); }
@@ -1164,7 +1174,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lua_Integer ib; lua_Integer ic;
- if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
setivalue(s2v(ra), intop(^, ib, ic));
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); }
@@ -1174,7 +1184,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lua_Integer ib; lua_Integer ic;
- if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
setivalue(s2v(ra), luaV_shiftl(ib, ic));
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); }
@@ -1184,7 +1194,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lua_Integer ib; lua_Integer ic;
- if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
+ if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
setivalue(s2v(ra), luaV_shiftl(ib, -ic));
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); }
@@ -1248,7 +1258,7 @@ void luaV_execute (lua_State *L) {
vmcase(OP_BNOT) {
TValue *rb = vRB(i);
lua_Integer ib;
- if (tointeger(rb, &ib)) {
+ if (tointegerns(rb, &ib)) {
setivalue(s2v(ra), intop(^, ~l_castS2U(0), ib));
}
else {
diff --git a/lvm.h b/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.45 2017/06/29 15:06:44 roberto Exp roberto $
+** $Id: lvm.h,v 2.46 2017/07/07 16:34:32 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -53,6 +53,12 @@
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
+/* convert an object to an integer (without string coercion) */
+#define tointegerns(o,i) \
+ (ttisinteger(o) ? (*(i) = ivalue(o), 1) \
+ : luaV_flttointeger(o,i,LUA_FLOORN2I))
+
+
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
@@ -100,6 +106,7 @@ LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
+LUAI_FUNC int luaV_flttointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,