aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lparser.c64
-rw-r--r--lparser.h4
-rw-r--r--testes/locals.lua37
3 files changed, 75 insertions, 30 deletions
diff --git a/lparser.c b/lparser.c
index 27daa926..37102b72 100644
--- a/lparser.c
+++ b/lparser.c
@@ -212,27 +212,28 @@ static int new_localvar (LexState *ls, TString *name) {
212 212
213 213
214/* 214/*
215** Return the "variable description" (Vardesc) of a given 215** Return the "variable description" (Vardesc) of a given variable.
216** variable 216** (Unless noted otherwise, all variables are referred to by their
217** compiler indices.)
217*/ 218*/
218static Vardesc *getlocalvardesc (FuncState *fs, int i) { 219static Vardesc *getlocalvardesc (FuncState *fs, int vidx) {
219 return &fs->ls->dyd->actvar.arr[fs->firstlocal + i]; 220 return &fs->ls->dyd->actvar.arr[fs->firstlocal + vidx];
220} 221}
221 222
222 223
223/* 224/*
224** Convert 'nvar' (number of active variables at some point) to 225** Convert 'nvar', a compiler index level, to it corresponding
225** number of variables in the stack at that point. 226** stack index level. For that, search for the highest variable
227** below that level that is in the stack and uses its stack
228** index ('sidx').
226*/ 229*/
227static int stacklevel (FuncState *fs, int nvar) { 230static int stacklevel (FuncState *fs, int nvar) {
228 while (nvar > 0) { 231 while (nvar-- > 0) {
229 Vardesc *vd = getlocalvardesc(fs, nvar - 1); 232 Vardesc *vd = getlocalvardesc(fs, nvar); /* get variable */
230 if (vd->vd.kind != RDKCTC) /* is in the stack? */ 233 if (vd->vd.kind != RDKCTC) /* is in the stack? */
231 return vd->vd.sidx + 1; 234 return vd->vd.sidx + 1;
232 else
233 nvar--; /* try previous variable */
234 } 235 }
235 return 0; /* no variables */ 236 return 0; /* no variables in the stack */
236} 237}
237 238
238 239
@@ -245,10 +246,10 @@ int luaY_nvarstack (FuncState *fs) {
245 246
246 247
247/* 248/*
248** Get the debug-information entry for current variable 'i'. 249** Get the debug-information entry for current variable 'vidx'.
249*/ 250*/
250static LocVar *localdebuginfo (FuncState *fs, int i) { 251static LocVar *localdebuginfo (FuncState *fs, int vidx) {
251 Vardesc *vd = getlocalvardesc(fs, i); 252 Vardesc *vd = getlocalvardesc(fs, vidx);
252 if (vd->vd.kind == RDKCTC) 253 if (vd->vd.kind == RDKCTC)
253 return NULL; /* no debug info. for constants */ 254 return NULL; /* no debug info. for constants */
254 else { 255 else {
@@ -259,14 +260,20 @@ static LocVar *localdebuginfo (FuncState *fs, int i) {
259} 260}
260 261
261 262
262static void init_var (FuncState *fs, expdesc *e, int i) { 263/*
264** Create an expression representing variable 'vidx'
265*/
266static void init_var (FuncState *fs, expdesc *e, int vidx) {
263 e->f = e->t = NO_JUMP; 267 e->f = e->t = NO_JUMP;
264 e->k = VLOCAL; 268 e->k = VLOCAL;
265 e->u.var.vidx = i; 269 e->u.var.vidx = vidx;
266 e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx; 270 e->u.var.sidx = getlocalvardesc(fs, vidx)->vd.sidx;
267} 271}
268 272
269 273
274/*
275** Raises an error if variable described by 'e' is read only
276*/
270static void check_readonly (LexState *ls, expdesc *e) { 277static void check_readonly (LexState *ls, expdesc *e) {
271 FuncState *fs = ls->fs; 278 FuncState *fs = ls->fs;
272 TString *varname = NULL; /* to be set if variable is const */ 279 TString *varname = NULL; /* to be set if variable is const */
@@ -306,8 +313,8 @@ static void adjustlocalvars (LexState *ls, int nvars) {
306 int stklevel = luaY_nvarstack(fs); 313 int stklevel = luaY_nvarstack(fs);
307 int i; 314 int i;
308 for (i = 0; i < nvars; i++) { 315 for (i = 0; i < nvars; i++) {
309 int varidx = fs->nactvar++; 316 int vidx = fs->nactvar++;
310 Vardesc *var = getlocalvardesc(fs, varidx); 317 Vardesc *var = getlocalvardesc(fs, vidx);
311 var->vd.sidx = stklevel++; 318 var->vd.sidx = stklevel++;
312 var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); 319 var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
313 } 320 }
@@ -377,7 +384,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
377 384
378/* 385/*
379** Look for an active local variable with the name 'n' in the 386** Look for an active local variable with the name 'n' in the
380** function 'fs'. 387** function 'fs'. If found, initialize 'var' with it and return
388** its expression kind; otherwise return -1.
381*/ 389*/
382static int searchvar (FuncState *fs, TString *n, expdesc *var) { 390static int searchvar (FuncState *fs, TString *n, expdesc *var) {
383 int i; 391 int i;
@@ -1592,7 +1600,7 @@ static void forlist (LexState *ls, TString *indexname) {
1592 line = ls->linenumber; 1600 line = ls->linenumber;
1593 adjust_assign(ls, 4, explist(ls, &e), &e); 1601 adjust_assign(ls, 4, explist(ls, &e), &e);
1594 adjustlocalvars(ls, 4); /* control variables */ 1602 adjustlocalvars(ls, 4); /* control variables */
1595 markupval(fs, luaY_nvarstack(fs)); /* state may create an upvalue */ 1603 markupval(fs, fs->nactvar); /* last control var. must be closed */
1596 luaK_checkstack(fs, 3); /* extra space to call generator */ 1604 luaK_checkstack(fs, 3); /* extra space to call generator */
1597 forbody(ls, base, line, nvars - 4, 1); 1605 forbody(ls, base, line, nvars - 4, 1);
1598} 1606}
@@ -1730,7 +1738,7 @@ static int getlocalattribute (LexState *ls) {
1730 luaK_semerror(ls, 1738 luaK_semerror(ls,
1731 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); 1739 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
1732 } 1740 }
1733 return VDKREG; 1741 return VDKREG; /* regular variable */
1734} 1742}
1735 1743
1736 1744
@@ -1739,7 +1747,7 @@ static void checktoclose (LexState *ls, int level) {
1739 FuncState *fs = ls->fs; 1747 FuncState *fs = ls->fs;
1740 markupval(fs, level + 1); 1748 markupval(fs, level + 1);
1741 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ 1749 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1742 luaK_codeABC(fs, OP_TBC, level, 0, 0); 1750 luaK_codeABC(fs, OP_TBC, stacklevel(fs, level), 0, 0);
1743 } 1751 }
1744} 1752}
1745 1753
@@ -1749,18 +1757,18 @@ static void localstat (LexState *ls) {
1749 FuncState *fs = ls->fs; 1757 FuncState *fs = ls->fs;
1750 int toclose = -1; /* index of to-be-closed variable (if any) */ 1758 int toclose = -1; /* index of to-be-closed variable (if any) */
1751 Vardesc *var; /* last variable */ 1759 Vardesc *var; /* last variable */
1752 int ivar, kind; /* index and kind of last variable */ 1760 int vidx, kind; /* index and kind of last variable */
1753 int nvars = 0; 1761 int nvars = 0;
1754 int nexps; 1762 int nexps;
1755 expdesc e; 1763 expdesc e;
1756 do { 1764 do {
1757 ivar = new_localvar(ls, str_checkname(ls)); 1765 vidx = new_localvar(ls, str_checkname(ls));
1758 kind = getlocalattribute(ls); 1766 kind = getlocalattribute(ls);
1759 getlocalvardesc(fs, ivar)->vd.kind = kind; 1767 getlocalvardesc(fs, vidx)->vd.kind = kind;
1760 if (kind == RDKTOCLOSE) { /* to-be-closed? */ 1768 if (kind == RDKTOCLOSE) { /* to-be-closed? */
1761 if (toclose != -1) /* one already present? */ 1769 if (toclose != -1) /* one already present? */
1762 luaK_semerror(ls, "multiple to-be-closed variables in local list"); 1770 luaK_semerror(ls, "multiple to-be-closed variables in local list");
1763 toclose = luaY_nvarstack(fs) + nvars; 1771 toclose = fs->nactvar + nvars;
1764 } 1772 }
1765 nvars++; 1773 nvars++;
1766 } while (testnext(ls, ',')); 1774 } while (testnext(ls, ','));
@@ -1770,7 +1778,7 @@ static void localstat (LexState *ls) {
1770 e.k = VVOID; 1778 e.k = VVOID;
1771 nexps = 0; 1779 nexps = 0;
1772 } 1780 }
1773 var = getlocalvardesc(fs, ivar); /* get last variable */ 1781 var = getlocalvardesc(fs, vidx); /* get last variable */
1774 if (nvars == nexps && /* no adjustments? */ 1782 if (nvars == nexps && /* no adjustments? */
1775 var->vd.kind == RDKCONST && /* last variable is const? */ 1783 var->vd.kind == RDKCONST && /* last variable is const? */
1776 luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */ 1784 luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */
diff --git a/lparser.h b/lparser.h
index f544492e..618cb010 100644
--- a/lparser.h
+++ b/lparser.h
@@ -77,7 +77,7 @@ typedef struct expdesc {
77 } ind; 77 } ind;
78 struct { /* for local variables */ 78 struct { /* for local variables */
79 lu_byte sidx; /* index in the stack */ 79 lu_byte sidx; /* index in the stack */
80 unsigned short vidx; /* index in 'actvar.arr' */ 80 unsigned short vidx; /* compiler index (in 'actvar.arr') */
81 } var; 81 } var;
82 } u; 82 } u;
83 int t; /* patch list of 'exit when true' */ 83 int t; /* patch list of 'exit when true' */
@@ -125,7 +125,7 @@ typedef struct Labellist {
125 125
126/* dynamic structures used by the parser */ 126/* dynamic structures used by the parser */
127typedef struct Dyndata { 127typedef struct Dyndata {
128 struct { /* list of active local variables */ 128 struct { /* list of all active local variables */
129 Vardesc *arr; 129 Vardesc *arr;
130 int n; 130 int n;
131 int size; 131 int size;
diff --git a/testes/locals.lua b/testes/locals.lua
index 4f103be9..0e5e0c74 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -264,6 +264,43 @@ do
264end 264end
265 265
266 266
267-- testing to-be-closed x compile-time constants
268-- (there were some bugs here in Lua 5.4-rc3, due to a confusion
269-- between compile levels and stack levels of variables)
270do
271 local flag = false
272 local x = setmetatable({},
273 {__close = function() assert(flag == false); flag = true end})
274 local y <const> = nil
275 local z <const> = nil
276 do
277 local a <close> = x
278 end
279 assert(flag) -- 'x' must be closed here
280end
281
282do
283 -- similar problem, but with implicit close in for loops
284 local flag = false
285 local x = setmetatable({},
286 {__close = function () assert(flag == false); flag = true end})
287 -- return an empty iterator, nil, nil, and 'x' to be closed
288 local function a ()
289 return (function () return nil end), nil, nil, x
290 end
291 local v <const> = 1
292 local w <const> = 1
293 local x <const> = 1
294 local y <const> = 1
295 local z <const> = 1
296 for k in a() do
297 a = k
298 end -- ending the loop must close 'x'
299 assert(flag) -- 'x' must be closed here
300end
301
302
303
267do 304do
268 -- calls cannot be tail in the scope of to-be-closed variables 305 -- calls cannot be tail in the scope of to-be-closed variables
269 local X, Y 306 local X, Y