lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


hi listers,

i've found myself doing lot of miserable things today, due to inability of lua
to simply break out of multiple nested breakable scopes in one statement.

finding nothing useful in powerpatches archive i wrote this rather naive
and unintrusive patch - so there is generally no reason why it shouldn't work,
but i've tested it extensively only with various for/while nested loops.

use:
while foo do
	while bar do
		if baz then eek() break 2 end
	end
end

if "foo and bar and baz" condition holds, 'break 2' escapes loops
imediately. the number is counted towards breakable scopes (thus "if",
"do" etc are left out)

note that only TK_NUMBER (that is, single numeral constants) are
accepted, doing this for dynamic values would equal enumerating
all possible breakable levels in bytecode, like:
if n == 1 then break 1 elseif n == 2 then break 2 ....

and i believe that wouldn't have much real use anyway.

//kt

diff -ruN lua-5.1.1/src/lparser.c tmp/src/lparser.c
--- lua-5.1.1/src/lparser.c	2006-06-05 17:57:59.000000000 +0200
+++ tmp/src/lparser.c	2006-10-31 22:23:42.000000000 +0100
@@ -970,11 +970,11 @@
 }
 
 
-static void breakstat (LexState *ls) {
+static void breakstat (LexState *ls, int n) {
   FuncState *fs = ls->fs;
   BlockCnt *bl = fs->bl;
   int upval = 0;
-  while (bl && !bl->isbreakable) {
+  while (bl && (!bl->isbreakable || --n)) {
     upval |= bl->upval;
     bl = bl->previous;
   }
@@ -1022,7 +1022,7 @@
     luaK_patchlist(ls->fs, condexit, repeat_init);  /* close the loop */
   }
   else {  /* complete semantics when there are upvalues */
-    breakstat(ls);  /* if condition then break */
+    breakstat(ls, 1);  /* if condition then break */
     luaK_patchtohere(ls->fs, condexit);  /* else... */
     leaveblock(fs);  /* finish scope... */
     luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init);  /* and repeat */
@@ -1309,7 +1309,9 @@
     }
     case TK_BREAK: {  /* stat -> breakstat */
       luaX_next(ls);  /* skip BREAK */
-      breakstat(ls);
+      if (testnext(ls, TK_NUMBER)) { /* multi scope 'break n' */
+        breakstat(ls, ls->t.seminfo.r);
+      } else breakstat(ls, 1);
       return 1;  /* must be last statement */
     }
     default: {