lua-users home
lua-l archive

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


It was thus said that the Great Dirk Laurie once stated:
> Several people, I'm sure, use the convention that the label
> ::continue:: is only used right before the loop's "end" or
> "until".
> 
> Try the following experiment: in llex.c, find "break" (complete
> with quotes) and change it to something else, say "BREAK",
> so that `break` is no longer a keyword. Rebuild.
> 
> Then this works:
> 
> > local k=0; while true do k=k+1 if k==7 then goto break end end print(k)
> 7
> 
> I.e. the statement "break" is mere syntactic sugar for "goto break",
> where the label "break" is predefined.
> 
> One could do that with `continue` too. t's just within my patching skills
> make it work with `while`, `for` (both versions), and `repeat`...`until false`.
> In lparser.c, change the function `breaklabel` to:
> 
> static void breaklabel (LexState *ls) {
>   TString *n = luaS_new(ls->L, "break"), *c = luaS_new(ls->L, "continue");
>   int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc),
>       m = newlabelentry(ls, &ls->dyd->label, c, 0, ls->fs->pc-1);
>   findgotos(ls, &ls->dyd->label.arr[l]);
>   findgotos(ls, &ls->dyd->label.arr[m]);
> }
> 
> Then (patching a superseded Lua version):
> 
> Lua 5.3.0 (work2)  Copyright (C) 1994-2014 Lua.org, PUC-Rio
> > k=0; repeat
> >> k=k+1
> >> if k<5 then goto continue end
> >> print(k)
> >> if k>5 then goto break end
> >> until false
> 5
> 6
> 
> For any other `repeat`, `pc-1` is wrong since it bypasses the test.
> 
> Maybe a better programmer than me can take up the challenge
> of patching lparser.c to handle `repeat` correctly too and to do
> `goto restart` (as if ::restart:: sits just before `while` etc.) and
> `goto resume` (as if ::resume sits just after `do` etc).

  If you are serious about this, you can remove "while", "repeat", "until",
"else", "break" and "for" and replace them all with just "if" and "goto".

	while <cond> do <block> end

	::L1::
	if not <cond> then goto L2 end
	<block>
	goto L1
	::L2::

---

	repeat <block> until <cond>

	::L1::
	<block>
	if not <cond> then goto L1 end

---

	for i = <low> , <high> , <incr> do <block> end

	do
	  local i = <low>
	  ::L1::
	  <block>
	  i = i + <incr>
	  if not i > <high> then goto L1 end
	end

---

	for v1,... in <iterator()> do <block> end

	do
	  local f,s,var = <iterator()>
	  ::L1::
	  local v1,... = f(s,var)
	  if not v1 == nil then goto L2 end
	  <block>
	  goto L1
	end
	::L2::

---

	if <cond> then <block1> else <block2> end

	if not <cond> then goto L1 end
	<block1>
	goto L2
	::L1::
	<block2>
	::L2::

---

  GOTO is a very versatile statement, one that will allow you to construct
whatever type of flow control you can conceive of.  How about the equivelent
of:

	while <cond> do <block1> else <block2> end

or even

	if <cond1> then <block1> until <cond2> end

Or how about

	repeat <block> if <cond> end

  -spc (Another improvement would be to allow goto between functions, but
	some people would consider that silly talk ... )