diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-06-16 13:36:39 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-06-16 13:36:39 -0300 |
| commit | fdede8541965a58be39178528d31cdb397010b94 (patch) | |
| tree | fbc2ed2dfe6941bededbdc50823dbd0c022574a2 | |
| parent | beab626061a29bd957ae297bd5993cb5b4e15f22 (diff) | |
| download | lua-fdede8541965a58be39178528d31cdb397010b94.tar.gz lua-fdede8541965a58be39178528d31cdb397010b94.tar.bz2 lua-fdede8541965a58be39178528d31cdb397010b94.zip | |
label names must be unique inside a function
| -rw-r--r-- | lparser.c | 39 |
1 files changed, 27 insertions, 12 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.c,v 2.108 2011/04/18 19:48:24 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 2.109 2011/05/02 17:33:01 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 | */ |
| @@ -367,7 +367,7 @@ static int findlabel (LexState *ls, int g) { | |||
| 367 | /* check labels in current block for a match */ | 367 | /* check labels in current block for a match */ |
| 368 | for (i = bl->firstlabel; i < dyd->label.n; i++) { | 368 | for (i = bl->firstlabel; i < dyd->label.n; i++) { |
| 369 | Labeldesc *lb = &dyd->label.arr[i]; | 369 | Labeldesc *lb = &dyd->label.arr[i]; |
| 370 | if (eqstr(lb->name, gt->name)) { /* correct label? */ | 370 | if (eqstr(lb->name, gt->name) && lb->pc != -1) { /* correct label? */ |
| 371 | if (gt->nactvar > lb->nactvar && | 371 | if (gt->nactvar > lb->nactvar && |
| 372 | (bl->upval || dyd->label.n > bl->firstlabel)) | 372 | (bl->upval || dyd->label.n > bl->firstlabel)) |
| 373 | luaK_patchclose(ls->fs, gt->pc, lb->nactvar); | 373 | luaK_patchclose(ls->fs, gt->pc, lb->nactvar); |
| @@ -411,7 +411,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { | |||
| 411 | /* | 411 | /* |
| 412 | ** "export" pending gotos to outer level, to check them against | 412 | ** "export" pending gotos to outer level, to check them against |
| 413 | ** outer labels; if the block being exited has upvalues, and | 413 | ** outer labels; if the block being exited has upvalues, and |
| 414 | ** the goto exists the scope of any variable (which can be the | 414 | ** the goto exits the scope of any variable (which can be the |
| 415 | ** upvalue), close those variables being exited. | 415 | ** upvalue), close those variables being exited. |
| 416 | */ | 416 | */ |
| 417 | static void movegotosout (FuncState *fs, BlockCnt *bl) { | 417 | static void movegotosout (FuncState *fs, BlockCnt *bl) { |
| @@ -460,12 +460,18 @@ static void breaklabel (LexState *ls) { | |||
| 460 | static void undefgoto (LexState *ls, Labeldesc *gt) { | 460 | static void undefgoto (LexState *ls, Labeldesc *gt) { |
| 461 | const char *msg = (gt->name->tsv.reserved > 0) | 461 | const char *msg = (gt->name->tsv.reserved > 0) |
| 462 | ? "<%s> at line %d not inside a loop" | 462 | ? "<%s> at line %d not inside a loop" |
| 463 | : "label " LUA_QS " (<goto> at line %d) undefined"; | 463 | : "no visible label " LUA_QS " for <goto> at line %d"; |
| 464 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); | 464 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); |
| 465 | semerror(ls, msg); | 465 | semerror(ls, msg); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | 468 | ||
| 469 | static void invalidatelabels (Labellist *ll, int level) { | ||
| 470 | for (; level < ll->n; level++) | ||
| 471 | ll->arr[level].pc = -1; /* mark label as out of scope */ | ||
| 472 | } | ||
| 473 | |||
| 474 | |||
| 469 | static void leaveblock (FuncState *fs) { | 475 | static void leaveblock (FuncState *fs) { |
| 470 | BlockCnt *bl = fs->bl; | 476 | BlockCnt *bl = fs->bl; |
| 471 | LexState *ls = fs->ls; | 477 | LexState *ls = fs->ls; |
| @@ -481,7 +487,7 @@ static void leaveblock (FuncState *fs) { | |||
| 481 | removevars(fs, bl->nactvar); | 487 | removevars(fs, bl->nactvar); |
| 482 | lua_assert(bl->nactvar == fs->nactvar); | 488 | lua_assert(bl->nactvar == fs->nactvar); |
| 483 | fs->freereg = fs->nactvar; /* free registers */ | 489 | fs->freereg = fs->nactvar; /* free registers */ |
| 484 | ls->dyd->label.n = bl->firstlabel; /* remove local labels */ | 490 | invalidatelabels(&ls->dyd->label, bl->firstlabel); /* remove local labels */ |
| 485 | if (bl->previous) /* inner block? */ | 491 | if (bl->previous) /* inner block? */ |
| 486 | movegotosout(fs, bl); /* update pending gotos to outer block */ | 492 | movegotosout(fs, bl); /* update pending gotos to outer block */ |
| 487 | else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ | 493 | 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) { | |||
| 526 | fs->nlocvars = 0; | 532 | fs->nlocvars = 0; |
| 527 | fs->nactvar = 0; | 533 | fs->nactvar = 0; |
| 528 | fs->firstlocal = ls->dyd->actvar.n; | 534 | fs->firstlocal = ls->dyd->actvar.n; |
| 535 | fs->firstlabel = ls->dyd->label.n; | ||
| 529 | fs->bl = NULL; | 536 | fs->bl = NULL; |
| 530 | f = luaF_newproto(L); | 537 | f = luaF_newproto(L); |
| 531 | fs->f = f; | 538 | fs->f = f; |
| @@ -548,6 +555,7 @@ static void close_func (LexState *ls) { | |||
| 548 | Proto *f = fs->f; | 555 | Proto *f = fs->f; |
| 549 | luaK_ret(fs, 0, 0); /* final return */ | 556 | luaK_ret(fs, 0, 0); /* final return */ |
| 550 | leaveblock(fs); | 557 | leaveblock(fs); |
| 558 | ls->dyd->label.n = fs->firstlabel; /* remove labels */ | ||
| 551 | luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); | 559 | luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); |
| 552 | f->sizecode = fs->pc; | 560 | f->sizecode = fs->pc; |
| 553 | luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); | 561 | luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); |
| @@ -1185,13 +1193,11 @@ static void gotostat (LexState *ls, TString *label, int line) { | |||
| 1185 | } | 1193 | } |
| 1186 | 1194 | ||
| 1187 | 1195 | ||
| 1188 | static void labelstat (LexState *ls, TString *label, int line) { | 1196 | /* check for repeated labels on the same function */ |
| 1189 | /* label -> '@' NAME ':' */ | 1197 | static void checkrepeated (LexState *ls, FuncState *fs, Labellist *ll, |
| 1190 | FuncState *fs = ls->fs; | 1198 | TString *label) { |
| 1191 | Labellist *ll = &ls->dyd->label; | 1199 | int i; |
| 1192 | int l, i; /* index of new label being created */ | 1200 | for (i = fs->firstlabel; i < ll->n; i++) { |
| 1193 | /* check for repeated labels on the same block */ | ||
| 1194 | for (i = ls->fs->bl->firstlabel; i < ll->n; i++) { | ||
| 1195 | if (eqstr(label, ll->arr[i].name)) { | 1201 | if (eqstr(label, ll->arr[i].name)) { |
| 1196 | const char *msg = luaO_pushfstring(ls->L, | 1202 | const char *msg = luaO_pushfstring(ls->L, |
| 1197 | "label " LUA_QS " already defined on line %d", | 1203 | "label " LUA_QS " already defined on line %d", |
| @@ -1199,6 +1205,15 @@ static void labelstat (LexState *ls, TString *label, int line) { | |||
| 1199 | semerror(ls, msg); | 1205 | semerror(ls, msg); |
| 1200 | } | 1206 | } |
| 1201 | } | 1207 | } |
| 1208 | } | ||
| 1209 | |||
| 1210 | |||
| 1211 | static void labelstat (LexState *ls, TString *label, int line) { | ||
| 1212 | /* label -> '@' NAME ':' */ | ||
| 1213 | FuncState *fs = ls->fs; | ||
| 1214 | Labellist *ll = &ls->dyd->label; | ||
| 1215 | int l; /* index of new label being created */ | ||
| 1216 | checkrepeated(ls, fs, ll, label); /* check for repeated labels */ | ||
| 1202 | checknext(ls, ':'); /* skip colon */ | 1217 | checknext(ls, ':'); /* skip colon */ |
| 1203 | /* create new entry for this label */ | 1218 | /* create new entry for this label */ |
| 1204 | l = newlabelentry(ls, ll, label, line, fs->pc); | 1219 | l = newlabelentry(ls, ll, label, line, fs->pc); |
