lua-users home
lua-l archive

Re: Predefined labels (Inspired by discussion on: Why do we have ipairs?)

[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 ... )

AltStyle によって変換されたページ (->オリジナル) /