|
|
|
|
|
by tveita
3928 days ago
|
|
This is cute but of course horribly unsafe since it doesn't respect control statements. Some examples you'd expect to work that will crash the interpreter: @with_goto
def fun1():
while True:
for x in [1]:
goto .next
label .next
@with_goto
def fun2():
goto .next
for x in [1]:
label .next
@with_goto
def fun3():
while True:
try:
goto .next
finally:
print('skipped')
label .next
|
|
How it works is that tagbody contains a bunch of labels mixed with forms. The tagbody establishes an exit point for GO expressions used in these forms. When a (go label) occurs, it works by abandoning the current sub-form being evaluated, and initiating a control transfer to the exit point, which then transfers control to the appropriate label.
The upshot is that whatever form is interrupted will cleanly unwind, as necessary:
Note that you can only have labels and GO in certain forms like TAGBODY and PROG, not just willy nilly in any construct. The labels of a given TAGBODY are all on the same level of nesting: immediate children of the TAGBODY form. SO this isn't possible: Here, impossible is not considered a label associated with the tagbody, so the (go impossible) is branching to a nonexistent label. If it were allowed, of course it would create the problem of what becomes of the initialization of x.Thus, compilers only have to reason about GO within specific constructs, and rely on those GO's to only be performing abandonment followed by a simple lateral move.