lua

A copy of the Lua development repository
Log | Files | Refs | README

commit e560ac4862df81a2e84f09b2cf126d6790ff8589
parent 915a9a912c3f59a0f24c4e59506933922aa0b17c
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Thu,  4 Mar 2010 15:12:33 -0300

when searching for a variable name, look existing upvalues before
goingg to upper levels

Diffstat:
Mlparser.c | 52++++++++++++++++++++++++++++++++--------------------
1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/lparser.c b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp roberto $ +** $Id: lparser.c,v 2.76 2010/02/26 20:40:29 roberto Exp roberto $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -207,26 +207,26 @@ static void removevars (FuncState *fs, int tolevel) { } -static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { +static int searchupvalue (FuncState *fs, TString *name) { int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (up[i].name == name) return i; + } + return -1; /* not found */ +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; - int instk = (v->k == VLOCAL); - lua_assert(instk || v->k == VUPVAL); - for (i=0; i<fs->nups; i++) { - if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) { - lua_assert(f->upvalues[i].name == name); - return i; - } - } - /* new one */ checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, UCHAR_MAX, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->L, f, name); - f->upvalues[fs->nups].instack = cast_byte(instk); + f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); return fs->nups++; } @@ -242,6 +242,10 @@ static int searchvar (FuncState *fs, TString *n) { } +/* + Mark block where variable at given level was defined + (to emit OP_CLOSE later). +*/ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl && bl->nactvar > level) bl = bl->previous; @@ -249,22 +253,30 @@ static void markupval (FuncState *fs, int level) { } +/* + Find variable with given name 'n'. If it is an upvalue, add this + upvalue into all intermediate functions. +*/ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ return VGLOBAL; /* default is global variable */ else { - int v = searchvar(fs, n); /* look up at current level */ - if (v >= 0) { - init_exp(var, VLOCAL, v); + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) { /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } - else { /* not found at current level; try upper one */ - if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) - return VGLOBAL; - var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ - var->k = VUPVAL; /* upvalue in this level */ + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) /* try upper levels */ + return VGLOBAL; /* not found; is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); return VUPVAL; } }