Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ShExBy/shex_roo.../lib64/python2..../compiler
File: pyassem.py
"""A flow graph representation for Python bytecode"""
[0] Fix | Delete
[1] Fix | Delete
import dis
[2] Fix | Delete
import types
[3] Fix | Delete
import sys
[4] Fix | Delete
[5] Fix | Delete
from compiler import misc
[6] Fix | Delete
from compiler.consts \
[7] Fix | Delete
import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
[8] Fix | Delete
[9] Fix | Delete
class FlowGraph:
[10] Fix | Delete
def __init__(self):
[11] Fix | Delete
self.current = self.entry = Block()
[12] Fix | Delete
self.exit = Block("exit")
[13] Fix | Delete
self.blocks = misc.Set()
[14] Fix | Delete
self.blocks.add(self.entry)
[15] Fix | Delete
self.blocks.add(self.exit)
[16] Fix | Delete
[17] Fix | Delete
def startBlock(self, block):
[18] Fix | Delete
if self._debug:
[19] Fix | Delete
if self.current:
[20] Fix | Delete
print "end", repr(self.current)
[21] Fix | Delete
print " next", self.current.next
[22] Fix | Delete
print " prev", self.current.prev
[23] Fix | Delete
print " ", self.current.get_children()
[24] Fix | Delete
print repr(block)
[25] Fix | Delete
self.current = block
[26] Fix | Delete
[27] Fix | Delete
def nextBlock(self, block=None):
[28] Fix | Delete
# XXX think we need to specify when there is implicit transfer
[29] Fix | Delete
# from one block to the next. might be better to represent this
[30] Fix | Delete
# with explicit JUMP_ABSOLUTE instructions that are optimized
[31] Fix | Delete
# out when they are unnecessary.
[32] Fix | Delete
#
[33] Fix | Delete
# I think this strategy works: each block has a child
[34] Fix | Delete
# designated as "next" which is returned as the last of the
[35] Fix | Delete
# children. because the nodes in a graph are emitted in
[36] Fix | Delete
# reverse post order, the "next" block will always be emitted
[37] Fix | Delete
# immediately after its parent.
[38] Fix | Delete
# Worry: maintaining this invariant could be tricky
[39] Fix | Delete
if block is None:
[40] Fix | Delete
block = self.newBlock()
[41] Fix | Delete
[42] Fix | Delete
# Note: If the current block ends with an unconditional control
[43] Fix | Delete
# transfer, then it is techically incorrect to add an implicit
[44] Fix | Delete
# transfer to the block graph. Doing so results in code generation
[45] Fix | Delete
# for unreachable blocks. That doesn't appear to be very common
[46] Fix | Delete
# with Python code and since the built-in compiler doesn't optimize
[47] Fix | Delete
# it out we don't either.
[48] Fix | Delete
self.current.addNext(block)
[49] Fix | Delete
self.startBlock(block)
[50] Fix | Delete
[51] Fix | Delete
def newBlock(self):
[52] Fix | Delete
b = Block()
[53] Fix | Delete
self.blocks.add(b)
[54] Fix | Delete
return b
[55] Fix | Delete
[56] Fix | Delete
def startExitBlock(self):
[57] Fix | Delete
self.startBlock(self.exit)
[58] Fix | Delete
[59] Fix | Delete
_debug = 0
[60] Fix | Delete
[61] Fix | Delete
def _enable_debug(self):
[62] Fix | Delete
self._debug = 1
[63] Fix | Delete
[64] Fix | Delete
def _disable_debug(self):
[65] Fix | Delete
self._debug = 0
[66] Fix | Delete
[67] Fix | Delete
def emit(self, *inst):
[68] Fix | Delete
if self._debug:
[69] Fix | Delete
print "\t", inst
[70] Fix | Delete
if len(inst) == 2 and isinstance(inst[1], Block):
[71] Fix | Delete
self.current.addOutEdge(inst[1])
[72] Fix | Delete
self.current.emit(inst)
[73] Fix | Delete
[74] Fix | Delete
def getBlocksInOrder(self):
[75] Fix | Delete
"""Return the blocks in reverse postorder
[76] Fix | Delete
[77] Fix | Delete
i.e. each node appears before all of its successors
[78] Fix | Delete
"""
[79] Fix | Delete
order = order_blocks(self.entry, self.exit)
[80] Fix | Delete
return order
[81] Fix | Delete
[82] Fix | Delete
def getBlocks(self):
[83] Fix | Delete
return self.blocks.elements()
[84] Fix | Delete
[85] Fix | Delete
def getRoot(self):
[86] Fix | Delete
"""Return nodes appropriate for use with dominator"""
[87] Fix | Delete
return self.entry
[88] Fix | Delete
[89] Fix | Delete
def getContainedGraphs(self):
[90] Fix | Delete
l = []
[91] Fix | Delete
for b in self.getBlocks():
[92] Fix | Delete
l.extend(b.getContainedGraphs())
[93] Fix | Delete
return l
[94] Fix | Delete
[95] Fix | Delete
[96] Fix | Delete
def order_blocks(start_block, exit_block):
[97] Fix | Delete
"""Order blocks so that they are emitted in the right order"""
[98] Fix | Delete
# Rules:
[99] Fix | Delete
# - when a block has a next block, the next block must be emitted just after
[100] Fix | Delete
# - when a block has followers (relative jumps), it must be emitted before
[101] Fix | Delete
# them
[102] Fix | Delete
# - all reachable blocks must be emitted
[103] Fix | Delete
order = []
[104] Fix | Delete
[105] Fix | Delete
# Find all the blocks to be emitted.
[106] Fix | Delete
remaining = set()
[107] Fix | Delete
todo = [start_block]
[108] Fix | Delete
while todo:
[109] Fix | Delete
b = todo.pop()
[110] Fix | Delete
if b in remaining:
[111] Fix | Delete
continue
[112] Fix | Delete
remaining.add(b)
[113] Fix | Delete
for c in b.get_children():
[114] Fix | Delete
if c not in remaining:
[115] Fix | Delete
todo.append(c)
[116] Fix | Delete
[117] Fix | Delete
# A block is dominated by another block if that block must be emitted
[118] Fix | Delete
# before it.
[119] Fix | Delete
dominators = {}
[120] Fix | Delete
for b in remaining:
[121] Fix | Delete
if __debug__ and b.next:
[122] Fix | Delete
assert b is b.next[0].prev[0], (b, b.next)
[123] Fix | Delete
# Make sure every block appears in dominators, even if no
[124] Fix | Delete
# other block must precede it.
[125] Fix | Delete
dominators.setdefault(b, set())
[126] Fix | Delete
# preceding blocks dominate following blocks
[127] Fix | Delete
for c in b.get_followers():
[128] Fix | Delete
while 1:
[129] Fix | Delete
dominators.setdefault(c, set()).add(b)
[130] Fix | Delete
# Any block that has a next pointer leading to c is also
[131] Fix | Delete
# dominated because the whole chain will be emitted at once.
[132] Fix | Delete
# Walk backwards and add them all.
[133] Fix | Delete
if c.prev and c.prev[0] is not b:
[134] Fix | Delete
c = c.prev[0]
[135] Fix | Delete
else:
[136] Fix | Delete
break
[137] Fix | Delete
[138] Fix | Delete
def find_next():
[139] Fix | Delete
# Find a block that can be emitted next.
[140] Fix | Delete
for b in remaining:
[141] Fix | Delete
for c in dominators[b]:
[142] Fix | Delete
if c in remaining:
[143] Fix | Delete
break # can't emit yet, dominated by a remaining block
[144] Fix | Delete
else:
[145] Fix | Delete
return b
[146] Fix | Delete
assert 0, 'circular dependency, cannot find next block'
[147] Fix | Delete
[148] Fix | Delete
b = start_block
[149] Fix | Delete
while 1:
[150] Fix | Delete
order.append(b)
[151] Fix | Delete
remaining.discard(b)
[152] Fix | Delete
if b.next:
[153] Fix | Delete
b = b.next[0]
[154] Fix | Delete
continue
[155] Fix | Delete
elif b is not exit_block and not b.has_unconditional_transfer():
[156] Fix | Delete
order.append(exit_block)
[157] Fix | Delete
if not remaining:
[158] Fix | Delete
break
[159] Fix | Delete
b = find_next()
[160] Fix | Delete
return order
[161] Fix | Delete
[162] Fix | Delete
[163] Fix | Delete
class Block:
[164] Fix | Delete
_count = 0
[165] Fix | Delete
[166] Fix | Delete
def __init__(self, label=''):
[167] Fix | Delete
self.insts = []
[168] Fix | Delete
self.outEdges = set()
[169] Fix | Delete
self.label = label
[170] Fix | Delete
self.bid = Block._count
[171] Fix | Delete
self.next = []
[172] Fix | Delete
self.prev = []
[173] Fix | Delete
Block._count = Block._count + 1
[174] Fix | Delete
[175] Fix | Delete
def __repr__(self):
[176] Fix | Delete
if self.label:
[177] Fix | Delete
return "<block %s id=%d>" % (self.label, self.bid)
[178] Fix | Delete
else:
[179] Fix | Delete
return "<block id=%d>" % (self.bid)
[180] Fix | Delete
[181] Fix | Delete
def __str__(self):
[182] Fix | Delete
insts = map(str, self.insts)
[183] Fix | Delete
return "<block %s %d:\n%s>" % (self.label, self.bid,
[184] Fix | Delete
'\n'.join(insts))
[185] Fix | Delete
[186] Fix | Delete
def emit(self, inst):
[187] Fix | Delete
op = inst[0]
[188] Fix | Delete
self.insts.append(inst)
[189] Fix | Delete
[190] Fix | Delete
def getInstructions(self):
[191] Fix | Delete
return self.insts
[192] Fix | Delete
[193] Fix | Delete
def addOutEdge(self, block):
[194] Fix | Delete
self.outEdges.add(block)
[195] Fix | Delete
[196] Fix | Delete
def addNext(self, block):
[197] Fix | Delete
self.next.append(block)
[198] Fix | Delete
assert len(self.next) == 1, map(str, self.next)
[199] Fix | Delete
block.prev.append(self)
[200] Fix | Delete
assert len(block.prev) == 1, map(str, block.prev)
[201] Fix | Delete
[202] Fix | Delete
_uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
[203] Fix | Delete
'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP',
[204] Fix | Delete
)
[205] Fix | Delete
[206] Fix | Delete
def has_unconditional_transfer(self):
[207] Fix | Delete
"""Returns True if there is an unconditional transfer to an other block
[208] Fix | Delete
at the end of this block. This means there is no risk for the bytecode
[209] Fix | Delete
executer to go past this block's bytecode."""
[210] Fix | Delete
try:
[211] Fix | Delete
op, arg = self.insts[-1]
[212] Fix | Delete
except (IndexError, ValueError):
[213] Fix | Delete
return
[214] Fix | Delete
return op in self._uncond_transfer
[215] Fix | Delete
[216] Fix | Delete
def get_children(self):
[217] Fix | Delete
return list(self.outEdges) + self.next
[218] Fix | Delete
[219] Fix | Delete
def get_followers(self):
[220] Fix | Delete
"""Get the whole list of followers, including the next block."""
[221] Fix | Delete
followers = set(self.next)
[222] Fix | Delete
# Blocks that must be emitted *after* this one, because of
[223] Fix | Delete
# bytecode offsets (e.g. relative jumps) pointing to them.
[224] Fix | Delete
for inst in self.insts:
[225] Fix | Delete
if inst[0] in PyFlowGraph.hasjrel:
[226] Fix | Delete
followers.add(inst[1])
[227] Fix | Delete
return followers
[228] Fix | Delete
[229] Fix | Delete
def getContainedGraphs(self):
[230] Fix | Delete
"""Return all graphs contained within this block.
[231] Fix | Delete
[232] Fix | Delete
For example, a MAKE_FUNCTION block will contain a reference to
[233] Fix | Delete
the graph for the function body.
[234] Fix | Delete
"""
[235] Fix | Delete
contained = []
[236] Fix | Delete
for inst in self.insts:
[237] Fix | Delete
if len(inst) == 1:
[238] Fix | Delete
continue
[239] Fix | Delete
op = inst[1]
[240] Fix | Delete
if hasattr(op, 'graph'):
[241] Fix | Delete
contained.append(op.graph)
[242] Fix | Delete
return contained
[243] Fix | Delete
[244] Fix | Delete
# flags for code objects
[245] Fix | Delete
[246] Fix | Delete
# the FlowGraph is transformed in place; it exists in one of these states
[247] Fix | Delete
RAW = "RAW"
[248] Fix | Delete
FLAT = "FLAT"
[249] Fix | Delete
CONV = "CONV"
[250] Fix | Delete
DONE = "DONE"
[251] Fix | Delete
[252] Fix | Delete
class PyFlowGraph(FlowGraph):
[253] Fix | Delete
super_init = FlowGraph.__init__
[254] Fix | Delete
[255] Fix | Delete
def __init__(self, name, filename, args=(), optimized=0, klass=None):
[256] Fix | Delete
self.super_init()
[257] Fix | Delete
self.name = name
[258] Fix | Delete
self.filename = filename
[259] Fix | Delete
self.docstring = None
[260] Fix | Delete
self.args = args # XXX
[261] Fix | Delete
self.argcount = getArgCount(args)
[262] Fix | Delete
self.klass = klass
[263] Fix | Delete
if optimized:
[264] Fix | Delete
self.flags = CO_OPTIMIZED | CO_NEWLOCALS
[265] Fix | Delete
else:
[266] Fix | Delete
self.flags = 0
[267] Fix | Delete
self.consts = []
[268] Fix | Delete
self.names = []
[269] Fix | Delete
# Free variables found by the symbol table scan, including
[270] Fix | Delete
# variables used only in nested scopes, are included here.
[271] Fix | Delete
self.freevars = []
[272] Fix | Delete
self.cellvars = []
[273] Fix | Delete
# The closure list is used to track the order of cell
[274] Fix | Delete
# variables and free variables in the resulting code object.
[275] Fix | Delete
# The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
[276] Fix | Delete
# kinds of variables.
[277] Fix | Delete
self.closure = []
[278] Fix | Delete
self.varnames = list(args) or []
[279] Fix | Delete
for i in range(len(self.varnames)):
[280] Fix | Delete
var = self.varnames[i]
[281] Fix | Delete
if isinstance(var, TupleArg):
[282] Fix | Delete
self.varnames[i] = var.getName()
[283] Fix | Delete
self.stage = RAW
[284] Fix | Delete
[285] Fix | Delete
def setDocstring(self, doc):
[286] Fix | Delete
self.docstring = doc
[287] Fix | Delete
[288] Fix | Delete
def setFlag(self, flag):
[289] Fix | Delete
self.flags = self.flags | flag
[290] Fix | Delete
if flag == CO_VARARGS:
[291] Fix | Delete
self.argcount = self.argcount - 1
[292] Fix | Delete
[293] Fix | Delete
def checkFlag(self, flag):
[294] Fix | Delete
if self.flags & flag:
[295] Fix | Delete
return 1
[296] Fix | Delete
[297] Fix | Delete
def setFreeVars(self, names):
[298] Fix | Delete
self.freevars = list(names)
[299] Fix | Delete
[300] Fix | Delete
def setCellVars(self, names):
[301] Fix | Delete
self.cellvars = names
[302] Fix | Delete
[303] Fix | Delete
def getCode(self):
[304] Fix | Delete
"""Get a Python code object"""
[305] Fix | Delete
assert self.stage == RAW
[306] Fix | Delete
self.computeStackDepth()
[307] Fix | Delete
self.flattenGraph()
[308] Fix | Delete
assert self.stage == FLAT
[309] Fix | Delete
self.convertArgs()
[310] Fix | Delete
assert self.stage == CONV
[311] Fix | Delete
self.makeByteCode()
[312] Fix | Delete
assert self.stage == DONE
[313] Fix | Delete
return self.newCodeObject()
[314] Fix | Delete
[315] Fix | Delete
def dump(self, io=None):
[316] Fix | Delete
if io:
[317] Fix | Delete
save = sys.stdout
[318] Fix | Delete
sys.stdout = io
[319] Fix | Delete
pc = 0
[320] Fix | Delete
for t in self.insts:
[321] Fix | Delete
opname = t[0]
[322] Fix | Delete
if opname == "SET_LINENO":
[323] Fix | Delete
print
[324] Fix | Delete
if len(t) == 1:
[325] Fix | Delete
print "\t", "%3d" % pc, opname
[326] Fix | Delete
pc = pc + 1
[327] Fix | Delete
else:
[328] Fix | Delete
print "\t", "%3d" % pc, opname, t[1]
[329] Fix | Delete
pc = pc + 3
[330] Fix | Delete
if io:
[331] Fix | Delete
sys.stdout = save
[332] Fix | Delete
[333] Fix | Delete
def computeStackDepth(self):
[334] Fix | Delete
"""Compute the max stack depth.
[335] Fix | Delete
[336] Fix | Delete
Approach is to compute the stack effect of each basic block.
[337] Fix | Delete
Then find the path through the code with the largest total
[338] Fix | Delete
effect.
[339] Fix | Delete
"""
[340] Fix | Delete
depth = {}
[341] Fix | Delete
exit = None
[342] Fix | Delete
for b in self.getBlocks():
[343] Fix | Delete
depth[b] = findDepth(b.getInstructions())
[344] Fix | Delete
[345] Fix | Delete
seen = {}
[346] Fix | Delete
[347] Fix | Delete
def max_depth(b, d):
[348] Fix | Delete
if b in seen:
[349] Fix | Delete
return d
[350] Fix | Delete
seen[b] = 1
[351] Fix | Delete
d = d + depth[b]
[352] Fix | Delete
children = b.get_children()
[353] Fix | Delete
if children:
[354] Fix | Delete
return max([max_depth(c, d) for c in children])
[355] Fix | Delete
else:
[356] Fix | Delete
if not b.label == "exit":
[357] Fix | Delete
return max_depth(self.exit, d)
[358] Fix | Delete
else:
[359] Fix | Delete
return d
[360] Fix | Delete
[361] Fix | Delete
self.stacksize = max_depth(self.entry, 0)
[362] Fix | Delete
[363] Fix | Delete
def flattenGraph(self):
[364] Fix | Delete
"""Arrange the blocks in order and resolve jumps"""
[365] Fix | Delete
assert self.stage == RAW
[366] Fix | Delete
self.insts = insts = []
[367] Fix | Delete
pc = 0
[368] Fix | Delete
begin = {}
[369] Fix | Delete
end = {}
[370] Fix | Delete
for b in self.getBlocksInOrder():
[371] Fix | Delete
begin[b] = pc
[372] Fix | Delete
for inst in b.getInstructions():
[373] Fix | Delete
insts.append(inst)
[374] Fix | Delete
if len(inst) == 1:
[375] Fix | Delete
pc = pc + 1
[376] Fix | Delete
elif inst[0] != "SET_LINENO":
[377] Fix | Delete
# arg takes 2 bytes
[378] Fix | Delete
pc = pc + 3
[379] Fix | Delete
end[b] = pc
[380] Fix | Delete
pc = 0
[381] Fix | Delete
for i in range(len(insts)):
[382] Fix | Delete
inst = insts[i]
[383] Fix | Delete
if len(inst) == 1:
[384] Fix | Delete
pc = pc + 1
[385] Fix | Delete
elif inst[0] != "SET_LINENO":
[386] Fix | Delete
pc = pc + 3
[387] Fix | Delete
opname = inst[0]
[388] Fix | Delete
if opname in self.hasjrel:
[389] Fix | Delete
oparg = inst[1]
[390] Fix | Delete
offset = begin[oparg] - pc
[391] Fix | Delete
insts[i] = opname, offset
[392] Fix | Delete
elif opname in self.hasjabs:
[393] Fix | Delete
insts[i] = opname, begin[inst[1]]
[394] Fix | Delete
self.stage = FLAT
[395] Fix | Delete
[396] Fix | Delete
hasjrel = set()
[397] Fix | Delete
for i in dis.hasjrel:
[398] Fix | Delete
hasjrel.add(dis.opname[i])
[399] Fix | Delete
hasjabs = set()
[400] Fix | Delete
for i in dis.hasjabs:
[401] Fix | Delete
hasjabs.add(dis.opname[i])
[402] Fix | Delete
[403] Fix | Delete
def convertArgs(self):
[404] Fix | Delete
"""Convert arguments from symbolic to concrete form"""
[405] Fix | Delete
assert self.stage == FLAT
[406] Fix | Delete
self.consts.insert(0, self.docstring)
[407] Fix | Delete
self.sort_cellvars()
[408] Fix | Delete
for i in range(len(self.insts)):
[409] Fix | Delete
t = self.insts[i]
[410] Fix | Delete
if len(t) == 2:
[411] Fix | Delete
opname, oparg = t
[412] Fix | Delete
conv = self._converters.get(opname, None)
[413] Fix | Delete
if conv:
[414] Fix | Delete
self.insts[i] = opname, conv(self, oparg)
[415] Fix | Delete
self.stage = CONV
[416] Fix | Delete
[417] Fix | Delete
def sort_cellvars(self):
[418] Fix | Delete
"""Sort cellvars in the order of varnames and prune from freevars.
[419] Fix | Delete
"""
[420] Fix | Delete
cells = {}
[421] Fix | Delete
for name in self.cellvars:
[422] Fix | Delete
cells[name] = 1
[423] Fix | Delete
self.cellvars = [name for name in self.varnames
[424] Fix | Delete
if name in cells]
[425] Fix | Delete
for name in self.cellvars:
[426] Fix | Delete
del cells[name]
[427] Fix | Delete
self.cellvars = self.cellvars + cells.keys()
[428] Fix | Delete
self.closure = self.cellvars + self.freevars
[429] Fix | Delete
[430] Fix | Delete
def _lookupName(self, name, list):
[431] Fix | Delete
"""Return index of name in list, appending if necessary
[432] Fix | Delete
[433] Fix | Delete
This routine uses a list instead of a dictionary, because a
[434] Fix | Delete
dictionary can't store two different keys if the keys have the
[435] Fix | Delete
same value but different types, e.g. 2 and 2L. The compiler
[436] Fix | Delete
must treat these two separately, so it does an explicit type
[437] Fix | Delete
comparison before comparing the values.
[438] Fix | Delete
"""
[439] Fix | Delete
t = type(name)
[440] Fix | Delete
for i in range(len(list)):
[441] Fix | Delete
if t == type(list[i]) and list[i] == name:
[442] Fix | Delete
return i
[443] Fix | Delete
end = len(list)
[444] Fix | Delete
list.append(name)
[445] Fix | Delete
return end
[446] Fix | Delete
[447] Fix | Delete
_converters = {}
[448] Fix | Delete
def _convert_LOAD_CONST(self, arg):
[449] Fix | Delete
if hasattr(arg, 'getCode'):
[450] Fix | Delete
arg = arg.getCode()
[451] Fix | Delete
return self._lookupName(arg, self.consts)
[452] Fix | Delete
[453] Fix | Delete
def _convert_LOAD_FAST(self, arg):
[454] Fix | Delete
self._lookupName(arg, self.names)
[455] Fix | Delete
return self._lookupName(arg, self.varnames)
[456] Fix | Delete
_convert_STORE_FAST = _convert_LOAD_FAST
[457] Fix | Delete
_convert_DELETE_FAST = _convert_LOAD_FAST
[458] Fix | Delete
[459] Fix | Delete
def _convert_LOAD_NAME(self, arg):
[460] Fix | Delete
if self.klass is None:
[461] Fix | Delete
self._lookupName(arg, self.varnames)
[462] Fix | Delete
return self._lookupName(arg, self.names)
[463] Fix | Delete
[464] Fix | Delete
def _convert_NAME(self, arg):
[465] Fix | Delete
if self.klass is None:
[466] Fix | Delete
self._lookupName(arg, self.varnames)
[467] Fix | Delete
return self._lookupName(arg, self.names)
[468] Fix | Delete
_convert_STORE_NAME = _convert_NAME
[469] Fix | Delete
_convert_DELETE_NAME = _convert_NAME
[470] Fix | Delete
_convert_IMPORT_NAME = _convert_NAME
[471] Fix | Delete
_convert_IMPORT_FROM = _convert_NAME
[472] Fix | Delete
_convert_STORE_ATTR = _convert_NAME
[473] Fix | Delete
_convert_LOAD_ATTR = _convert_NAME
[474] Fix | Delete
_convert_DELETE_ATTR = _convert_NAME
[475] Fix | Delete
_convert_LOAD_GLOBAL = _convert_NAME
[476] Fix | Delete
_convert_STORE_GLOBAL = _convert_NAME
[477] Fix | Delete
_convert_DELETE_GLOBAL = _convert_NAME
[478] Fix | Delete
[479] Fix | Delete
def _convert_DEREF(self, arg):
[480] Fix | Delete
self._lookupName(arg, self.names)
[481] Fix | Delete
self._lookupName(arg, self.varnames)
[482] Fix | Delete
return self._lookupName(arg, self.closure)
[483] Fix | Delete
_convert_LOAD_DEREF = _convert_DEREF
[484] Fix | Delete
_convert_STORE_DEREF = _convert_DEREF
[485] Fix | Delete
[486] Fix | Delete
def _convert_LOAD_CLOSURE(self, arg):
[487] Fix | Delete
self._lookupName(arg, self.varnames)
[488] Fix | Delete
return self._lookupName(arg, self.closure)
[489] Fix | Delete
[490] Fix | Delete
_cmp = list(dis.cmp_op)
[491] Fix | Delete
def _convert_COMPARE_OP(self, arg):
[492] Fix | Delete
return self._cmp.index(arg)
[493] Fix | Delete
[494] Fix | Delete
# similarly for other opcodes...
[495] Fix | Delete
[496] Fix | Delete
for name, obj in locals().items():
[497] Fix | Delete
if name[:9] == "_convert_":
[498] Fix | Delete
opname = name[9:]
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function