Skip to content

Instantly share code, notes, and snippets.

@georgexsh
Created September 18, 2017 07:47
Show Gist options
  • Star 85 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save georgexsh/ede5163a294ced53c3e2369ccaa392cc to your computer and use it in GitHub Desktop.
Save georgexsh/ede5163a294ced53c3e2369ccaa392cc to your computer and use it in GitHub Desktop.
python goto with system trace function
import sys
def j(lineno):
frame = sys._getframe().f_back
called_from = frame
def hook(frame, event, arg):
if event == 'line' and frame == called_from:
try:
frame.f_lineno = lineno
except ValueError as e:
print "jump failed:", e
while frame:
frame.f_trace = None
frame = frame.f_back
return None
return hook
while frame:
frame.f_trace = hook
frame = frame.f_back
sys.settrace(hook)
def foo():
a = 1
j(30)
a = 2
print 1
print 2
if a == 1:
j(28)
print 4
foo()
@onequbit
Copy link

onequbit commented May 5, 2020

How about making a BASIC interpreter, and then a transpiler to convert Python code into BASIC?
Yo DAWG! Now you can throw up in your mouth while you die a little inside!

@Kyuuhachi
Copy link

I made a py3 port. This one uses relative line numbers though.

@shakna-israel
Copy link

Here's a reworking of the version above that adds labels, that uses the bytecode dissassembler rather than re-parsing a file that may have changed:

import sys
import dis

def label(name):
    pass

def j(lineno):
    frame = sys._getframe().f_back
    called_from = frame

    if isinstance(lineno, str):
        # Dissassemble our byte code to find and create our labels:
        bc = dis.Bytecode(called_from.f_code)
        labels = {}
        SET_LABEL = False
        LABEL_LINE = None
        for idx, instr in enumerate(bc):
            if instr.opname == 'LOAD_GLOBAL':
                if instr.argval == 'label':
                    SET_LABEL = True
                    LABEL_LINE = instr.starts_line
            if instr.opname == 'LOAD_CONST' and SET_LABEL:
                label_name = instr.argval
                labels[label_name] = LABEL_LINE

                SET_LABEL = False
                LABEL_LINE = None

        try:
            lineno = labels[lineno]
        except KeyError:
            raise RuntimeError("Unknown Label: {}".format(lineno))

    def hook(frame, event, arg):
        if event == 'line' and frame == called_from:
            try:
                frame.f_lineno = lineno
            except ValueError as e:
                print("jump failed:", e)
            while frame:
                frame.f_trace = None
                frame = frame.f_back
            return None
        return hook

    while frame:
        frame.f_trace = hook
        frame = frame.f_back
    sys.settrace(hook)


def foo():
    a = 1
    j('l1')
    label('l2')
    a = 2
    print(1)
    label('l1')
    print(2)
    if a == 1:
        j('l2')
    print(4)


foo()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment