diff options
| -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 | } |
