@@ -99,12 +99,6 @@ def getBlocksInOrder(self):
9999 if not self .exit in order :
100100 order .append (self .exit )
101101
102- ## for b in order:
103- ## print repr(b)
104- ## print "\t", b.get_children()
105- ## print b
106- ## print
107-
108102 return order
109103
110104 def getBlocks (self ):
@@ -222,6 +216,7 @@ def getContainedGraphs(self):
222216CO_NEWLOCALS = 0x0002
223217CO_VARARGS = 0x0004
224218CO_VARKEYWORDS = 0x0008
219+ CO_NESTED = 0x0010
225220
226221# the FlowGraph is transformed in place; it exists in one of these states
227222RAW = "RAW"
@@ -245,6 +240,15 @@ def __init__(self, name, filename, args=(), optimized=0):
245240 self .flags = 0
246241 self .consts = []
247242 self .names = []
243+ # Free variables found by the symbol table scan, including
244+ # variables used only in nested scopes, are included here.
245+ self .freevars = []
246+ self .cellvars = []
247+ # The closure list is used to track the order of cell
248+ # variables and free variables in the resulting code object.
249+ # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
250+ # kinds of variables.
251+ self .closure = []
248252 self .varnames = list (args ) or []
249253 for i in range (len (self .varnames )):
250254 var = self .varnames [i ]
@@ -260,6 +264,12 @@ def setFlag(self, flag):
260264 if flag == CO_VARARGS :
261265 self .argcount = self .argcount - 1
262266
267+ def setFreeVars (self , names ):
268+ self .freevars = list (names )
269+
270+ def setCellVars (self , names ):
271+ self .cellvars = names
272+
263273 def getCode (self ):
264274 """Get a Python code object"""
265275 if self .stage == RAW :
@@ -335,6 +345,7 @@ def convertArgs(self):
335345 """Convert arguments from symbolic to concrete form"""
336346 assert self .stage == FLAT
337347 self .consts .insert (0 , self .docstring )
348+ self .sort_cellvars ()
338349 for i in range (len (self .insts )):
339350 t = self .insts [i ]
340351 if len (t ) == 2 :
@@ -345,6 +356,19 @@ def convertArgs(self):
345356 self .insts [i ] = opname , conv (self , oparg )
346357 self .stage = CONV
347358
359+ def sort_cellvars (self ):
360+ """Sort cellvars in the order of varnames and prune from freevars.
361+ """
362+ cells = {}
363+ for name in self .cellvars :
364+ cells [name ] = 1
365+ self .cellvars = [name for name in self .varnames
366+ if cells .has_key (name )]
367+ for name in self .cellvars :
368+ del cells [name ]
369+ self .cellvars = self .cellvars + cells .keys ()
370+ self .closure = self .cellvars + self .freevars
371+
348372 def _lookupName (self , name , list ):
349373 """Return index of name in list, appending if necessary"""
350374 t = type (name )
@@ -382,6 +406,17 @@ def _convert_NAME(self, arg):
382406 _convert_STORE_GLOBAL = _convert_NAME
383407 _convert_DELETE_GLOBAL = _convert_NAME
384408
409+ def _convert_DEREF (self , arg ):
410+ self ._lookupName (arg , self .names )
411+ self ._lookupName (arg , self .varnames )
412+ return self ._lookupName (arg , self .closure )
413+ _convert_LOAD_DEREF = _convert_DEREF
414+ _convert_STORE_DEREF = _convert_DEREF
415+
416+ def _convert_LOAD_CLOSURE (self , arg ):
417+ self ._lookupName (arg , self .varnames )
418+ return self ._lookupName (arg , self .closure )
419+
385420 _cmp = list (dis .cmp_op )
386421 def _convert_COMPARE_OP (self , arg ):
387422 return self ._cmp .index (arg )
@@ -432,7 +467,8 @@ def newCodeObject(self):
432467 self .lnotab .getCode (), self .getConsts (),
433468 tuple (self .names ), tuple (self .varnames ),
434469 self .filename , self .name , self .lnotab .firstline ,
435- self .lnotab .getTable ())
470+ self .lnotab .getTable (), tuple (self .freevars ),
471+ tuple (self .cellvars ))
436472
437473 def getConsts (self ):
438474 """Return a tuple for the const slot of the code object
0 commit comments