Browse Source

label names must be unique inside a function

Roberto Ierusalimschy 14 năm trước cách đây
mục cha
commit
fdede85419
1 tập tin đã thay đổi với 27 bổ sung12 xóa
  1. 27 12
      lparser.c

+ 27 - 12
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.108 2011/04/18 19:48:24 roberto Exp roberto $
+** $Id: lparser.c,v 2.109 2011/05/02 17:33:01 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -367,7 +367,7 @@ static int findlabel (LexState *ls, int g) {
   /* check labels in current block for a match */
   for (i = bl->firstlabel; i < dyd->label.n; i++) {
     Labeldesc *lb = &dyd->label.arr[i];
-    if (eqstr(lb->name, gt->name)) {  /* correct label? */
+    if (eqstr(lb->name, gt->name) && lb->pc != -1) {  /* correct label? */
       if (gt->nactvar > lb->nactvar &&
           (bl->upval || dyd->label.n > bl->firstlabel))
         luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
@@ -411,7 +411,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
 /*
 ** "export" pending gotos to outer level, to check them against
 ** outer labels; if the block being exited has upvalues, and
-** the goto exists the scope of any variable (which can be the
+** the goto exits the scope of any variable (which can be the
 ** upvalue), close those variables being exited.
 */
 static void movegotosout (FuncState *fs, BlockCnt *bl) {
@@ -460,12 +460,18 @@ static void breaklabel (LexState *ls) {
 static void undefgoto (LexState *ls, Labeldesc *gt) {
   const char *msg = (gt->name->tsv.reserved > 0)
                     ? "<%s> at line %d not inside a loop"
-                    : "label " LUA_QS " (<goto> at line %d) undefined";
+                    : "no visible label " LUA_QS " for <goto> at line %d";
   msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
   semerror(ls, msg);
 }
 
 
+static void invalidatelabels (Labellist *ll, int level) {
+  for (; level < ll->n; level++)
+    ll->arr[level].pc = -1;  /* mark label as out of scope */
+}
+
+
 static void leaveblock (FuncState *fs) {
   BlockCnt *bl = fs->bl;
   LexState *ls = fs->ls;
@@ -481,7 +487,7 @@ static void leaveblock (FuncState *fs) {
   removevars(fs, bl->nactvar);
   lua_assert(bl->nactvar == fs->nactvar);
   fs->freereg = fs->nactvar;  /* free registers */
-  ls->dyd->label.n = bl->firstlabel;  /* remove local labels */
+  invalidatelabels(&ls->dyd->label, bl->firstlabel); /* remove local labels */
   if (bl->previous)  /* inner block? */
     movegotosout(fs, bl);  /* update pending gotos to outer block */
   else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */
@@ -526,6 +532,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
   fs->nlocvars = 0;
   fs->nactvar = 0;
   fs->firstlocal = ls->dyd->actvar.n;
+  fs->firstlabel = ls->dyd->label.n;
   fs->bl = NULL;
   f = luaF_newproto(L);
   fs->f = f;
@@ -548,6 +555,7 @@ static void close_func (LexState *ls) {
   Proto *f = fs->f;
   luaK_ret(fs, 0, 0);  /* final return */
   leaveblock(fs);
+  ls->dyd->label.n = fs->firstlabel;  /* remove labels */
   luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
   f->sizecode = fs->pc;
   luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
@@ -1185,13 +1193,11 @@ static void gotostat (LexState *ls, TString *label, int line) {
 }
 
 
-static void labelstat (LexState *ls, TString *label, int line) {
-  /* label -> '@' NAME ':' */
-  FuncState *fs = ls->fs;
-  Labellist *ll = &ls->dyd->label;
-  int l, i;  /* index of new label being created */
-  /* check for repeated labels on the same block */
-  for (i = ls->fs->bl->firstlabel; i < ll->n; i++) {
+/* check for repeated labels on the same function */
+static void checkrepeated (LexState *ls, FuncState *fs, Labellist *ll,
+                           TString *label) {
+  int i;
+  for (i = fs->firstlabel; i < ll->n; i++) {
     if (eqstr(label, ll->arr[i].name)) {
       const char *msg = luaO_pushfstring(ls->L, 
         "label " LUA_QS " already defined on line %d",
@@ -1199,6 +1205,15 @@ static void labelstat (LexState *ls, TString *label, int line) {
       semerror(ls, msg);
     }
   }
+}
+
+
+static void labelstat (LexState *ls, TString *label, int line) {
+  /* label -> '@' NAME ':' */
+  FuncState *fs = ls->fs;
+  Labellist *ll = &ls->dyd->label;
+  int l;  /* index of new label being created */
+  checkrepeated(ls, fs, ll, label);  /* check for repeated labels */
   checknext(ls, ':');  /* skip colon */
   /* create new entry for this label */
   l = newlabelentry(ls, ll, label, line, fs->pc);