-
-
Save georgexsh/ede5163a294ced53c3e2369ccaa392cc to your computer and use it in GitHub Desktop.
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() |
2 | |
1 | |
2 | |
4 |
Great :) Going to study this. Thank you.
I added labels lol
import ast
import sys
def label(name):
pass
def j(lineno):
frame = sys._getframe().f_back
called_from = frame
if isinstance(lineno, str):
with open(called_from.f_code.co_filename) as f:
for node in ast.walk(ast.parse(f.read())):
if isinstance(node, ast.Call) \
and isinstance(node.func, ast.Name) \
and node.func.id == 'label' \
and lineno == ast.literal_eval(node.args[0]):
lineno = node.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()
could someone explain what the hook function is for and who calls it?
Meh... "goto" is already taken on PyPI... :(
The "goto" on pypi follows the same idea, and was made for an April first a couple years ago. It is actually "production quality" and implements labels and a comefrom
statement as well as the goto
.
Can this at GOSUB too ?
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!
I made a py3 port. This one uses relative line numbers though.
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()
Hehe, should consider renaming "j" to "goto" for full effect.