From 06dc893f88641e1df6a455c1f24ecaf9ce484d8d Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 9 May 2014 11:20:52 -0300 Subject: [PATCH] in 'for' loops, make the limit an integer whenever initial value and step are integers --- lvm.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/lvm.c b/lvm.c index 026e943d..3854c90a 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.204 2014/04/30 19:29:51 roberto Exp roberto $ +** $Id: lvm.c,v 2.205 2014/05/01 18:18:06 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -143,6 +143,41 @@ int luaV_tostring (lua_State *L, StkId obj) { } +/* +** 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 +** 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 +** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects +** the extreme case when the initial value is LUA_MININTEGER, in which +** case the LUA_MININTEGER limit would run the loop once. +*/ +static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, + int *stopnow) { + *stopnow = 0; /* usually, let loops run */ + if (!tointeger_aux(obj, p, (step < 0))) { /* does not fit in integer? */ + lua_Number n; /* try to convert to float */ + if (!tonumber(obj, &n)) /* cannot convert to float? */ + return 0; /* not a number */ + if (n > 0) { /* if true, float is larger than max integer */ + *p = LUA_MAXINTEGER; + if (step < 0) *stopnow = 1; + } + else { /* float is smaller than min integer */ + *p = LUA_MININTEGER; + if (step >= 0) *stopnow = 1; + } + } + return 1; +} + + void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { @@ -980,11 +1015,13 @@ void luaV_execute (lua_State *L) { TValue *plimit = ra + 1; TValue *pstep = ra + 2; lua_Integer ilimit; + int stopnow; if (ttisinteger(init) && ttisinteger(pstep) && - tointeger_aux(plimit, &ilimit, (ivalue(pstep) < 0))) { + forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { /* all values are integer */ - setivalue(init, ivalue(init) - ivalue(pstep)); + lua_Integer initv = (stopnow ? 0 : ivalue(init)); setivalue(plimit, ilimit); + setivalue(init, initv - ivalue(pstep)); } else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep;