1 from goto import *
2
3 @patch
4 def f2():
5 goto(10)
6 print 'should not see this'
7 label(10)
8 for i in range(1,99999):
9 print i
10 if i == 5:
11 goto('out')
12 label('out')
13
14 f2() 用法是:
1. from goto import *。注意暂时不支持import goto,不是不能实现,是暂时没时间写。
2.对需要使用goto的函数,前面加个@patch
3.用label(x)和goto(x)的形式写label和goto。x可以是数字或字符串。
goto模块的代码如下:
goto.py
import dis,pdb
#dummy functions serving as target of bytecode patching
def goto(label):
pass
def label(label):
pass
#
def decode_bytecode(fun):
"""Input: a function
Ouput: a list of pairs (opcode, arguments)"""
c = fun.func_code.co_code
n = len(c)
i = 0
while i < n:
op = c
i += 1
arguments = ""
if ord(op) >= dis.HAVE_ARGUMENT:
arguments = c[i : i+2]
i += 2
yield (op, arguments)
def sample():
goto(200)
if 1 == 2:
sample()
else:
print 'sample'
def test_decode(fun):
for op,arg in decode_bytecode(fun):
if arg=='':
print dis.opname[ord(op)]
else:
print dis.opname[ord(op)] +' '+str(ord(arg[0]))+' '+str(ord(arg[1]))
def match_pattern(seq, i, p):
"""
try to match pattern p to seq[i:], return None if match failed
seq: output of decode_bytecode
p -> [instr, instr, ...]
instr -> (opcode, arg, arg) opcode is a opcode string
arg -> '' I don't give a damn about this arg
arg -> integer match arg with number
arg -> string the arg is key of the returned match dict from which the arg value can be extracted
arg -> lambda lambda is evaluated with the argument, false return means failed match
"""
#pdb.set_trace()
m = {}
for op, arg1, arg2 in p:
if i==len(seq):
return None
if dis.opmap[op] != ord(seq[0]):
return None
if arg1 == '':
pass
else:
if seq[1] == '': return None
a1 = ord(seq[1][0])
if type(arg1) is str:
m[arg1]=a1
elif type(arg1) is int:
if arg1 != a1: return None
elif not arg1(a1):
return None
#don't need arg2 in this program
i+=1
return m
def int_to_bytecode_arg(i):
return chr(i % 256) +\
chr(i // 256)
def patch(fun):
NOP = chr(dis.opmap['NOP'])
co = fun.func_code
old = list(decode_bytecode(fun))
new = [] #a list of characters
#mapping from label to bytecode offset
label_table={}
#if a goto(label) is seen but label is not seen
#record for the number the bytecode offset of the
#argument for JUMP_ABSOLUTE for later patching
goto_table={}
i=0
#pdb.set_trace()
while i