summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-19 10:53:18 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-19 10:53:18 -0300
commit9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0 (patch)
tree2a6b0f6c1c2eb962bb383175eb0a67ea81a4564d
parent1e0c73d5b643707335b06abd2546a83d9439d14c (diff)
downloadlua-github-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.tar.gz
New semantics for the integer 'for' loop
The numerical 'for' loop over integers now uses a precomputed counter to control its number of iteractions. This change eliminates several weird cases caused by overflows (wrap-around) in the control variable. (It also ensures that every integer loop halts.) Also, the special opcodes for the usual case of step==1 were removed. (The new code is already somewhat complex for the usual case, but efficient.)
-rw-r--r--ljumptab.h2
-rw-r--r--lopcodes.c2
-rw-r--r--lopcodes.h4
-rw-r--r--lopnames.h2
-rw-r--r--lparser.c42
-rw-r--r--lvm.c147
-rw-r--r--manual/manual.of124
-rw-r--r--testes/code.lua4
-rw-r--r--testes/db.lua2
-rw-r--r--testes/nextvar.lua73
10 files changed, 215 insertions, 187 deletions
diff --git a/ljumptab.h b/ljumptab.h
index 9fa72a73..fa4277cc 100644
--- a/ljumptab.h
+++ b/ljumptab.h
@@ -99,8 +99,6 @@ static void *disptab[NUM_OPCODES] = {
&&L_OP_RETURN,
&&L_OP_RETURN0,
&&L_OP_RETURN1,
-&&L_OP_FORLOOP1,
-&&L_OP_FORPREP1,
&&L_OP_FORLOOP,
&&L_OP_FORPREP,
&&L_OP_TFORPREP,
diff --git a/lopcodes.c b/lopcodes.c
index 3f0d551a..c35a0aaf 100644
--- a/lopcodes.c
+++ b/lopcodes.c
@@ -93,8 +93,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, 0, 0, iABC) /* OP_RETURN */
,opmode(0, 0, 0, 0, iABC) /* OP_RETURN0 */
,opmode(0, 0, 0, 0, iABC) /* OP_RETURN1 */
- ,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP1 */
- ,opmode(0, 0, 0, 1, iABx) /* OP_FORPREP1 */
,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP */
,opmode(0, 0, 0, 1, iABx) /* OP_FORPREP */
,opmode(0, 0, 0, 0, iABx) /* OP_TFORPREP */
diff --git a/lopcodes.h b/lopcodes.h
index 3e100259..f867a01b 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -280,10 +280,6 @@ OP_RETURN,/* A B C return R(A), ... ,R(A+B-2) (see note) */
OP_RETURN0,/* return */
OP_RETURN1,/* A return R(A) */
-OP_FORLOOP1,/* A Bx R(A)++;
- if R(A) <= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */
-OP_FORPREP1,/* A Bx R(A)--; pc+=Bx */
-
OP_FORLOOP,/* A Bx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */
OP_FORPREP,/* A Bx R(A)-=R(A+2); pc+=Bx */
diff --git a/lopnames.h b/lopnames.h
index 96d901ac..dfca34d1 100644
--- a/lopnames.h
+++ b/lopnames.h
@@ -84,8 +84,6 @@ static const char *const opnames[] = {
"RETURN",
"RETURN0",
"RETURN1",
- "FORLOOP1",
- "FORPREP1",
"FORLOOP",
"FORPREP",
"TFORPREP",
diff --git a/lparser.c b/lparser.c
index 3887958e..8ffd9742 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1371,18 +1371,14 @@ static void repeatstat (LexState *ls, int line) {
/*
** Read an expression and generate code to put its results in next
-** stack slot. Return true if expression is a constant integer and,
-** if 'i' is not-zero, its value is equal to 'i'.
+** stack slot.
**
*/
-static int exp1 (LexState *ls, int i) {
+static void exp1 (LexState *ls) {
expdesc e;
- int res;
expr(ls, &e);
- res = luaK_isKint(&e) && (i == 0 || i == e.u.ival);
luaK_exp2nextreg(ls->fs, &e);
lua_assert(e.k == VNONRELOC);
- return res;
}
@@ -1403,31 +1399,29 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) {
/*
-** Generate code for a 'for' loop. 'kind' can be zero (a common for
-** loop), one (a basic for loop, with integer values and increment of
-** 1), or two (a generic for loop).
+** Generate code for a 'for' loop.
*/
-static void forbody (LexState *ls, int base, int line, int nvars, int kind) {
+static void forbody (LexState *ls, int base, int line, int nvars, int isgen) {
/* forbody -> DO block */
- static OpCode forprep[3] = {OP_FORPREP, OP_FORPREP1, OP_TFORPREP};
- static OpCode forloop[3] = {OP_FORLOOP, OP_FORLOOP1, OP_TFORLOOP};
+ static OpCode forprep[2] = {OP_FORPREP, OP_TFORPREP};
+ static OpCode forloop[2] = {OP_FORLOOP, OP_TFORLOOP};
BlockCnt bl;
FuncState *fs = ls->fs;
int prep, endfor;
checknext(ls, TK_DO);
- prep = luaK_codeABx(fs, forprep[kind], base, 0);
+ prep = luaK_codeABx(fs, forprep[isgen], base, 0);
enterblock(fs, &bl, 0); /* scope for declared variables */
adjustlocalvars(ls, nvars);
luaK_reserveregs(fs, nvars);
block(ls);
leaveblock(fs); /* end of scope for declared variables */
fixforjump(fs, prep, luaK_getlabel(fs), 0);
- if (kind == 2) { /* generic for? */
+ if (isgen) { /* generic for? */
luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
luaK_fixline(fs, line);
base += 2; /* base for 'OP_TFORLOOP' (skips function and state) */
}
- endfor = luaK_codeABx(fs, forloop[kind], base, 0);
+ endfor = luaK_codeABx(fs, forloop[isgen], base, 0);
fixforjump(fs, endfor, prep + 1, 1);
luaK_fixline(fs, line);
}
@@ -1437,26 +1431,22 @@ static void fornum (LexState *ls, TString *varname, int line) {
/* fornum -> NAME = exp,exp[,exp] forbody */
FuncState *fs = ls->fs;
int base = fs->freereg;
- int basicfor = 1; /* true if it is a "basic" 'for' (integer + 1) */
new_localvarliteral(ls, "(for index)");
new_localvarliteral(ls, "(for limit)");
new_localvarliteral(ls, "(for step)");
new_localvar(ls, varname);
checknext(ls, '=');
- if (!exp1(ls, 0)) /* initial value not an integer? */
- basicfor = 0; /* not a basic 'for' */
+ exp1(ls); /* initial value */
checknext(ls, ',');
- exp1(ls, 0); /* limit */
- if (testnext(ls, ',')) {
- if (!exp1(ls, 1)) /* optional step not 1? */
- basicfor = 0; /* not a basic 'for' */
- }
+ exp1(ls); /* limit */
+ if (testnext(ls, ','))
+ exp1(ls); /* optional step */
else { /* default step = 1 */
luaK_int(fs, fs->freereg, 1);
luaK_reserveregs(fs, 1);
}
adjustlocalvars(ls, 3); /* control variables */
- forbody(ls, base, line, 1, basicfor);
+ forbody(ls, base, line, 1, 0);
}
@@ -1484,7 +1474,7 @@ static void forlist (LexState *ls, TString *indexname) {
adjust_assign(ls, 4, explist(ls, &e), &e);
adjustlocalvars(ls, 4); /* control variables */
luaK_checkstack(fs, 3); /* extra space to call generator */
- forbody(ls, base, line, nvars - 4, 2);
+ forbody(ls, base, line, nvars - 4, 1);
}
@@ -1633,7 +1623,7 @@ static void tocloselocalstat (LexState *ls) {
luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr)));
new_localvar(ls, str_checkname(ls));
checknext(ls, '=');
- exp1(ls, 0);
+ exp1(ls);
markupval(fs, fs->nactvar);
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
adjustlocalvars(ls, 1);
diff --git a/lvm.c b/lvm.c
index 23e7ff70..75b05f00 100644
--- a/lvm.c
+++ b/lvm.c
@@ -148,35 +148,34 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
/*
** Try to convert a 'for' limit to an integer, preserving the semantics
-** of the loop. (The following explanation assumes a non-negative step;
+** of the loop. (The following explanation assumes a positive step;
** it is valid for negative steps mutatis mutandis.)
** If the limit is an integer or can be converted to an integer,
** rounding down, that is it.
-** Otherwise, check whether the limit can be converted to a float. 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 still run the loop once.
+** Otherwise, check whether the limit can be converted to a float. If
+** the float is too large, clip it to LUA_MAXINTEGER. If the float
+** is too negative, the loop should not run, because any initial
+** integer value is greater than such limit; so, it sets 'stopnow'.
+** (For this latter case, no integer limit would be correct; even a
+** limit of LUA_MININTEGER would run the loop once for an initial
+** value equal to LUA_MININTEGER.)
*/
-static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
+static int forlimit (const TValue *lim, lua_Integer *p, lua_Integer step,
int *stopnow) {
*stopnow = 0; /* usually, let loops run */
- if (ttisinteger(obj))
- *p = ivalue(obj);
- else if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) {
+ if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) {
/* not coercible to in integer */
- lua_Number n; /* try to convert to float */
- if (!tonumber(obj, &n)) /* cannot convert to float? */
+ lua_Number flim; /* try to convert to float */
+ if (!tonumber(lim, &flim)) /* cannot convert to float? */
return 0; /* not a number */
- if (luai_numlt(0, n)) { /* if true, float is larger than max integer */
- *p = LUA_MAXINTEGER;
- if (step < 0) *stopnow = 1;
+ /* 'flim' is a float out of integer bounds */
+ if (luai_numlt(0, flim)) { /* if it is positive, it is too large */
+ *p = LUA_MAXINTEGER; /* truncate */
+ if (step < 0) *stopnow = 1; /* initial value must be less than it */
}
- else { /* float is less than min integer */
- *p = LUA_MININTEGER;
- if (step >= 0) *stopnow = 1;
+ else { /* it is less than min integer */
+ *p = LUA_MININTEGER; /* truncate */
+ if (step > 0) *stopnow = 1; /* initial value must be greater than it */
}
}
return 1;
@@ -1636,85 +1635,87 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
return;
}
- vmcase(OP_FORLOOP1) {
- lua_Integer idx = intop(+, ivalue(s2v(ra)), 1); /* increment index */
- lua_Integer limit = ivalue(s2v(ra + 1));
- if (idx <= limit) {
- pc -= GETARG_Bx(i); /* jump back */
- chgivalue(s2v(ra), idx); /* update internal index... */
- setivalue(s2v(ra + 3), idx); /* ...and external index */
- }
- updatetrap(ci);
- vmbreak;
- }
- vmcase(OP_FORPREP1) {
- TValue *init = s2v(ra);
- TValue *plimit = s2v(ra + 1);
- lua_Integer ilimit, initv;
- int stopnow;
- if (unlikely(!forlimit(plimit, &ilimit, 1, &stopnow))) {
- savestate(L, ci); /* for the error message */
- luaG_forerror(L, plimit, "limit");
- }
- initv = (stopnow ? 0 : ivalue(init));
- setivalue(plimit, ilimit);
- setivalue(init, intop(-, initv, 1));
- pc += GETARG_Bx(i);
- vmbreak;
- }
vmcase(OP_FORLOOP) {
- if (ttisinteger(s2v(ra))) { /* integer loop? */
- lua_Integer step = ivalue(s2v(ra + 2));
- lua_Integer idx = intop(+, ivalue(s2v(ra)), step); /* new index */
- lua_Integer limit = ivalue(s2v(ra + 1));
- if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
+ if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
+ lua_Unsigned count = l_castS2U(ivalue(s2v(ra)));
+ if (count > 0) { /* still more iterations? */
+ lua_Integer step = ivalue(s2v(ra + 2));
+ lua_Integer idx = ivalue(s2v(ra + 3));
+ idx = intop(+, idx, step); /* add step to index */
+ chgivalue(s2v(ra), count - 1); /* update counter... */
+ setivalue(s2v(ra + 3), idx); /* ...and index */
pc -= GETARG_Bx(i); /* jump back */
- chgivalue(s2v(ra), idx); /* update internal index... */
- setivalue(s2v(ra + 3), idx); /* ...and external index */
}
}
else { /* floating loop */
lua_Number step = fltvalue(s2v(ra + 2));
lua_Number limit = fltvalue(s2v(ra + 1));
- lua_Number idx = fltvalue(s2v(ra));
+ lua_Number idx = fltvalue(s2v(ra + 3));
idx = luai_numadd(L, idx, step); /* inc. index */
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
+ setfltvalue(s2v(ra + 3), idx); /* update index */
pc -= GETARG_Bx(i); /* jump back */
- chgfltvalue(s2v(ra), idx); /* update internal index... */
- setfltvalue(s2v(ra + 3), idx); /* ...and external index */
}
}
- updatetrap(ci);
+ updatetrap(ci); /* allows a signal to break the loop */
vmbreak;
}
vmcase(OP_FORPREP) {
- TValue *init = s2v(ra);
+ TValue *pinit = s2v(ra);
TValue *plimit = s2v(ra + 1);
TValue *pstep = s2v(ra + 2);
lua_Integer ilimit;
int stopnow;
- if (ttisinteger(init) && ttisinteger(pstep) &&
+ savestate(L, ci); /* in case of errors */
+ if (ttisinteger(pinit) && ttisinteger(pstep) &&
forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {
- /* all values are integer */
- lua_Integer initv = (stopnow ? 0 : ivalue(init));
- setivalue(plimit, ilimit);
- setivalue(init, intop(-, initv, ivalue(pstep)));
+ /* integer loop */
+ lua_Integer init = ivalue(pinit);
+ lua_Integer step = ivalue(pstep);
+ setivalue(s2v(ra + 3), init); /* control variable */
+ if (step == 0)
+ luaG_runerror(L, "'for' step is zero");
+ else if (stopnow)
+ pc += GETARG_Bx(i) + 1; /* skip the loop */
+ else if (step > 0) { /* ascending loop? */
+ if (init > ilimit)
+ pc += GETARG_Bx(i) + 1; /* skip the loop */
+ else {
+ lua_Unsigned count = l_castS2U(ilimit) - l_castS2U(init);
+ if (step != 1) /* avoid division in the too common case */
+ count /= l_castS2U(step);
+ setivalue(s2v(ra), count);
+ }
+ }
+ else { /* descending loop */
+ if (init < ilimit)
+ pc += GETARG_Bx(i) + 1; /* skip the loop */
+ else {
+ lua_Unsigned count = l_castS2U(init) - l_castS2U(ilimit);
+ count /= -l_castS2U(step);
+ setivalue(s2v(ra), count);
+ }
+ }
}
else { /* try making all values floats */
- lua_Number ninit; lua_Number nlimit; lua_Number nstep;
- savestate(L, ci); /* in case of errors */
- if (unlikely(!tonumber(plimit, &nlimit)))
+ lua_Number init; lua_Number flimit; lua_Number step;
+ if (unlikely(!tonumber(plimit, &flimit)))
luaG_forerror(L, plimit, "limit");
- setfltvalue(plimit, nlimit);
- if (unlikely(!tonumber(pstep, &nstep)))
+ setfltvalue(plimit, flimit);
+ if (unlikely(!tonumber(pstep, &step)))
luaG_forerror(L, pstep, "step");
- setfltvalue(pstep, nstep);
- if (unlikely(!tonumber(init, &ninit)))
- luaG_forerror(L, init, "initial value");
- setfltvalue(init, luai_numsub(L, ninit, nstep));
+ setfltvalue(pstep, step);
+ if (unlikely(!tonumber(pinit, &init)))
+ luaG_forerror(L, pinit, "initial value");
+ if (step == 0)
+ luaG_runerror(L, "'for' step is zero");
+ if (luai_numlt(0, step) ? luai_numlt(flimit, init)
+ : luai_numlt(init, flimit))
+ pc += GETARG_Bx(i) + 1; /* skip the loop */
+ else
+ setfltvalue(s2v(ra + 3), init); /* control variable */
}
- pc += GETARG_Bx(i);
vmbreak;
}
vmcase(OP_TFORPREP) {
diff --git a/manual/manual.of b/manual/manual.of
index 8a8ebad5..b7ced443 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -594,7 +594,7 @@ controls how long the collector waits before starting a new cycle.
The collector starts a new cycle when the use of memory
hits @M{n%} of the use after the previous collection.
Larger values make the collector less aggressive.
-Values smaller than 100 mean the collector will not wait to
+Values less than 100 mean the collector will not wait to
start a new cycle.
A value of 200 means that the collector waits for the total memory in use
to double before starting a new cycle.
@@ -608,7 +608,7 @@ how many elements it marks or sweeps for each
kilobyte of memory allocated.
Larger values make the collector more aggressive but also increase
the size of each incremental step.
-You should not use values smaller than 100,
+You should not use values less than 100,
because they make the collector too slow and
can result in the collector never finishing a cycle.
The default value is 100; the maximum value is 1000.
@@ -1004,7 +1004,7 @@ the escape sequence @T{\u{@rep{XXX}}}
(note the mandatory enclosing brackets),
where @rep{XXX} is a sequence of one or more hexadecimal digits
representing the character code point.
-This code point can be any value smaller than @M{2@sp{31}}.
+This code point can be any value less than @M{2@sp{31}}.
(Lua uses the original UTF-8 specification here.)
Literal strings can also be defined using a long format
@@ -1370,73 +1370,49 @@ because now @Rw{return} is the last statement in its (inner) block.
The @Rw{for} statement has two forms:
one numerical and one generic.
+@sect4{@title{The numerical @Rw{for} loop}
+
The numerical @Rw{for} loop repeats a block of code while a
-control variable runs through an arithmetic progression.
+control variable goes through an arithmetic progression.
It has the following syntax:
@Produc{
@producname{stat}@producbody{@Rw{for} @bnfNter{Name} @bnfter{=}
exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}}
}
-The @emph{block} is repeated for @emph{name} starting at the value of
-the first @emph{exp}, until it passes the second @emph{exp} by steps of the
-third @emph{exp}.
-More precisely, a @Rw{for} statement like
-@verbatim{
-for v = @rep{e1}, @rep{e2}, @rep{e3} do @rep{block} end
-}
-is equivalent to the code:
-@verbatim{
-do
- local @rep{var}, @rep{limit}, @rep{step} = tonumber(@rep{e1}), tonumber(@rep{e2}), tonumber(@rep{e3})
- if not (@rep{var} and @rep{limit} and @rep{step}) then error() end
- @rep{var} = @rep{var} - @rep{step}
- while true do
- @rep{var} = @rep{var} + @rep{step}
- if (@rep{step} >= 0 and @rep{var} > @rep{limit}) or (@rep{step} < 0 and @rep{var} < @rep{limit}) then
- break
- end
- local v = @rep{var}
- @rep{block}
- end
-end
-}
-
-Note the following:
-@itemize{
-
-@item{
-All three control expressions are evaluated only once,
-before the loop starts.
-They must all result in numbers.
-}
-
-@item{
-@T{@rep{var}}, @T{@rep{limit}}, and @T{@rep{step}} are invisible variables.
-The names shown here are for explanatory purposes only.
-}
-
-@item{
-If the third expression (the step) is absent,
-then a step @N{of 1} is used.
-}
-
-@item{
-You can use @Rw{break} and @Rw{goto} to exit a @Rw{for} loop.
-}
-
-@item{
-The loop variable @T{v} is local to the loop body.
+The given identifier (@bnfNter{Name}) defines the control variable,
+which is local to the loop body (@emph{block}).
+
+The loop starts by evaluating once the three control expressions;
+they must all result in numbers.
+Their values are called respectively
+the @emph{initial value}, the @emph{limit}, and the @emph{step}.
+If the step is absent, it defaults @N{to 1}.
+Then the loop body is repeated with the value of the control variable
+going through an arithmetic progression,
+starting at the initial value,
+with a common difference given by the step,
+until that value passes the limit.
+A negative step makes a decreasing sequence;
+a step equal to zero raises an error.
+If the initial value is already greater than the limit
+(or less than, if the step is negative), the body is not executed.
+
+If both the initial value and the step are integers,
+the loop is done with integers;
+in this case, the range of the control variable is limited
+by the range of integers.
+Otherwise, the loop is done with floats.
+(Beware of floating-point accuracy in this case.)
+
+You should not change the value of the control variable
+during the loop.
If you need its value after the loop,
assign it to another variable before exiting the loop.
-}
-@item{
-The values in @rep{var}, @rep{limit}, and @rep{step}
-can be integers or floats.
-All operations on them respect the usual rules in Lua.
}
-}
+@sect4{@title{The generic @Rw{for} loop}
+
The generic @Rw{for} statement works over functions,
called @def{iterators}.
@@ -1499,6 +1475,8 @@ then assign them to other variables before breaking or exiting the loop.
}
+}
+
@sect3{funcstat| @title{Function Calls as Statements}
To allow possible side-effects,
function calls can be executed as statements:
@@ -1819,7 +1797,7 @@ A comparison @T{a > b} is translated to @T{b < a}
and @T{a >= b} is translated to @T{b <= a}.
Following the @x{IEEE 754} standard,
-@x{NaN} is considered neither smaller than,
+@x{NaN} is considered neither less than,
nor equal to, nor greater than any value (including itself).
}
@@ -2171,7 +2149,7 @@ then the function returns with no results.
@index{multiple return}
There is a system-dependent limit on the number of values
that a function may return.
-This limit is guaranteed to be larger than 1000.
+This limit is guaranteed to be greater than 1000.
The @emphx{colon} syntax
is used for defining @def{methods},
@@ -2367,7 +2345,7 @@ but it also can be any positive index after the stack top
within the space allocated for the stack,
that is, indices up to the stack size.
(Note that 0 is never an acceptable index.)
-Indices to upvalues @see{c-closure} larger than the real number
+Indices to upvalues @see{c-closure} greater than the real number
of upvalues in the current @N{C function} are also acceptable (but invalid).
Except when noted otherwise,
functions in the API work with acceptable indices.
@@ -2879,7 +2857,7 @@ Ensures that the stack has space for at least @id{n} extra slots
(that is, that you can safely push up to @id{n} values into it).
It returns false if it cannot fulfill the request,
either because it would cause the stack
-to be larger than a fixed maximum size
+to be greater than a fixed maximum size
(typically at least several thousand elements) or
because it cannot allocate memory for the extra space.
This function never shrinks the stack;
@@ -4053,7 +4031,7 @@ for the @Q{newindex} event @see{metatable}.
Accepts any index, @N{or 0},
and sets the stack top to this index.
-If the new top is larger than the old one,
+If the new top is greater than the old one,
then the new elements are filled with @nil.
If @id{index} @N{is 0}, then all stack elements are removed.
@@ -5056,7 +5034,7 @@ size @id{sz} with a call @T{luaL_buffinitsize(L, &b, sz)}.}
@item{
Finish by calling @T{luaL_pushresultsize(&b, sz)},
where @id{sz} is the total size of the resulting string
-copied into that space (which may be smaller than or
+copied into that space (which may be less than or
equal to the preallocated size).
}
@@ -7336,7 +7314,7 @@ Functions that interpret byte sequences only accept
valid sequences (well formed and not overlong).
By default, they only accept byte sequences
that result in valid Unicode code points,
-rejecting values larger than @T{10FFFF} and surrogates.
+rejecting values greater than @T{10FFFF} and surrogates.
A boolean argument @id{nonstrict}, when available,
lifts these checks,
so that all values up to @T{0x7FFFFFFF} are accepted.
@@ -7572,7 +7550,7 @@ returns the arc tangent of @id{y}.
@LibEntry{math.ceil (x)|
-Returns the smallest integral value larger than or equal to @id{x}.
+Returns the smallest integral value greater than or equal to @id{x}.
}
@@ -7597,7 +7575,7 @@ Returns the value @M{e@sp{x}}
@LibEntry{math.floor (x)|
-Returns the largest integral value smaller than or equal to @id{x}.
+Returns the largest integral value less than or equal to @id{x}.
}
@@ -7611,7 +7589,7 @@ that rounds the quotient towards zero. (integer/float)
@LibEntry{math.huge|
The float value @idx{HUGE_VAL},
-a value larger than any other numeric value.
+a value greater than any other numeric value.
}
@@ -8352,7 +8330,7 @@ of the given thread:
@N{level 1} is the function that called @id{getinfo}
(except for tail calls, which do not count on the stack);
and so on.
-If @id{f} is a number larger than the number of active functions,
+If @id{f} is a number greater than the number of active functions,
then @id{getinfo} returns @nil.
The returned table can contain all the fields returned by @Lid{lua_getinfo},
@@ -8746,6 +8724,12 @@ When needed, this metamethod must be explicitly defined.
}
@item{
+The semantics of the numerical @Rw{for} loop
+over integers changed in some details.
+In particular, the control variable never wraps around.
+}
+
+@item{
When a coroutine finishes with an error,
its stack is unwound (to run any pending closing methods).
}
diff --git a/testes/code.lua b/testes/code.lua
index 834ff5e2..128ca2cb 100644
--- a/testes/code.lua
+++ b/testes/code.lua
@@ -303,9 +303,9 @@ check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'RETURN1')
-- basic 'for' loops
check(function () for i = -10, 10.5 do end end,
-'LOADI', 'LOADK', 'LOADI', 'FORPREP1', 'FORLOOP1', 'RETURN0')
+'LOADI', 'LOADK', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0')
check(function () for i = 0xfffffff, 10.0, 1 do end end,
-'LOADK', 'LOADF', 'LOADI', 'FORPREP1', 'FORLOOP1', 'RETURN0')
+'LOADK', 'LOADF', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0')
-- bug in constant folding for 5.1
check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN1')
diff --git a/testes/db.lua b/testes/db.lua
index 976962b0..0858dd20 100644
--- a/testes/db.lua
+++ b/testes/db.lua
@@ -162,7 +162,7 @@ test([[for i,v in pairs{'a','b'} do
end
]], {1,2,1,2,1,3})
-test([[for i=1,4 do a=1 end]], {1,1,1,1,1})
+test([[for i=1,4 do a=1 end]], {1,1,1,1}, true)
do -- testing line info/trace with large gaps in source
diff --git a/testes/nextvar.lua b/testes/nextvar.lua
index d2306ed1..e769ccdd 100644
--- a/testes/nextvar.lua
+++ b/testes/nextvar.lua
@@ -76,7 +76,7 @@ while a < lim do
a = math.ceil(a*1.3)
end
-
+
local function check (t, na, nh)
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
@@ -100,7 +100,7 @@ local s = 'return {'
for i=1,lim do
s = s..i..','
local s = s
- for k=0,lim do
+ for k=0,lim do
local t = load(s..'}', '')()
assert(#t == i)
check(t, fb(i), mp2(k))
@@ -279,7 +279,7 @@ do -- clear global table
end
---
+--
local function checknext (a)
local b = {}
@@ -500,7 +500,7 @@ else --[
mt.__newindex = nil
mt.__len = nil
local tab2 = {}
- local u2 = T.newuserdata(0)
+ local u2 = T.newuserdata(0)
debug.setmetatable(u2, {__newindex = function (_, k, v) tab2[k] = v end})
table.move(u, 1, 4, 1, u2)
assert(#tab2 == 4 and tab2[1] == tab[1] and tab2[4] == tab[4])
@@ -601,6 +601,69 @@ do -- checking types
end
+
+do -- testing other strange cases for numeric 'for'
+
+ local function checkfor (from, to, step, t)
+ local c = 0
+ for i = from, to, step do
+ c = c + 1
+ assert(i == t[c])
+ end
+ assert(c == #t)
+ end
+
+ local maxi = math.maxinteger
+ local mini = math.mininteger
+
+ checkfor(mini, maxi, maxi, {mini, -1, maxi - 1})
+
+ checkfor(mini, math.huge, maxi, {mini, -1, maxi - 1})
+
+ checkfor(maxi, mini, mini, {maxi, -1})
+
+ checkfor(maxi, mini, -maxi, {maxi, 0, -maxi})
+
+ checkfor(maxi, -math.huge, mini, {maxi, -1})
+
+ checkfor(maxi, mini, 1, {})
+ checkfor(mini, maxi, -1, {})
+
+ checkfor(maxi - 6, maxi, 3, {maxi - 6, maxi - 3, maxi})
+ checkfor(mini + 4, mini, -2, {mini + 4, mini + 2, mini})
+
+ local step = maxi // 10
+ local c = mini
+ for i = mini, maxi, step do
+ assert(i == c)
+ c = c + step
+ end
+
+ c = maxi
+ for i = maxi, mini, -step do
+ assert(i == c)
+ c = c - step
+ end
+
+ checkfor(maxi, maxi, maxi, {maxi})
+ checkfor(maxi, maxi, mini, {maxi})
+ checkfor(mini, mini, maxi, {mini})
+ checkfor(mini, mini, mini, {mini})
+end
+
+
+checkerror("'for' step is zero", function ()
+ for i = 1, 10, 0 do end
+end)
+
+checkerror("'for' step is zero", function ()
+ for i = 1, -10, 0 do end
+end)
+
+checkerror("'for' step is zero", function ()
+ for i = 1.0, -10, 0.0 do end
+end)
+
collectgarbage()
@@ -657,7 +720,7 @@ a[3] = 30
-- testing ipairs with metamethods
a = {n=10}
setmetatable(a, { __index = function (t,k)
- if k <= t.n then return k * 10 end
+ if k <= t.n then return k * 10 end
end})
i = 0
for k,v in ipairs(a) do