2
0
Эх сурвалжийг харах

Error "break outside loop" made a syntax error

Syntax errors are easier to handle than semantic errors.
Roberto Ierusalimschy 6 сар өмнө
parent
commit
10e931da82
1 өөрчлөгдсөн 14 нэмэгдсэн , 11 устгасан
  1. 14 11
      lparser.c

+ 14 - 11
lparser.c

@@ -52,7 +52,7 @@ typedef struct BlockCnt {
   int firstgoto;  /* index of first pending goto in this block */
   lu_byte nactvar;  /* # active locals outside the block */
   lu_byte upval;  /* true if some variable in the block is an upvalue */
-  lu_byte isloop;  /* true if 'block' is a loop */
+  lu_byte isloop;  /* 1 if 'block' is a loop; 2 if it has pending breaks */
   lu_byte insidetbc;  /* true if inside the scope of a to-be-closed var. */
 } BlockCnt;
 
@@ -677,15 +677,10 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
 ** generates an error for an undefined 'goto'.
 */
 static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
-  const char *msg;
-  if (eqstr(gt->name, luaS_newliteral(ls->L, "break"))) {
-    msg = "break outside loop at line %d";
-    msg = luaO_pushfstring(ls->L, msg, gt->line);
-  }
-  else {
-    msg = "no visible label '%s' for <goto> at line %d";
-    msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
-  }
+  const char *msg = "no visible label '%s' for <goto> at line %d";
+  msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
+  /* breaks are checked when created, cannot be undefined */
+  lua_assert(!eqstr(gt->name, luaS_newliteral(ls->L, "break")));
   luaK_semerror(ls, msg);
 }
 
@@ -699,7 +694,7 @@ static void leaveblock (FuncState *fs) {
   fs->freereg = stklevel;  /* free registers */
   removevars(fs, bl->nactvar);  /* remove block locals */
   lua_assert(bl->nactvar == fs->nactvar);  /* back to level on entry */
-  if (bl->isloop)  /* has to fix pending breaks? */
+  if (bl->isloop == 2)  /* has to fix pending breaks? */
     createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
   solvegotos(fs, bl);
   if (bl->previous == NULL) {  /* was it the last block? */
@@ -1465,6 +1460,14 @@ static void gotostat (LexState *ls, int line) {
 ** Break statement. Semantically equivalent to "goto break".
 */
 static void breakstat (LexState *ls, int line) {
+  BlockCnt *bl;  /* to look for an enclosing loop */
+  for (bl = ls->fs->bl; bl != NULL; bl = bl->previous) {
+    if (bl->isloop)  /* found one? */
+      goto ok;
+  }
+  luaX_syntaxerror(ls, "break outside loop");
+ ok:
+  bl->isloop = 2;  /* signal that block has pending breaks */
   luaX_next(ls);  /* skip break */
   newgotoentry(ls, luaS_newliteral(ls->L, "break"), line);
 }