Browse Source

'for' loop tries to convert limit to integer when initial value and
step are integers

Roberto Ierusalimschy 11 years ago
parent
commit
9c4398de8f
1 changed files with 23 additions and 2 deletions
  1. 23 2
      lvm.c

+ 23 - 2
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.198 2014/04/15 16:32:49 roberto Exp roberto $
+** $Id: lvm.c,v 2.199 2014/04/27 14:41:11 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -110,6 +110,24 @@ int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
 }
 
 
+/*
+** Check whether the limit of a 'for' loop can be safely converted
+** to an integer (rounding down or up depending on the signal of 'step')
+*/
+static int limittointeger (const TValue *n, lua_Integer *p, lua_Integer step) {
+  if (ttisinteger(n)) {
+    *p = ivalue(n);
+    return 1;
+  }
+  else if (!ttisfloat(n)) return 0;
+  else {
+    lua_Number f = fltvalue(n);
+    f = (step >= 0) ? l_floor(f) : -l_floor(-f);
+    return luaV_numtointeger(f, p);
+  }
+}
+
+
 void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
   int loop;
   for (loop = 0; loop < MAXTAGLOOP; loop++) {
@@ -946,9 +964,12 @@ void luaV_execute (lua_State *L) {
         TValue *init = ra;
         TValue *plimit = ra + 1;
         TValue *pstep = ra + 2;
-        if (ttisinteger(init) && ttisinteger(plimit) && ttisinteger(pstep)) {
+        lua_Integer ilimit;
+        if (ttisinteger(init) && ttisinteger(pstep) &&
+            limittointeger(plimit, &ilimit, ivalue(pstep))) {
           /* all values are integer */
           setivalue(init, ivalue(init) - ivalue(pstep));
+          setivalue(plimit, ilimit);
         }
         else {  /* try making all values floats */
           lua_Number ninit; lua_Number nlimit; lua_Number nstep;