diff options
-rw-r--r-- | lparser.c | 30 | ||||
-rw-r--r-- | manual/manual.of | 16 | ||||
-rw-r--r-- | testes/attrib.lua | 2 | ||||
-rw-r--r-- | testes/closure.lua | 19 | ||||
-rw-r--r-- | testes/nextvar.lua | 10 |
5 files changed, 40 insertions, 37 deletions
@@ -187,10 +187,10 @@ static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) { | |||
187 | 187 | ||
188 | 188 | ||
189 | /* | 189 | /* |
190 | ** Create a new local variable with the given 'name'. Return its index | 190 | ** Create a new local variable with the given 'name' and given 'kind'. |
191 | ** in the function. | 191 | ** Return its index in the function. |
192 | */ | 192 | */ |
193 | static int new_localvar (LexState *ls, TString *name) { | 193 | static int new_localvarkind (LexState *ls, TString *name, int kind) { |
194 | lua_State *L = ls->L; | 194 | lua_State *L = ls->L; |
195 | FuncState *fs = ls->fs; | 195 | FuncState *fs = ls->fs; |
196 | Dyndata *dyd = ls->dyd; | 196 | Dyndata *dyd = ls->dyd; |
@@ -200,11 +200,19 @@ static int new_localvar (LexState *ls, TString *name) { | |||
200 | luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, | 200 | luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, |
201 | dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); | 201 | dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); |
202 | var = &dyd->actvar.arr[dyd->actvar.n++]; | 202 | var = &dyd->actvar.arr[dyd->actvar.n++]; |
203 | var->vd.kind = VDKREG; /* default */ | 203 | var->vd.kind = kind; /* default */ |
204 | var->vd.name = name; | 204 | var->vd.name = name; |
205 | return dyd->actvar.n - 1 - fs->firstlocal; | 205 | return dyd->actvar.n - 1 - fs->firstlocal; |
206 | } | 206 | } |
207 | 207 | ||
208 | |||
209 | /* | ||
210 | ** Create a new local variable with the given 'name' and regular kind. | ||
211 | */ | ||
212 | static int new_localvar (LexState *ls, TString *name) { | ||
213 | return new_localvarkind(ls, name, VDKREG); | ||
214 | } | ||
215 | |||
208 | #define new_localvarliteral(ls,v) \ | 216 | #define new_localvarliteral(ls,v) \ |
209 | new_localvar(ls, \ | 217 | new_localvar(ls, \ |
210 | luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); | 218 | luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); |
@@ -1573,7 +1581,7 @@ static void fornum (LexState *ls, TString *varname, int line) { | |||
1573 | new_localvarliteral(ls, "(for state)"); | 1581 | new_localvarliteral(ls, "(for state)"); |
1574 | new_localvarliteral(ls, "(for state)"); | 1582 | new_localvarliteral(ls, "(for state)"); |
1575 | new_localvarliteral(ls, "(for state)"); | 1583 | new_localvarliteral(ls, "(for state)"); |
1576 | new_localvar(ls, varname); | 1584 | new_localvarkind(ls, varname, RDKCONST); /* control variable */ |
1577 | checknext(ls, '='); | 1585 | checknext(ls, '='); |
1578 | exp1(ls); /* initial value */ | 1586 | exp1(ls); /* initial value */ |
1579 | checknext(ls, ','); | 1587 | checknext(ls, ','); |
@@ -1601,8 +1609,8 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1601 | new_localvarliteral(ls, "(for state)"); | 1609 | new_localvarliteral(ls, "(for state)"); |
1602 | new_localvarliteral(ls, "(for state)"); | 1610 | new_localvarliteral(ls, "(for state)"); |
1603 | new_localvarliteral(ls, "(for state)"); | 1611 | new_localvarliteral(ls, "(for state)"); |
1604 | /* create declared variables */ | 1612 | new_localvarkind(ls, indexname, RDKCONST); /* control variable */ |
1605 | new_localvar(ls, indexname); | 1613 | /* other declared variables */ |
1606 | while (testnext(ls, ',')) { | 1614 | while (testnext(ls, ',')) { |
1607 | new_localvar(ls, str_checkname(ls)); | 1615 | new_localvar(ls, str_checkname(ls)); |
1608 | nvars++; | 1616 | nvars++; |
@@ -1728,14 +1736,14 @@ static void localstat (LexState *ls) { | |||
1728 | FuncState *fs = ls->fs; | 1736 | FuncState *fs = ls->fs; |
1729 | int toclose = -1; /* index of to-be-closed variable (if any) */ | 1737 | int toclose = -1; /* index of to-be-closed variable (if any) */ |
1730 | Vardesc *var; /* last variable */ | 1738 | Vardesc *var; /* last variable */ |
1731 | int vidx, kind; /* index and kind of last variable */ | 1739 | int vidx; /* index of last variable */ |
1732 | int nvars = 0; | 1740 | int nvars = 0; |
1733 | int nexps; | 1741 | int nexps; |
1734 | expdesc e; | 1742 | expdesc e; |
1735 | do { | 1743 | do { |
1736 | vidx = new_localvar(ls, str_checkname(ls)); | 1744 | TString *vname = str_checkname(ls); |
1737 | kind = getlocalattribute(ls); | 1745 | int kind = getlocalattribute(ls); |
1738 | getlocalvardesc(fs, vidx)->vd.kind = kind; | 1746 | vidx = new_localvarkind(ls, vname, kind); |
1739 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ | 1747 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ |
1740 | if (toclose != -1) /* one already present? */ | 1748 | if (toclose != -1) /* one already present? */ |
1741 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); | 1749 | 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: | |||
1467 | exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} | 1467 | exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} |
1468 | } | 1468 | } |
1469 | The given identifier (@bnfNter{Name}) defines the control variable, | 1469 | The given identifier (@bnfNter{Name}) defines the control variable, |
1470 | which is a new variable local to the loop body (@emph{block}). | 1470 | which is a new read-only variable local to the loop body (@emph{block}). |
1471 | 1471 | ||
1472 | The loop starts by evaluating once the three control expressions. | 1472 | The loop starts by evaluating once the three control expressions. |
1473 | Their values are called respectively | 1473 | Their values are called respectively |
@@ -1499,11 +1499,6 @@ For integer loops, | |||
1499 | the control variable never wraps around; | 1499 | the control variable never wraps around; |
1500 | instead, the loop ends in case of an overflow. | 1500 | instead, the loop ends in case of an overflow. |
1501 | 1501 | ||
1502 | You should not change the value of the control variable | ||
1503 | during the loop. | ||
1504 | If you need its value after the loop, | ||
1505 | assign it to another variable before exiting the loop. | ||
1506 | |||
1507 | } | 1502 | } |
1508 | 1503 | ||
1509 | @sect4{@title{The generic @Rw{for} loop} | 1504 | @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 | |||
1526 | works as follows. | 1521 | works as follows. |
1527 | 1522 | ||
1528 | The names @rep{var_i} declare loop variables local to the loop body. | 1523 | The names @rep{var_i} declare loop variables local to the loop body. |
1529 | The first of these variables is the @emph{control variable}. | 1524 | The first of these variables is the @emph{control variable}, |
1525 | which is a read-only variable. | ||
1530 | 1526 | ||
1531 | The loop starts by evaluating @rep{explist} | 1527 | The loop starts by evaluating @rep{explist} |
1532 | to produce four values: | 1528 | to produce four values: |
@@ -1550,9 +1546,6 @@ to-be-closed variable @see{to-be-closed}, | |||
1550 | which can be used to release resources when the loop ends. | 1546 | which can be used to release resources when the loop ends. |
1551 | Otherwise, it does not interfere with the loop. | 1547 | Otherwise, it does not interfere with the loop. |
1552 | 1548 | ||
1553 | You should not change the value of the control variable | ||
1554 | during the loop. | ||
1555 | |||
1556 | } | 1549 | } |
1557 | 1550 | ||
1558 | } | 1551 | } |
@@ -9156,6 +9149,9 @@ change between versions. | |||
9156 | @itemize{ | 9149 | @itemize{ |
9157 | 9150 | ||
9158 | @item{ | 9151 | @item{ |
9152 | The control variable in @Rw{for} loops are read only. | ||
9153 | If you need to change it, | ||
9154 | declare a local variable with the same name in the loop body. | ||
9159 | } | 9155 | } |
9160 | 9156 | ||
9161 | } | 9157 | } |
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 | |||
236 | local fname = "file_does_not_exist2" | 236 | local fname = "file_does_not_exist2" |
237 | local m, err = pcall(require, fname) | 237 | local m, err = pcall(require, fname) |
238 | for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do | 238 | for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do |
239 | t = string.gsub(t, "?", fname) | 239 | local t = string.gsub(t, "?", fname) |
240 | assert(string.find(err, t, 1, true)) | 240 | assert(string.find(err, t, 1, true)) |
241 | end | 241 | end |
242 | 242 | ||
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 | |||
60 | -- testing closures with 'for' control variable | 60 | -- testing closures with 'for' control variable |
61 | a = {} | 61 | a = {} |
62 | for i=1,10 do | 62 | for i=1,10 do |
63 | a[i] = {set = function(x) i=x end, get = function () return i end} | 63 | a[i] = function () return i end |
64 | if i == 3 then break end | 64 | if i == 3 then break end |
65 | end | 65 | end |
66 | assert(a[4] == undef) | 66 | assert(a[4] == undef) |
67 | a[1].set(10) | 67 | assert(a[2]() == 2) |
68 | assert(a[2].get() == 2) | 68 | assert(a[3]() == 3) |
69 | a[2].set('a') | ||
70 | assert(a[3].get() == 3) | ||
71 | assert(a[2].get() == 'a') | ||
72 | 69 | ||
73 | a = {} | 70 | a = {} |
74 | local t = {"a", "b"} | 71 | local t = {"a", "b"} |
75 | for i = 1, #t do | 72 | for i = 1, #t do |
76 | local k = t[i] | 73 | local k = t[i] |
77 | a[i] = {set = function(x, y) i=x; k=y end, | 74 | a[i] = {set = function(x) k=x end, |
78 | get = function () return i, k end} | 75 | get = function () return i, k end} |
79 | if i == 2 then break end | 76 | if i == 2 then break end |
80 | end | 77 | end |
81 | a[1].set(10, 20) | 78 | a[1].set(10) |
82 | local r,s = a[2].get() | 79 | local r,s = a[2].get() |
83 | assert(r == 2 and s == 'b') | 80 | assert(r == 2 and s == 'b') |
84 | r,s = a[1].get() | 81 | r,s = a[1].get() |
85 | assert(r == 10 and s == 20) | 82 | assert(r == 1 and s == 10) |
86 | a[2].set('a', 'b') | 83 | a[2].set('a') |
87 | r,s = a[2].get() | 84 | r,s = a[2].get() |
88 | assert(r == "a" and s == "b") | 85 | assert(r == 2 and s == "a") |
89 | 86 | ||
90 | 87 | ||
91 | -- testing closures with 'for' control variable x break | 88 | -- 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 | |||
609 | a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) | 609 | a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) |
610 | end | 610 | end |
611 | 611 | ||
612 | do -- changing the control variable | 612 | do -- attempt to change the control variable |
613 | local a | 613 | local st, msg = load "for i = 1, 10 do i = 10 end" |
614 | a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10) | 614 | assert(not st and string.find(msg, "assign to const variable 'i'")) |
615 | a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10) | 615 | |
616 | local st, msg = load "for v, k in pairs{} do v = 10 end" | ||
617 | assert(not st and string.find(msg, "assign to const variable 'v'")) | ||
616 | end | 618 | end |
617 | 619 | ||
618 | -- conversion | 620 | -- conversion |