diff --git a/ldebug.c b/ldebug.c index ac0b7d54..b83b2f89 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.127 2017/06/27 11:35:31 roberto Exp roberto $ +** $Id: ldebug.c,v 2.128 2017/06/29 15:06:44 roberto Exp roberto $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -679,8 +679,7 @@ l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { l_noret luaG_opinterror (lua_State *L, const TValue *p1, const TValue *p2, const char *msg) { - lua_Number temp; - if (!tonumber(p1, &temp)) /* first operand is wrong? */ + if (!ttisnumber(p1)) /* first operand is wrong? */ p2 = p1; /* now second is wrong */ luaG_typeerror(L, p2, msg); } diff --git a/lobject.c b/lobject.c index 9ad833c9..21616fad 100644 --- a/lobject.c +++ b/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.115 2017/05/24 13:47:11 roberto Exp roberto $ +** $Id: lobject.c,v 2.116 2017/06/29 15:06:44 roberto Exp roberto $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -147,7 +147,7 @@ int luaO_rawarith (lua_State *L, int op, const TValue *p1, const TValue *p2, setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); return 1; } - else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + else if (tonumberns(p1, n1) && tonumberns(p2, n2)) { setfltvalue(res, numarith(L, op, n1, n2)); return 1; } diff --git a/lstrlib.c b/lstrlib.c index 89896fa6..c7cfa421 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.255 2017/03/14 12:40:44 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.256 2017/05/19 16:29:40 roberto Exp roberto $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -201,6 +201,88 @@ static int str_dump (lua_State *L) { +/* +** {====================================================== +** METAMETHODS +** ======================================================= +*/ + +static int tonum (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNUMBER) { /* already a number? */ + lua_pushvalue(L, arg); + return 1; + } + else { /* check whether it is a numerical string */ + size_t len; + const char *s = lua_tolstring(L, arg, &len); + return (s != NULL && lua_stringtonumber(L, s) == len + 1); + } +} + + +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 */ + } + return 1; +} + + +static int arith_add (lua_State *L) { + return arith(L, LUA_OPADD, "__add"); +} + +static int arith_sub (lua_State *L) { + return arith(L, LUA_OPSUB, "__sub"); +} + +static int arith_mul (lua_State *L) { + return arith(L, LUA_OPMUL, "__mul"); +} + +static int arith_mod (lua_State *L) { + return arith(L, LUA_OPMOD, "__mod"); +} + +static int arith_pow (lua_State *L) { + return arith(L, LUA_OPPOW, "__pow"); +} + +static int arith_div (lua_State *L) { + return arith(L, LUA_OPDIV, "__div"); +} + +static int arith_idiv (lua_State *L) { + return arith(L, LUA_OPIDIV, "__idiv"); +} + +static int arith_unm (lua_State *L) { + return arith(L, LUA_OPUNM, "__unm"); +} + + +static const luaL_Reg stringmetamethods[] = { + {"__add", arith_add}, + {"__sub", arith_sub}, + {"__mul", arith_mul}, + {"__mod", arith_mod}, + {"__pow", arith_pow}, + {"__div", arith_div}, + {"__idiv", arith_idiv}, + {"__unm", arith_unm}, + {"__index", NULL}, /* placeholder */ + {NULL, NULL} +}; + +/* }====================================================== */ + /* ** {====================================================== ** PATTERN MATCHING @@ -1576,7 +1658,9 @@ static const luaL_Reg strlib[] = { static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* table to be metatable for strings */ + /* table to be metatable for strings */ + luaL_newlibtable(L, stringmetamethods); + luaL_setfuncs(L, stringmetamethods, 0); lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); /* copy table */ lua_setmetatable(L, -2); /* set table as metatable for strings */ diff --git a/lvm.c b/lvm.c index 8f8cc49f..18799be7 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.288 2017/06/29 15:06:44 roberto Exp roberto $ +** $Id: lvm.c,v 2.289 2017/06/29 15:38:41 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -35,7 +35,6 @@ #define MAXTAGLOOP 2000 - /* ** 'l_intfitsf' checks whether a given integer can be converted to a ** float without rounding. Used in comparisons. Left undefined if @@ -997,7 +996,7 @@ void luaV_execute (lua_State *L) { if (ttisinteger(rb)) { setivalue(s2v(ra), intop(+, ivalue(rb), ic)); } - else if (tonumber(rb, &nb)) { + else if (tonumberns(rb, nb)) { setfltvalue(s2v(ra), luai_numadd(L, nb, cast_num(ic))); } else { @@ -1019,7 +1018,7 @@ void luaV_execute (lua_State *L) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(s2v(ra), intop(+, ib, ic)); } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { setfltvalue(s2v(ra), luai_numadd(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } @@ -1033,7 +1032,7 @@ void luaV_execute (lua_State *L) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(s2v(ra), intop(-, ib, ic)); } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { setfltvalue(s2v(ra), luai_numsub(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } @@ -1047,7 +1046,7 @@ void luaV_execute (lua_State *L) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(s2v(ra), intop(*, ib, ic)); } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { setfltvalue(s2v(ra), luai_nummul(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } @@ -1057,7 +1056,7 @@ void luaV_execute (lua_State *L) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + if (tonumberns(rb, nb) && tonumberns(rc, nc)) { setfltvalue(s2v(ra), luai_numdiv(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } @@ -1121,7 +1120,7 @@ void luaV_execute (lua_State *L) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(s2v(ra), luaV_mod(L, ib, ic)); } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { lua_Number m; luai_nummod(L, nb, nc, m); setfltvalue(s2v(ra), m); @@ -1137,7 +1136,7 @@ void luaV_execute (lua_State *L) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(s2v(ra), luaV_div(L, ib, ic)); } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { setfltvalue(s2v(ra), luai_numidiv(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } @@ -1147,7 +1146,7 @@ void luaV_execute (lua_State *L) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + if (tonumberns(rb, nb) && tonumberns(rc, nc)) { setfltvalue(s2v(ra), luai_numpow(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } @@ -1160,7 +1159,7 @@ void luaV_execute (lua_State *L) { lua_Integer ib = ivalue(rb); setivalue(s2v(ra), intop(-, 0, ib)); } - else if (tonumber(rb, &nb)) { + else if (tonumberns(rb, nb)) { setfltvalue(s2v(ra), luai_numunm(L, nb)); } else { diff --git a/lvm.h b/lvm.h index 7ac959af..6bb5818d 100644 --- a/lvm.h +++ b/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.44 2017/06/09 19:16:41 roberto Exp roberto $ +** $Id: lvm.h,v 2.45 2017/06/29 15:06:44 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -37,12 +37,22 @@ #endif +/* convert an object to a float (including string coercion) */ #define tonumber(o,n) \ (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) + +/* convert an object to a float (without string coercion) */ +#define tonumberns(o,n) \ + (ttisfloat(o) ? ((n) = fltvalue(o), 1) : \ + (ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0)) + + +/* convert an object to an integer (including string coercion) */ #define tointeger(o,i) \ (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(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)