[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Predefined labels (Inspired by discussion on: Why do we have ipairs?)
- From: Sean Conner <sean@...>
- Date: Fri, 27 Jun 2014 05:15:38 -0400
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 ... )