Browse Source

coercion string->number in arithmetic operations moved to string
library

Roberto Ierusalimschy 8 years ago
parent
commit
4dff277255
5 changed files with 111 additions and 19 deletions
  1. 2 3
      ldebug.c
  2. 2 2
      lobject.c
  3. 86 2
      lstrlib.c
  4. 10 11
      lvm.c
  5. 11 1
      lvm.h

+ 2 - 3
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
 ** Debug Interface
 ** See Copyright Notice in lua.h
 ** 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,
 l_noret luaG_opinterror (lua_State *L, const TValue *p1,
                          const TValue *p2, const char *msg) {
                          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 */
     p2 = p1;  /* now second is wrong */
   luaG_typeerror(L, p2, msg);
   luaG_typeerror(L, p2, msg);
 }
 }

+ 2 - 2
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
 ** Some generic functions over Lua objects
 ** See Copyright Notice in lua.h
 ** 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)));
         setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));
         return 1;
         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));
         setfltvalue(res, numarith(L, op, n1, n2));
         return 1;
         return 1;
       }
       }

+ 86 - 2
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
 ** Standard library for string operations and pattern-matching
 ** See Copyright Notice in lua.h
 ** 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
 ** PATTERN MATCHING
@@ -1576,7 +1658,9 @@ static const luaL_Reg strlib[] = {
 
 
 
 
 static void createmetatable (lua_State *L) {
 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_pushliteral(L, "");  /* dummy string */
   lua_pushvalue(L, -2);  /* copy table */
   lua_pushvalue(L, -2);  /* copy table */
   lua_setmetatable(L, -2);  /* set table as metatable for strings */
   lua_setmetatable(L, -2);  /* set table as metatable for strings */

+ 10 - 11
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
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -35,7 +35,6 @@
 #define MAXTAGLOOP	2000
 #define MAXTAGLOOP	2000
 
 
 
 
-
 /*
 /*
 ** 'l_intfitsf' checks whether a given integer can be converted to a
 ** 'l_intfitsf' checks whether a given integer can be converted to a
 ** float without rounding. Used in comparisons. Left undefined if
 ** float without rounding. Used in comparisons. Left undefined if
@@ -997,7 +996,7 @@ void luaV_execute (lua_State *L) {
         if (ttisinteger(rb)) {
         if (ttisinteger(rb)) {
           setivalue(s2v(ra), intop(+, ivalue(rb), ic));
           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)));
           setfltvalue(s2v(ra), luai_numadd(L, nb, cast_num(ic)));
         }
         }
         else {
         else {
@@ -1019,7 +1018,7 @@ void luaV_execute (lua_State *L) {
           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
           setivalue(s2v(ra), intop(+, ib, ic));
           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));
           setfltvalue(s2v(ra), luai_numadd(L, nb, nc));
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
         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);
           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
           setivalue(s2v(ra), intop(-, ib, ic));
           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));
           setfltvalue(s2v(ra), luai_numsub(L, nb, nc));
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); }
         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);
           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
           setivalue(s2v(ra), intop(*, ib, ic));
           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));
           setfltvalue(s2v(ra), luai_nummul(L, nb, nc));
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); }
         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 *rb = RKB(i);
         TValue *rc = RKC(i);
         TValue *rc = RKC(i);
         lua_Number nb; lua_Number nc;
         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));
           setfltvalue(s2v(ra), luai_numdiv(L, nb, nc));
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }
         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);
           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
           setivalue(s2v(ra), luaV_mod(L, ib, ic));
           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;
           lua_Number m;
           luai_nummod(L, nb, nc, m);
           luai_nummod(L, nb, nc, m);
           setfltvalue(s2v(ra), 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);
           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
           setivalue(s2v(ra), luaV_div(L, ib, ic));
           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));
           setfltvalue(s2v(ra), luai_numidiv(L, nb, nc));
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
         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 *rb = RKB(i);
         TValue *rc = RKC(i);
         TValue *rc = RKC(i);
         lua_Number nb; lua_Number nc;
         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));
           setfltvalue(s2v(ra), luai_numpow(L, nb, nc));
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); }
         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);
           lua_Integer ib = ivalue(rb);
           setivalue(s2v(ra), intop(-, 0, ib));
           setivalue(s2v(ra), intop(-, 0, ib));
         }
         }
-        else if (tonumber(rb, &nb)) {
+        else if (tonumberns(rb, nb)) {
           setfltvalue(s2v(ra), luai_numunm(L, nb));
           setfltvalue(s2v(ra), luai_numunm(L, nb));
         }
         }
         else {
         else {

+ 11 - 1
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
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -37,12 +37,22 @@
 #endif
 #endif
 
 
 
 
+/* convert an object to a float (including string coercion) */
 #define tonumber(o,n) \
 #define tonumber(o,n) \
 	(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_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) \
 #define tointeger(o,i) \
     (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
     (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 intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
 
 
 #define luaV_rawequalobj(t1,t2)		luaV_equalobj(NULL,t1,t2)
 #define luaV_rawequalobj(t1,t2)		luaV_equalobj(NULL,t1,t2)