5 ms·
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:
by tveita 11y 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
- RussianCow 11y agoHow would you expect the second one to work?
- tveita 11y agoI guess similarly to C: for i in foo: print(42) would be considered equivalent to something like it = iter(foo) while True: try: i = next(it) catch StopIteration: break print(42) and jumping to print(42) would skip the init and first iteration expression. Of course that's non-obvious behaviour, so in practice you would make it a compile time error. A careful language designer might even decide to not support goto at all. :)
- kazinator 11y agoNote how Lisp's TAGBODY/GO doesn't have this problem. (loop (tagbody (loop for x in '(1 2 3) do (go next)) next (print 'out))) (OUT is printed repeatedly.) 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: (tagbody (unwind-protect (progn (go out) (progn 'never-printed)) (print 'bye-bye)) out) 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: (tagbody (go impossible) (let ((x 42)) impossible x)) 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.
- wallunit 11y agoFixed: https://github.com/snoack/python-goto/commit/a46dbe57e9cfa4fd8a0a7fa0ca7d163d3942a992 https://github.com/snoack/python-goto/commit/a46dbe57e9cfa4f... Jumps out of loops and other blocks work now. However, there are some limitations: 1. As I only have 4 bytes left to inject POP_BLOCK instructions, you can't exit more than 4 blocks with a goto. But this is handled and results into a SyntaxError rather than crashing Python. 2. Jumps into loops still doesn't work. However, it's handled now, and causes a SyntaxError as well. 3. When jumping out of a try- or with-block the finalizer is skipped.