Browse Source

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

Roberto Ierusalimschy 15 years ago
parent
commit
e560ac4862
1 changed files with 32 additions and 20 deletions
  1. 32 20
      lparser.c

+ 32 - 20
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;
     }
   }