diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-03-04 15:12:57 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-03-04 15:12:57 -0300 |
commit | e560ac4862df81a2e84f09b2cf126d6790ff8589 (patch) | |
tree | bf4ad341f67353a66de3ba2ecdca7de58bffbef3 | |
parent | 915a9a912c3f59a0f24c4e59506933922aa0b17c (diff) | |
download | lua-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.c | 52 |
1 files changed, 32 insertions, 20 deletions
@@ -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 | ||
210 | static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { | 210 | static 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 | |||
220 | static 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 | */ | ||
245 | static void markupval (FuncState *fs, int level) { | 249 | static 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 | */ | ||
252 | static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { | 260 | static 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 | } |