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 /lparser.c | |
parent | beab626061a29bd957ae297bd5993cb5b4e15f22 (diff) | |
download | lua-fdede8541965a58be39178528d31cdb397010b94.tar.gz lua-fdede8541965a58be39178528d31cdb397010b94.tar.bz2 lua-fdede8541965a58be39178528d31cdb397010b94.zip |
label names must be unique inside a function
Diffstat (limited to 'lparser.c')
-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); |