diff --git a/lparser.c b/lparser.c index 24668c24..79b2317b 100644 --- a/lparser.c +++ b/lparser.c @@ -187,10 +187,10 @@ static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) { /* -** Create a new local variable with the given 'name'. Return its index -** in the function. +** Create a new local variable with the given 'name' and given 'kind'. +** Return its index in the function. */ -static int new_localvar (LexState *ls, TString *name) { +static int new_localvarkind (LexState *ls, TString *name, int kind) { lua_State *L = ls->L; FuncState *fs = ls->fs; Dyndata *dyd = ls->dyd; @@ -200,11 +200,19 @@ static int new_localvar (LexState *ls, TString *name) { luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); var = &dyd->actvar.arr[dyd->actvar.n++]; - var->vd.kind = VDKREG; /* default */ + var->vd.kind = kind; /* default */ var->vd.name = name; return dyd->actvar.n - 1 - fs->firstlocal; } + +/* +** Create a new local variable with the given 'name' and regular kind. +*/ +static int new_localvar (LexState *ls, TString *name) { + return new_localvarkind(ls, name, VDKREG); +} + #define new_localvarliteral(ls,v) \ new_localvar(ls, \ luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); @@ -1573,7 +1581,7 @@ static void fornum (LexState *ls, TString *varname, int line) { new_localvarliteral(ls, "(for state)"); new_localvarliteral(ls, "(for state)"); new_localvarliteral(ls, "(for state)"); - new_localvar(ls, varname); + new_localvarkind(ls, varname, RDKCONST); /* control variable */ checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); @@ -1601,8 +1609,8 @@ static void forlist (LexState *ls, TString *indexname) { new_localvarliteral(ls, "(for state)"); new_localvarliteral(ls, "(for state)"); new_localvarliteral(ls, "(for state)"); - /* create declared variables */ - new_localvar(ls, indexname); + new_localvarkind(ls, indexname, RDKCONST); /* control variable */ + /* other declared variables */ while (testnext(ls, ',')) { new_localvar(ls, str_checkname(ls)); nvars++; @@ -1728,14 +1736,14 @@ static void localstat (LexState *ls) { FuncState *fs = ls->fs; int toclose = -1; /* index of to-be-closed variable (if any) */ Vardesc *var; /* last variable */ - int vidx, kind; /* index and kind of last variable */ + int vidx; /* index of last variable */ int nvars = 0; int nexps; expdesc e; do { - vidx = new_localvar(ls, str_checkname(ls)); - kind = getlocalattribute(ls); - getlocalvardesc(fs, vidx)->vd.kind = kind; + TString *vname = str_checkname(ls); + int kind = getlocalattribute(ls); + vidx = new_localvarkind(ls, vname, kind); if (kind == RDKTOCLOSE) { /* to-be-closed? */ if (toclose != -1) /* one already present? */ luaK_semerror(ls, "multiple to-be-closed variables in local list"); diff --git a/manual/manual.of b/manual/manual.of index 416622c1..73d25951 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -1467,7 +1467,7 @@ It has the following syntax: exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} } The given identifier (@bnfNter{Name}) defines the control variable, -which is a new variable local to the loop body (@emph{block}). +which is a new read-only variable local to the loop body (@emph{block}). The loop starts by evaluating once the three control expressions. Their values are called respectively @@ -1499,11 +1499,6 @@ For integer loops, the control variable never wraps around; instead, the loop ends in case of an overflow. -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. - } @sect4{@title{The generic @Rw{for} loop} @@ -1526,7 +1521,8 @@ for @rep{var_1}, @Cdots, @rep{var_n} in @rep{explist} do @rep{body} end works as follows. The names @rep{var_i} declare loop variables local to the loop body. -The first of these variables is the @emph{control variable}. +The first of these variables is the @emph{control variable}, +which is a read-only variable. The loop starts by evaluating @rep{explist} to produce four values: @@ -1550,9 +1546,6 @@ to-be-closed variable @see{to-be-closed}, which can be used to release resources when the loop ends. Otherwise, it does not interfere with the loop. -You should not change the value of the control variable -during the loop. - } } @@ -9156,6 +9149,9 @@ change between versions. @itemize{ @item{ +The control variable in @Rw{for} loops are read only. +If you need to change it, +declare a local variable with the same name in the loop body. } } diff --git a/testes/attrib.lua b/testes/attrib.lua index 83821c06..fc427080 100644 --- a/testes/attrib.lua +++ b/testes/attrib.lua @@ -236,7 +236,7 @@ package.path = oldpath local fname = "file_does_not_exist2" local m, err = pcall(require, fname) for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do - t = string.gsub(t, "?", fname) + local t = string.gsub(t, "?", fname) assert(string.find(err, t, 1, true)) end diff --git a/testes/closure.lua b/testes/closure.lua index c2453677..27ec5596 100644 --- a/testes/closure.lua +++ b/testes/closure.lua @@ -60,32 +60,29 @@ end -- testing closures with 'for' control variable a = {} for i=1,10 do - a[i] = {set = function(x) i=x end, get = function () return i end} + a[i] = function () return i end if i == 3 then break end end assert(a[4] == undef) -a[1].set(10) -assert(a[2].get() == 2) -a[2].set('a') -assert(a[3].get() == 3) -assert(a[2].get() == 'a') +assert(a[2]() == 2) +assert(a[3]() == 3) a = {} local t = {"a", "b"} for i = 1, #t do local k = t[i] - a[i] = {set = function(x, y) i=x; k=y end, + a[i] = {set = function(x) k=x end, get = function () return i, k end} if i == 2 then break end end -a[1].set(10, 20) +a[1].set(10) local r,s = a[2].get() assert(r == 2 and s == 'b') r,s = a[1].get() -assert(r == 10 and s == 20) -a[2].set('a', 'b') +assert(r == 1 and s == 10) +a[2].set('a') r,s = a[2].get() -assert(r == "a" and s == "b") +assert(r == 2 and s == "a") -- testing closures with 'for' control variable x break diff --git a/testes/nextvar.lua b/testes/nextvar.lua index 80b3d05c..87910ef9 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua @@ -609,10 +609,12 @@ do a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) end -do -- changing the control variable - local a - a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10) - a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10) +do -- attempt to change the control variable + local st, msg = load "for i = 1, 10 do i = 10 end" + assert(not st and string.find(msg, "assign to const variable 'i'")) + + local st, msg = load "for v, k in pairs{} do v = 10 end" + assert(not st and string.find(msg, "assign to const variable 'v'")) end -- conversion