diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-29 14:26:48 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-29 14:26:48 -0300 |
| commit | a006514ea138a29b6031058d9002b48a572b5dd6 (patch) | |
| tree | b289a8af0c0497f2555784a0cf666659ceab0236 /lparser.c | |
| parent | 6e9b719694bffb8de711f182d405ec37d32ae0b1 (diff) | |
| download | lua-a006514ea138a29b6031058d9002b48a572b5dd6.tar.gz lua-a006514ea138a29b6031058d9002b48a572b5dd6.tar.bz2 lua-a006514ea138a29b6031058d9002b48a572b5dd6.zip | |
Big revamp in the implmentation of labels/gotos
Added restriction that, when a label is created, there cannot be
another label with the same name visible. That allows backward goto's
to be resolved when they are read. Backward goto's get a close if
they jump out of the scope of some variable; labels get a close only
if previous goto to it jumps out of the scope of some upvalue.
Diffstat (limited to 'lparser.c')
| -rw-r--r-- | lparser.c | 241 |
1 files changed, 117 insertions, 124 deletions
| @@ -49,8 +49,6 @@ typedef struct BlockCnt { | |||
| 49 | struct BlockCnt *previous; /* chain */ | 49 | struct BlockCnt *previous; /* chain */ |
| 50 | int firstlabel; /* index of first label in this block */ | 50 | int firstlabel; /* index of first label in this block */ |
| 51 | int firstgoto; /* index of first pending goto in this block */ | 51 | int firstgoto; /* index of first pending goto in this block */ |
| 52 | int brks; /* list of break jumps in this block */ | ||
| 53 | lu_byte brkcls; /* true if some 'break' needs to close upvalues */ | ||
| 54 | lu_byte nactvar; /* # active locals outside the block */ | 52 | lu_byte nactvar; /* # active locals outside the block */ |
| 55 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 53 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
| 56 | lu_byte isloop; /* true if 'block' is a loop */ | 54 | lu_byte isloop; /* true if 'block' is a loop */ |
| @@ -330,50 +328,56 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { | |||
| 330 | #define leavelevel(ls) ((ls)->L->nCcalls--) | 328 | #define leavelevel(ls) ((ls)->L->nCcalls--) |
| 331 | 329 | ||
| 332 | 330 | ||
| 333 | static void closegoto (LexState *ls, int g, Labeldesc *label) { | 331 | /* |
| 332 | ** Generates an error that a goto jumps into the scope of some | ||
| 333 | ** local variable. | ||
| 334 | */ | ||
| 335 | static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { | ||
| 336 | const char *varname = getstr(getlocvar(ls->fs, gt->nactvar)->varname); | ||
| 337 | const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; | ||
| 338 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); | ||
| 339 | luaK_semerror(ls, msg); /* raise the error */ | ||
| 340 | } | ||
| 341 | |||
| 342 | |||
| 343 | /* | ||
| 344 | ** Solves the goto at index 'g' to given 'label' and removes it | ||
| 345 | ** from the list of pending goto's. | ||
| 346 | ** If it jumps into the scope of some variable, raises an error. | ||
| 347 | */ | ||
| 348 | static void solvegoto (LexState *ls, int g, Labeldesc *label) { | ||
| 334 | int i; | 349 | int i; |
| 335 | FuncState *fs = ls->fs; | 350 | Labellist *gl = &ls->dyd->gt; /* list of goto's */ |
| 336 | Labellist *gl = &ls->dyd->gt; | 351 | Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ |
| 337 | Labeldesc *gt = &gl->arr[g]; | ||
| 338 | lua_assert(eqstr(gt->name, label->name)); | 352 | lua_assert(eqstr(gt->name, label->name)); |
| 339 | if (gt->nactvar < label->nactvar) { | 353 | if (gt->nactvar < label->nactvar) /* enter some scope? */ |
| 340 | TString *vname = getlocvar(fs, gt->nactvar)->varname; | 354 | jumpscopeerror(ls, gt); |
| 341 | const char *msg = luaO_pushfstring(ls->L, | 355 | luaK_patchlist(ls->fs, gt->pc, label->pc); |
| 342 | "<goto %s> at line %d jumps into the scope of local '%s'", | 356 | for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ |
| 343 | getstr(gt->name), gt->line, getstr(vname)); | ||
| 344 | luaK_semerror(ls, msg); | ||
| 345 | } | ||
| 346 | luaK_patchgoto(fs, gt->pc, label->pc, 1); | ||
| 347 | /* remove goto from pending list */ | ||
| 348 | for (i = g; i < gl->n - 1; i++) | ||
| 349 | gl->arr[i] = gl->arr[i + 1]; | 357 | gl->arr[i] = gl->arr[i + 1]; |
| 350 | gl->n--; | 358 | gl->n--; |
| 351 | } | 359 | } |
| 352 | 360 | ||
| 353 | 361 | ||
| 354 | /* | 362 | /* |
| 355 | ** try to close a goto with existing labels; this solves backward jumps | 363 | ** Search for an active label with the given name. |
| 356 | */ | 364 | */ |
| 357 | static int solvelabel (LexState *ls, int g) { | 365 | static Labeldesc *findlabel (LexState *ls, TString *name) { |
| 358 | int i; | 366 | int i; |
| 359 | BlockCnt *bl = ls->fs->bl; | ||
| 360 | Dyndata *dyd = ls->dyd; | 367 | Dyndata *dyd = ls->dyd; |
| 361 | Labeldesc *gt = &dyd->gt.arr[g]; | 368 | /* check labels in current function for a match */ |
| 362 | /* check labels in current block for a match */ | 369 | for (i = ls->fs->firstlabel; i < dyd->label.n; i++) { |
| 363 | for (i = bl->firstlabel; i < dyd->label.n; i++) { | ||
| 364 | Labeldesc *lb = &dyd->label.arr[i]; | 370 | Labeldesc *lb = &dyd->label.arr[i]; |
| 365 | if (eqstr(lb->name, gt->name)) { /* correct label? */ | 371 | if (eqstr(lb->name, name)) /* correct label? */ |
| 366 | if (gt->nactvar > lb->nactvar && | 372 | return lb; |
| 367 | (bl->upval || dyd->label.n > bl->firstlabel)) | ||
| 368 | luaK_patchclose(ls->fs, gt->pc); | ||
| 369 | closegoto(ls, g, lb); /* close it */ | ||
| 370 | return 1; | ||
| 371 | } | ||
| 372 | } | 373 | } |
| 373 | return 0; /* label not found; cannot close goto */ | 374 | return NULL; /* label not found */ |
| 374 | } | 375 | } |
| 375 | 376 | ||
| 376 | 377 | ||
| 378 | /* | ||
| 379 | ** Adds a new label/goto in the corresponding list. | ||
| 380 | */ | ||
| 377 | static int newlabelentry (LexState *ls, Labellist *l, TString *name, | 381 | static int newlabelentry (LexState *ls, Labellist *l, TString *name, |
| 378 | int line, int pc) { | 382 | int line, int pc) { |
| 379 | int n = l->n; | 383 | int n = l->n; |
| @@ -382,6 +386,7 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name, | |||
| 382 | l->arr[n].name = name; | 386 | l->arr[n].name = name; |
| 383 | l->arr[n].line = line; | 387 | l->arr[n].line = line; |
| 384 | l->arr[n].nactvar = ls->fs->nactvar; | 388 | l->arr[n].nactvar = ls->fs->nactvar; |
| 389 | l->arr[n].close = 0; | ||
| 385 | l->arr[n].pc = pc; | 390 | l->arr[n].pc = pc; |
| 386 | l->n = n + 1; | 391 | l->n = n + 1; |
| 387 | return n; | 392 | return n; |
| @@ -389,51 +394,64 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name, | |||
| 389 | 394 | ||
| 390 | 395 | ||
| 391 | /* | 396 | /* |
| 392 | ** check whether new label 'lb' matches any pending gotos in current | 397 | ** Solves forward jumps. Check whether new label 'lb' matches any |
| 393 | ** block; solves forward jumps | 398 | ** pending gotos in current block and solves them. Return true |
| 399 | ** if any of the goto's need to close upvalues. | ||
| 394 | */ | 400 | */ |
| 395 | static void solvegotos (LexState *ls, Labeldesc *lb) { | 401 | static int solvegotos (LexState *ls, Labeldesc *lb) { |
| 396 | Labellist *gl = &ls->dyd->gt; | 402 | Labellist *gl = &ls->dyd->gt; |
| 397 | int i = ls->fs->bl->firstgoto; | 403 | int i = ls->fs->bl->firstgoto; |
| 404 | int needsclose = 0; | ||
| 398 | while (i < gl->n) { | 405 | while (i < gl->n) { |
| 399 | if (eqstr(gl->arr[i].name, lb->name)) | 406 | if (eqstr(gl->arr[i].name, lb->name)) { |
| 400 | closegoto(ls, i, lb); /* will remove 'i' from the list */ | 407 | needsclose |= gl->arr[i].close; |
| 408 | solvegoto(ls, i, lb); /* will remove 'i' from the list */ | ||
| 409 | } | ||
| 401 | else | 410 | else |
| 402 | i++; | 411 | i++; |
| 403 | } | 412 | } |
| 413 | return needsclose; | ||
| 414 | } | ||
| 415 | |||
| 416 | |||
| 417 | /* | ||
| 418 | ** Create a new label with the given 'name' at the given 'line'. | ||
| 419 | ** 'last' tells whether label is the last non-op statement in its | ||
| 420 | ** block. Solves all pending goto's to this new label and adds | ||
| 421 | ** a close instruction if necessary. | ||
| 422 | ** Returns true iff it added a close instruction. | ||
| 423 | */ | ||
| 424 | static int createlabel (LexState *ls, TString *name, int line, | ||
| 425 | int last) { | ||
| 426 | FuncState *fs = ls->fs; | ||
| 427 | Labellist *ll = &ls->dyd->label; | ||
| 428 | int l = newlabelentry(ls, ll, name, line, luaK_getlabel(fs)); | ||
| 429 | if (last) { /* label is last no-op statement in the block? */ | ||
| 430 | /* assume that locals are already out of scope */ | ||
| 431 | ll->arr[l].nactvar = fs->bl->nactvar; | ||
| 432 | } | ||
| 433 | if (solvegotos(ls, &ll->arr[l])) { /* need close? */ | ||
| 434 | luaK_codeABC(fs, OP_CLOSE, fs->nactvar, 0, 0); | ||
| 435 | return 1; | ||
| 436 | } | ||
| 437 | return 0; | ||
| 404 | } | 438 | } |
| 405 | 439 | ||
| 406 | 440 | ||
| 407 | /* | 441 | /* |
| 408 | ** export pending gotos to outer level, to check them against | 442 | ** Adjust pending gotos to outer level of a block. |
| 409 | ** outer labels; if the block being exited has upvalues, and | ||
| 410 | ** the goto exits the scope of any variable (which can be the | ||
| 411 | ** upvalue), close those variables being exited. Also export | ||
| 412 | ** break list. | ||
| 413 | */ | 443 | */ |
| 414 | static void movegotosout (FuncState *fs, BlockCnt *bl) { | 444 | static void movegotosout (FuncState *fs, BlockCnt *bl) { |
| 415 | int i = bl->firstgoto; | 445 | int i; |
| 416 | Labellist *gl = &fs->ls->dyd->gt; | 446 | Labellist *gl = &fs->ls->dyd->gt; |
| 417 | /* correct pending gotos to current block and try to close it | 447 | /* correct pending gotos to current block */ |
| 418 | with visible labels */ | 448 | for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */ |
| 419 | while (i < gl->n) { /* for each pending goto */ | ||
| 420 | Labeldesc *gt = &gl->arr[i]; | 449 | Labeldesc *gt = &gl->arr[i]; |
| 421 | if (gt->nactvar > bl->nactvar) { /* leaving a variable scope? */ | 450 | if (gt->nactvar > bl->nactvar) { /* leaving a variable scope? */ |
| 422 | if (bl->upval) /* variable may be an upvalue? */ | ||
| 423 | luaK_patchclose(fs, gt->pc); /* jump will need a close */ | ||
| 424 | gt->nactvar = bl->nactvar; /* update goto level */ | 451 | gt->nactvar = bl->nactvar; /* update goto level */ |
| 452 | gt->close |= bl->upval; /* jump may need a close */ | ||
| 425 | } | 453 | } |
| 426 | if (!solvelabel(fs->ls, i)) | ||
| 427 | i++; /* move to next one */ | ||
| 428 | /* else, 'solvelabel' removed current goto from the list | ||
| 429 | and 'i' now points to next one */ | ||
| 430 | } | 454 | } |
| 431 | /* handles break list */ | ||
| 432 | if (bl->upval) /* exiting the scope of an upvalue? */ | ||
| 433 | luaK_patchclose(fs, bl->brks); /* breaks will need OP_CLOSE */ | ||
| 434 | /* move breaks to outer block */ | ||
| 435 | luaK_concat(fs, &bl->previous->brks, bl->brks); | ||
| 436 | bl->previous->brkcls |= bl->brkcls; | ||
| 437 | } | 455 | } |
| 438 | 456 | ||
| 439 | 457 | ||
| @@ -442,8 +460,6 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { | |||
| 442 | bl->nactvar = fs->nactvar; | 460 | bl->nactvar = fs->nactvar; |
| 443 | bl->firstlabel = fs->ls->dyd->label.n; | 461 | bl->firstlabel = fs->ls->dyd->label.n; |
| 444 | bl->firstgoto = fs->ls->dyd->gt.n; | 462 | bl->firstgoto = fs->ls->dyd->gt.n; |
| 445 | bl->brks = NO_JUMP; | ||
| 446 | bl->brkcls = 0; | ||
| 447 | bl->upval = 0; | 463 | bl->upval = 0; |
| 448 | bl->previous = fs->bl; | 464 | bl->previous = fs->bl; |
| 449 | fs->bl = bl; | 465 | fs->bl = bl; |
| @@ -452,20 +468,6 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { | |||
| 452 | 468 | ||
| 453 | 469 | ||
| 454 | /* | 470 | /* |
| 455 | ** Fix all breaks in block 'bl' to jump to the end of the block. | ||
| 456 | */ | ||
| 457 | static void fixbreaks (FuncState *fs, BlockCnt *bl) { | ||
| 458 | int target = fs->pc; | ||
| 459 | if (bl->brkcls) /* does the block need to close upvalues? */ | ||
| 460 | luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); | ||
| 461 | luaK_patchgoto(fs, bl->brks, target, bl->brkcls); | ||
| 462 | bl->brks = NO_JUMP; /* no more breaks to fix */ | ||
| 463 | bl->brkcls = 0; /* no more need to close upvalues */ | ||
| 464 | lua_assert(!bl->upval); /* loop body cannot have local variables */ | ||
| 465 | } | ||
| 466 | |||
| 467 | |||
| 468 | /* | ||
| 469 | ** generates an error for an undefined 'goto'. | 471 | ** generates an error for an undefined 'goto'. |
| 470 | */ | 472 | */ |
| 471 | static l_noret undefgoto (LexState *ls, Labeldesc *gt) { | 473 | static l_noret undefgoto (LexState *ls, Labeldesc *gt) { |
| @@ -478,11 +480,10 @@ static l_noret undefgoto (LexState *ls, Labeldesc *gt) { | |||
| 478 | static void leaveblock (FuncState *fs) { | 480 | static void leaveblock (FuncState *fs) { |
| 479 | BlockCnt *bl = fs->bl; | 481 | BlockCnt *bl = fs->bl; |
| 480 | LexState *ls = fs->ls; | 482 | LexState *ls = fs->ls; |
| 481 | if (bl->upval && bl->brks != NO_JUMP) /* breaks in upvalue scopes? */ | 483 | int hasclose = 0; |
| 482 | bl->brkcls = 1; /* these breaks must close the upvalues */ | 484 | if (bl->isloop) /* fix pending breaks? */ |
| 483 | if (bl->isloop) | 485 | hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); |
| 484 | fixbreaks(fs, bl); /* fix pending breaks */ | 486 | if (!hasclose && bl->previous && bl->upval) |
| 485 | if (bl->previous && bl->upval) | ||
| 486 | luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); | 487 | luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); |
| 487 | fs->bl = bl->previous; | 488 | fs->bl = bl->previous; |
| 488 | removevars(fs, bl->nactvar); | 489 | removevars(fs, bl->nactvar); |
| @@ -492,7 +493,6 @@ static void leaveblock (FuncState *fs) { | |||
| 492 | if (bl->previous) /* inner block? */ | 493 | if (bl->previous) /* inner block? */ |
| 493 | movegotosout(fs, bl); /* update pending gotos to outer block */ | 494 | movegotosout(fs, bl); /* update pending gotos to outer block */ |
| 494 | else { | 495 | else { |
| 495 | lua_assert(bl->brks == NO_JUMP); /* no pending breaks */ | ||
| 496 | if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ | 496 | if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ |
| 497 | undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ | 497 | undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ |
| 498 | } | 498 | } |
| @@ -550,6 +550,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { | |||
| 550 | fs->nactvar = 0; | 550 | fs->nactvar = 0; |
| 551 | fs->needclose = 0; | 551 | fs->needclose = 0; |
| 552 | fs->firstlocal = ls->dyd->actvar.n; | 552 | fs->firstlocal = ls->dyd->actvar.n; |
| 553 | fs->firstlabel = ls->dyd->label.n; | ||
| 553 | fs->bl = NULL; | 554 | fs->bl = NULL; |
| 554 | f->source = ls->source; | 555 | f->source = ls->source; |
| 555 | f->maxstacksize = 2; /* registers 0/1 are always valid */ | 556 | f->maxstacksize = 2; /* registers 0/1 are always valid */ |
| @@ -1204,63 +1205,59 @@ static int cond (LexState *ls) { | |||
| 1204 | } | 1205 | } |
| 1205 | 1206 | ||
| 1206 | 1207 | ||
| 1207 | static void gotostat (LexState *ls, int pc) { | 1208 | static void gotostat (LexState *ls) { |
| 1209 | FuncState *fs = ls->fs; | ||
| 1208 | int line = ls->linenumber; | 1210 | int line = ls->linenumber; |
| 1209 | int g; | 1211 | TString *name = str_checkname(ls); /* label's name */ |
| 1210 | luaX_next(ls); /* skip 'goto' */ | 1212 | Labeldesc *lb = findlabel(ls, name); |
| 1211 | g = newlabelentry(ls, &ls->dyd->gt, str_checkname(ls), line, pc); | 1213 | if (lb == NULL) /* no label? */ |
| 1212 | solvelabel(ls, g); /* close it if label already defined */ | 1214 | /* forward jump; will be resolved when the label is declared */ |
| 1215 | newlabelentry(ls, &ls->dyd->gt, name, line, luaK_jump(fs)); | ||
| 1216 | else { /* found a label */ | ||
| 1217 | /* backward jump; will be resolved here */ | ||
| 1218 | if (fs->nactvar > lb->nactvar) /* leaving the scope of some variable? */ | ||
| 1219 | luaK_codeABC(fs, OP_CLOSE, lb->nactvar, 0, 0); | ||
| 1220 | /* create jump and link it to the label */ | ||
| 1221 | luaK_patchlist(fs, luaK_jump(fs), lb->pc); | ||
| 1222 | } | ||
| 1213 | } | 1223 | } |
| 1214 | 1224 | ||
| 1215 | 1225 | ||
| 1226 | /* | ||
| 1227 | ** Break statement. Semantically equivalent to "goto break". | ||
| 1228 | */ | ||
| 1216 | static void breakstat (LexState *ls, int pc) { | 1229 | static void breakstat (LexState *ls, int pc) { |
| 1217 | FuncState *fs = ls->fs; | 1230 | FuncState *fs = ls->fs; |
| 1231 | int line = ls->linenumber; | ||
| 1218 | BlockCnt *bl = fs->bl; | 1232 | BlockCnt *bl = fs->bl; |
| 1219 | luaX_next(ls); /* skip break */ | 1233 | luaX_next(ls); /* skip break */ |
| 1234 | newlabelentry(ls, &ls->dyd->gt, luaS_newliteral(ls->L, "break"), line, pc); | ||
| 1220 | while (bl && !bl->isloop) { bl = bl->previous; } | 1235 | while (bl && !bl->isloop) { bl = bl->previous; } |
| 1221 | if (!bl) | 1236 | if (!bl) |
| 1222 | luaX_syntaxerror(ls, "no loop to break"); | 1237 | luaX_syntaxerror(ls, "no loop to break"); |
| 1223 | luaK_concat(fs, &fs->bl->brks, pc); | ||
| 1224 | } | 1238 | } |
| 1225 | 1239 | ||
| 1226 | 1240 | ||
| 1227 | /* check for repeated labels on the same block */ | 1241 | /* |
| 1228 | static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { | 1242 | ** Check whether there is already a label with the given 'name'. |
| 1229 | int i; | 1243 | */ |
| 1230 | for (i = fs->bl->firstlabel; i < ll->n; i++) { | 1244 | static void checkrepeated (LexState *ls, TString *name) { |
| 1231 | if (eqstr(label, ll->arr[i].name)) { | 1245 | Labeldesc *lb = findlabel(ls, name); |
| 1232 | const char *msg = luaO_pushfstring(fs->ls->L, | 1246 | if (lb != NULL) { /* already defined? */ |
| 1233 | "label '%s' already defined on line %d", | 1247 | const char *msg = "label '%s' already defined on line %d"; |
| 1234 | getstr(label), ll->arr[i].line); | 1248 | msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); |
| 1235 | luaK_semerror(fs->ls, msg); | 1249 | luaK_semerror(ls, msg); /* error */ |
| 1236 | } | ||
| 1237 | } | 1250 | } |
| 1238 | } | 1251 | } |
| 1239 | 1252 | ||
| 1240 | 1253 | ||
| 1241 | /* skip no-op statements */ | 1254 | static void labelstat (LexState *ls, TString *name, int line) { |
| 1242 | static void skipnoopstat (LexState *ls) { | ||
| 1243 | while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) | ||
| 1244 | statement(ls); | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | |||
| 1248 | static void labelstat (LexState *ls, TString *label, int line) { | ||
| 1249 | /* label -> '::' NAME '::' */ | 1255 | /* label -> '::' NAME '::' */ |
| 1250 | FuncState *fs = ls->fs; | ||
| 1251 | Labellist *ll = &ls->dyd->label; | ||
| 1252 | int l; /* index of new label being created */ | ||
| 1253 | checkrepeated(fs, ll, label); /* check for repeated labels */ | ||
| 1254 | checknext(ls, TK_DBCOLON); /* skip double colon */ | 1256 | checknext(ls, TK_DBCOLON); /* skip double colon */ |
| 1255 | /* create new entry for this label */ | 1257 | while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) |
| 1256 | l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); | 1258 | statement(ls); /* skip other no-op statements */ |
| 1257 | luaK_codeABC(fs, OP_CLOSE, fs->nactvar, 0, 0); | 1259 | checkrepeated(ls, name); /* check for repeated labels */ |
| 1258 | skipnoopstat(ls); /* skip other no-op statements */ | 1260 | createlabel(ls, name, line, block_follow(ls, 0)); |
| 1259 | if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ | ||
| 1260 | /* assume that locals are already out of scope */ | ||
| 1261 | ll->arr[l].nactvar = fs->bl->nactvar; | ||
| 1262 | } | ||
| 1263 | solvegotos(ls, &ll->arr[l]); | ||
| 1264 | } | 1261 | } |
| 1265 | 1262 | ||
| 1266 | 1263 | ||
| @@ -1295,8 +1292,6 @@ static void repeatstat (LexState *ls, int line) { | |||
| 1295 | statlist(ls); | 1292 | statlist(ls); |
| 1296 | check_match(ls, TK_UNTIL, TK_REPEAT, line); | 1293 | check_match(ls, TK_UNTIL, TK_REPEAT, line); |
| 1297 | condexit = cond(ls); /* read condition (inside scope block) */ | 1294 | condexit = cond(ls); /* read condition (inside scope block) */ |
| 1298 | if (bl2.upval) /* upvalues? */ | ||
| 1299 | luaK_patchclose(fs, condexit); | ||
| 1300 | leaveblock(fs); /* finish scope */ | 1295 | leaveblock(fs); /* finish scope */ |
| 1301 | if (bl2.upval) { /* upvalues? */ | 1296 | if (bl2.upval) { /* upvalues? */ |
| 1302 | int exit = luaK_jump(fs); /* normal exit must jump over fix */ | 1297 | int exit = luaK_jump(fs); /* normal exit must jump over fix */ |
| @@ -1453,15 +1448,12 @@ static void test_then_block (LexState *ls, int *escapelist) { | |||
| 1453 | luaX_next(ls); /* skip IF or ELSEIF */ | 1448 | luaX_next(ls); /* skip IF or ELSEIF */ |
| 1454 | expr(ls, &v); /* read condition */ | 1449 | expr(ls, &v); /* read condition */ |
| 1455 | checknext(ls, TK_THEN); | 1450 | checknext(ls, TK_THEN); |
| 1456 | if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { | 1451 | if (ls->t.token == TK_BREAK) { |
| 1457 | luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ | 1452 | luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ |
| 1458 | enterblock(fs, &bl, 0); /* must enter block before 'goto' */ | 1453 | enterblock(fs, &bl, 0); /* must enter block before 'goto' */ |
| 1459 | if (ls->t.token == TK_GOTO) | 1454 | breakstat(ls, v.t); /* handle break */ |
| 1460 | gotostat(ls, v.t); /* handle goto */ | ||
| 1461 | else | ||
| 1462 | breakstat(ls, v.t); /* handle break */ | ||
| 1463 | while (testnext(ls, ';')) {} /* skip semicolons */ | 1455 | while (testnext(ls, ';')) {} /* skip semicolons */ |
| 1464 | if (block_follow(ls, 0)) { /* 'goto'/'break' is the entire block? */ | 1456 | if (block_follow(ls, 0)) { /* 'break' is the entire block? */ |
| 1465 | leaveblock(fs); | 1457 | leaveblock(fs); |
| 1466 | return; /* and that is it */ | 1458 | return; /* and that is it */ |
| 1467 | } | 1459 | } |
| @@ -1683,7 +1675,8 @@ static void statement (LexState *ls) { | |||
| 1683 | break; | 1675 | break; |
| 1684 | } | 1676 | } |
| 1685 | case TK_GOTO: { /* stat -> 'goto' NAME */ | 1677 | case TK_GOTO: { /* stat -> 'goto' NAME */ |
| 1686 | gotostat(ls, luaK_jump(ls->fs)); | 1678 | luaX_next(ls); /* skip 'goto' */ |
| 1679 | gotostat(ls); | ||
| 1687 | break; | 1680 | break; |
| 1688 | } | 1681 | } |
| 1689 | default: { /* stat -> func | assignment */ | 1682 | default: { /* stat -> func | assignment */ |
