From fdede8541965a58be39178528d31cdb397010b94 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 16 Jun 2011 13:36:39 -0300 Subject: [PATCH] label names must be unique inside a function --- lparser.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/lparser.c b/lparser.c index 64c3ccce..c02e4b84 100644 --- a/lparser.c +++ b/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 " ( at line %d) undefined"; + : "no visible label " LUA_QS " for 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);