aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2010-03-04 15:12:57 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2010-03-04 15:12:57 -0300
commite560ac4862df81a2e84f09b2cf126d6790ff8589 (patch)
treebf4ad341f67353a66de3ba2ecdca7de58bffbef3
parent915a9a912c3f59a0f24c4e59506933922aa0b17c (diff)
downloadlua-e560ac4862df81a2e84f09b2cf126d6790ff8589.tar.gz
lua-e560ac4862df81a2e84f09b2cf126d6790ff8589.tar.bz2
lua-e560ac4862df81a2e84f09b2cf126d6790ff8589.zip
when searching for a variable name, look existing upvalues before
goingg to upper levels
-rw-r--r--lparser.c52
1 files changed, 32 insertions, 20 deletions
diff --git a/lparser.c b/lparser.c
index 8984bc79..77bb0b68 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp roberto $ 2** $Id: lparser.c,v 2.76 2010/02/26 20:40:29 roberto Exp roberto $
3** Lua Parser 3** Lua Parser
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -207,26 +207,26 @@ static void removevars (FuncState *fs, int tolevel) {
207} 207}
208 208
209 209
210static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { 210static int searchupvalue (FuncState *fs, TString *name) {
211 int i; 211 int i;
212 Upvaldesc *up = fs->f->upvalues;
213 for (i = 0; i < fs->nups; i++) {
214 if (up[i].name == name) return i;
215 }
216 return -1; /* not found */
217}
218
219
220static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
212 Proto *f = fs->f; 221 Proto *f = fs->f;
213 int oldsize = f->sizeupvalues; 222 int oldsize = f->sizeupvalues;
214 int instk = (v->k == VLOCAL);
215 lua_assert(instk || v->k == VUPVAL);
216 for (i=0; i<fs->nups; i++) {
217 if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) {
218 lua_assert(f->upvalues[i].name == name);
219 return i;
220 }
221 }
222 /* new one */
223 checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); 223 checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues");
224 luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, 224 luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues,
225 Upvaldesc, UCHAR_MAX, "upvalues"); 225 Upvaldesc, UCHAR_MAX, "upvalues");
226 while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; 226 while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
227 f->upvalues[fs->nups].name = name; 227 f->upvalues[fs->nups].name = name;
228 luaC_objbarrier(fs->L, f, name); 228 luaC_objbarrier(fs->L, f, name);
229 f->upvalues[fs->nups].instack = cast_byte(instk); 229 f->upvalues[fs->nups].instack = (v->k == VLOCAL);
230 f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); 230 f->upvalues[fs->nups].idx = cast_byte(v->u.s.info);
231 return fs->nups++; 231 return fs->nups++;
232} 232}
@@ -242,6 +242,10 @@ static int searchvar (FuncState *fs, TString *n) {
242} 242}
243 243
244 244
245/*
246 Mark block where variable at given level was defined
247 (to emit OP_CLOSE later).
248*/
245static void markupval (FuncState *fs, int level) { 249static void markupval (FuncState *fs, int level) {
246 BlockCnt *bl = fs->bl; 250 BlockCnt *bl = fs->bl;
247 while (bl && bl->nactvar > level) bl = bl->previous; 251 while (bl && bl->nactvar > level) bl = bl->previous;
@@ -249,22 +253,30 @@ static void markupval (FuncState *fs, int level) {
249} 253}
250 254
251 255
256/*
257 Find variable with given name 'n'. If it is an upvalue, add this
258 upvalue into all intermediate functions.
259*/
252static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { 260static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
253 if (fs == NULL) /* no more levels? */ 261 if (fs == NULL) /* no more levels? */
254 return VGLOBAL; /* default is global variable */ 262 return VGLOBAL; /* default is global variable */
255 else { 263 else {
256 int v = searchvar(fs, n); /* look up at current level */ 264 int v = searchvar(fs, n); /* look up locals at current level */
257 if (v >= 0) { 265 if (v >= 0) { /* found? */
258 init_exp(var, VLOCAL, v); 266 init_exp(var, VLOCAL, v); /* variable is local */
259 if (!base) 267 if (!base)
260 markupval(fs, v); /* local will be used as an upval */ 268 markupval(fs, v); /* local will be used as an upval */
261 return VLOCAL; 269 return VLOCAL;
262 } 270 }
263 else { /* not found at current level; try upper one */ 271 else { /* not found as local at current level; try upvalues */
264 if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) 272 int idx = searchupvalue(fs, n); /* try existing upvalues */
265 return VGLOBAL; 273 if (idx < 0) { /* not found? */
266 var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ 274 if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) /* try upper levels */
267 var->k = VUPVAL; /* upvalue in this level */ 275 return VGLOBAL; /* not found; is a global */
276 /* else was LOCAL or UPVAL */
277 idx = newupvalue(fs, n, var); /* will be a new upvalue */
278 }
279 init_exp(var, VUPVAL, idx);
268 return VUPVAL; 280 return VUPVAL;
269 } 281 }
270 } 282 }