diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-01-13 11:23:07 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-01-13 11:23:07 -0300 |
| commit | 10e931da82268a9d190c17a9bdb9b1a4b48c2947 (patch) | |
| tree | 219fa0c6d517893f4d1bef506d7dd50b1ea958aa | |
| parent | 4b107a87760ee5f85185a904c9088ca476b94be5 (diff) | |
| download | lua-10e931da82268a9d190c17a9bdb9b1a4b48c2947.tar.gz lua-10e931da82268a9d190c17a9bdb9b1a4b48c2947.tar.bz2 lua-10e931da82268a9d190c17a9bdb9b1a4b48c2947.zip | |
Error "break outside loop" made a syntax error
Syntax errors are easier to handle than semantic errors.
| -rw-r--r-- | lparser.c | 25 |
1 files changed, 14 insertions, 11 deletions
| @@ -52,7 +52,7 @@ typedef struct BlockCnt { | |||
| 52 | int firstgoto; /* index of first pending goto in this block */ | 52 | int firstgoto; /* index of first pending goto in this block */ |
| 53 | lu_byte nactvar; /* # active locals outside the block */ | 53 | lu_byte nactvar; /* # active locals outside the block */ |
| 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
| 55 | lu_byte isloop; /* true if 'block' is a loop */ | 55 | lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */ |
| 56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ | 56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ |
| 57 | } BlockCnt; | 57 | } BlockCnt; |
| 58 | 58 | ||
| @@ -677,15 +677,10 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { | |||
| 677 | ** generates an error for an undefined 'goto'. | 677 | ** generates an error for an undefined 'goto'. |
| 678 | */ | 678 | */ |
| 679 | static l_noret undefgoto (LexState *ls, Labeldesc *gt) { | 679 | static l_noret undefgoto (LexState *ls, Labeldesc *gt) { |
| 680 | const char *msg; | 680 | const char *msg = "no visible label '%s' for <goto> at line %d"; |
| 681 | if (eqstr(gt->name, luaS_newliteral(ls->L, "break"))) { | 681 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); |
| 682 | msg = "break outside loop at line %d"; | 682 | /* breaks are checked when created, cannot be undefined */ |
| 683 | msg = luaO_pushfstring(ls->L, msg, gt->line); | 683 | lua_assert(!eqstr(gt->name, luaS_newliteral(ls->L, "break"))); |
| 684 | } | ||
| 685 | else { | ||
| 686 | msg = "no visible label '%s' for <goto> at line %d"; | ||
| 687 | msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); | ||
| 688 | } | ||
| 689 | luaK_semerror(ls, msg); | 684 | luaK_semerror(ls, msg); |
| 690 | } | 685 | } |
| 691 | 686 | ||
| @@ -699,7 +694,7 @@ static void leaveblock (FuncState *fs) { | |||
| 699 | fs->freereg = stklevel; /* free registers */ | 694 | fs->freereg = stklevel; /* free registers */ |
| 700 | removevars(fs, bl->nactvar); /* remove block locals */ | 695 | removevars(fs, bl->nactvar); /* remove block locals */ |
| 701 | lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */ | 696 | lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */ |
| 702 | if (bl->isloop) /* has to fix pending breaks? */ | 697 | if (bl->isloop == 2) /* has to fix pending breaks? */ |
| 703 | createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); | 698 | createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); |
| 704 | solvegotos(fs, bl); | 699 | solvegotos(fs, bl); |
| 705 | if (bl->previous == NULL) { /* was it the last block? */ | 700 | if (bl->previous == NULL) { /* was it the last block? */ |
| @@ -1465,6 +1460,14 @@ static void gotostat (LexState *ls, int line) { | |||
| 1465 | ** Break statement. Semantically equivalent to "goto break". | 1460 | ** Break statement. Semantically equivalent to "goto break". |
| 1466 | */ | 1461 | */ |
| 1467 | static void breakstat (LexState *ls, int line) { | 1462 | static void breakstat (LexState *ls, int line) { |
| 1463 | BlockCnt *bl; /* to look for an enclosing loop */ | ||
| 1464 | for (bl = ls->fs->bl; bl != NULL; bl = bl->previous) { | ||
| 1465 | if (bl->isloop) /* found one? */ | ||
| 1466 | goto ok; | ||
| 1467 | } | ||
| 1468 | luaX_syntaxerror(ls, "break outside loop"); | ||
| 1469 | ok: | ||
| 1470 | bl->isloop = 2; /* signal that block has pending breaks */ | ||
| 1468 | luaX_next(ls); /* skip break */ | 1471 | luaX_next(ls); /* skip break */ |
| 1469 | newgotoentry(ls, luaS_newliteral(ls->L, "break"), line); | 1472 | newgotoentry(ls, luaS_newliteral(ls->L, "break"), line); |
| 1470 | } | 1473 | } |
