From 26679ea35bf261f2b5edc2fb2f5cc4df483fd50d Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 8 Nov 2017 12:50:23 -0200 Subject: new function 'luaV_flttointeger' to convert floats to integers (without string coercions) + string operands to bitwise operations handled by string metamethods --- lstrlib.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 9 deletions(-) (limited to 'lstrlib.c') diff --git a/lstrlib.c b/lstrlib.c index c7cfa421..626c9159 100644 --- 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} }; -- cgit v1.2.3-55-g6feb