python2.6-compiler-package

compiler/pycodegen.py

8:3dea01325c0d
2012-06-12 Paul Boddie Added confusing but probably necessary licensing statements.
     1 import imp     2 import os     3 import marshal     4 import struct     5 import sys     6 from cStringIO import StringIO     7      8 from compiler import ast, parse, walk, syntax     9 from compiler import pyassem, misc, future, symbols    10 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL    11 from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,    12      CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,    13      CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION)    14 from compiler.pyassem import TupleArg    15     16 # XXX The version-specific code can go, since this code only works with 2.x.    17 # Do we have Python 1.x or Python 2.x?    18 try:    19     VERSION = sys.version_info[0]    20 except AttributeError:    21     VERSION = 1    22     23 callfunc_opcode_info = {    24     # (Have *args, Have **args) : opcode    25     (0,0) : "CALL_FUNCTION",    26     (1,0) : "CALL_FUNCTION_VAR",    27     (0,1) : "CALL_FUNCTION_KW",    28     (1,1) : "CALL_FUNCTION_VAR_KW",    29 }    30     31 LOOP = 1    32 EXCEPT = 2    33 TRY_FINALLY = 3    34 END_FINALLY = 4    35     36 def compileFile(filename, display=0):    37     f = open(filename, 'U')    38     buf = f.read()    39     f.close()    40     mod = Module(buf, filename)    41     try:    42         mod.compile(display)    43     except SyntaxError:    44         raise    45     else:    46         f = open(filename + "c", "wb")    47         mod.dump(f)    48         f.close()    49     50 def compile(source, filename, mode, flags=None, dont_inherit=None):    51     """Replacement for builtin compile() function"""    52     if flags is not None or dont_inherit is not None:    53         raise RuntimeError, "not implemented yet"    54     55     if mode == "single":    56         gen = Interactive(source, filename)    57     elif mode == "exec":    58         gen = Module(source, filename)    59     elif mode == "eval":    60         gen = Expression(source, filename)    61     else:    62         raise ValueError("compile() 3rd arg must be 'exec' or "    63                          "'eval' or 'single'")    64     gen.compile()    65     return gen.code    66     67 class AbstractCompileMode:    68     69     mode = None # defined by subclass    70     71     def __init__(self, source, filename):    72         self.source = source    73         self.filename = filename    74         self.code = None    75     76     def _get_tree(self):    77         tree = parse(self.source, self.mode)    78         misc.set_filename(self.filename, tree)    79         syntax.check(tree)    80         return tree    81     82     def compile(self):    83         pass # implemented by subclass    84     85     def getCode(self):    86         return self.code    87     88 class Expression(AbstractCompileMode):    89     90     mode = "eval"    91     92     def compile(self):    93         tree = self._get_tree()    94         gen = ExpressionCodeGenerator(tree)    95         self.code = gen.getCode()    96     97 class Interactive(AbstractCompileMode):    98     99     mode = "single"   100    101     def compile(self):   102         tree = self._get_tree()   103         gen = InteractiveCodeGenerator(tree)   104         self.code = gen.getCode()   105    106 class Module(AbstractCompileMode):   107    108     mode = "exec"   109    110     def compile(self, display=0):   111         tree = self._get_tree()   112         gen = ModuleCodeGenerator(tree)   113         if display:   114             import pprint   115             print pprint.pprint(tree)   116         self.code = gen.getCode()   117    118     def dump(self, f):   119         f.write(self.getPycHeader())   120         marshal.dump(self.code, f)   121    122     MAGIC = imp.get_magic()   123    124     def getPycHeader(self):   125         # compile.c uses marshal to write a long directly, with   126         # calling the interface that would also generate a 1-byte code   127         # to indicate the type of the value.  simplest way to get the   128         # same effect is to call marshal and then skip the code.   129         mtime = os.path.getmtime(self.filename)   130         mtime = struct.pack('<i', mtime)   131         return self.MAGIC + mtime   132    133 class LocalNameFinder:   134     """Find local names in scope"""   135     def __init__(self, names=()):   136         self.names = misc.Set()   137         self.globals = misc.Set()   138         for name in names:   139             self.names.add(name)   140    141     # XXX list comprehensions and for loops   142    143     def getLocals(self):   144         for elt in self.globals.elements():   145             if self.names.has_elt(elt):   146                 self.names.remove(elt)   147         return self.names   148    149     def visitDict(self, node):   150         pass   151    152     def visitGlobal(self, node):   153         for name in node.names:   154             self.globals.add(name)   155    156     def visitFunction(self, node):   157         self.names.add(node.name)   158    159     def visitLambda(self, node):   160         pass   161    162     def visitImport(self, node):   163         for name, alias in node.names:   164             self.names.add(alias or name)   165    166     def visitFrom(self, node):   167         for name, alias in node.names:   168             self.names.add(alias or name)   169    170     def visitClass(self, node):   171         self.names.add(node.name)   172    173     def visitAssName(self, node):   174         self.names.add(node.name)   175    176 def is_constant_false(node):   177     if isinstance(node, ast.Const):   178         if not node.value:   179             return 1   180     return 0   181    182 class CodeGenerator:   183     """Defines basic code generator for Python bytecode   184    185     This class is an abstract base class.  Concrete subclasses must   186     define an __init__() that defines self.graph and then calls the   187     __init__() defined in this class.   188    189     The concrete class must also define the class attributes   190     NameFinder, FunctionGen, and ClassGen.  These attributes can be   191     defined in the initClass() method, which is a hook for   192     initializing these methods after all the classes have been   193     defined.   194     """   195    196     optimized = 0 # is namespace access optimized?   197     __initialized = None   198     class_name = None # provide default for instance variable   199    200     def __init__(self):   201         if self.__initialized is None:   202             self.initClass()   203             self.__class__.__initialized = 1   204         self.checkClass()   205         self.locals = misc.Stack()   206         self.setups = misc.Stack()   207         self.last_lineno = None   208         self._setupGraphDelegation()   209         self._div_op = "BINARY_DIVIDE"   210    211         # XXX set flags based on future features   212         futures = self.get_module().futures   213         for feature in futures:   214             if feature == "division":   215                 self.graph.setFlag(CO_FUTURE_DIVISION)   216                 self._div_op = "BINARY_TRUE_DIVIDE"   217             elif feature == "absolute_import":   218                 self.graph.setFlag(CO_FUTURE_ABSIMPORT)   219             elif feature == "with_statement":   220                 self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)   221             elif feature == "print_function":   222                 self.graph.setFlag(CO_FUTURE_PRINT_FUNCTION)   223    224     def initClass(self):   225         """This method is called once for each class"""   226    227     def checkClass(self):   228         """Verify that class is constructed correctly"""   229         try:   230             assert hasattr(self, 'graph')   231             assert getattr(self, 'NameFinder')   232             assert getattr(self, 'FunctionGen')   233             assert getattr(self, 'ClassGen')   234         except AssertionError, msg:   235             intro = "Bad class construction for %s" % self.__class__.__name__   236             raise AssertionError, intro   237    238     def _setupGraphDelegation(self):   239         self.emit = self.graph.emit   240         self.newBlock = self.graph.newBlock   241         self.startBlock = self.graph.startBlock   242         self.nextBlock = self.graph.nextBlock   243         self.setDocstring = self.graph.setDocstring   244    245     def getCode(self):   246         """Return a code object"""   247         return self.graph.getCode()   248    249     def mangle(self, name):   250         if self.class_name is not None:   251             return misc.mangle(name, self.class_name)   252         else:   253             return name   254    255     def parseSymbols(self, tree):   256         s = symbols.SymbolVisitor()   257         walk(tree, s)   258         return s.scopes   259    260     def get_module(self):   261         raise RuntimeError, "should be implemented by subclasses"   262    263     # Next five methods handle name access   264    265     def isLocalName(self, name):   266         return self.locals.top().has_elt(name)   267    268     def storeName(self, name):   269         self._nameOp('STORE', name)   270    271     def loadName(self, name):   272         self._nameOp('LOAD', name)   273    274     def delName(self, name):   275         self._nameOp('DELETE', name)   276    277     def _nameOp(self, prefix, name):   278         name = self.mangle(name)   279         scope = self.scope.check_name(name)   280         if scope == SC_LOCAL:   281             if not self.optimized:   282                 self.emit(prefix + '_NAME', name)   283             else:   284                 self.emit(prefix + '_FAST', name)   285         elif scope == SC_GLOBAL:   286             if not self.optimized:   287                 self.emit(prefix + '_NAME', name)   288             else:   289                 self.emit(prefix + '_GLOBAL', name)   290         elif scope == SC_FREE or scope == SC_CELL:   291             self.emit(prefix + '_DEREF', name)   292         else:   293             raise RuntimeError, "unsupported scope for var %s: %d" % \   294                   (name, scope)   295    296     def _implicitNameOp(self, prefix, name):   297         """Emit name ops for names generated implicitly by for loops   298    299         The interpreter generates names that start with a period or   300         dollar sign.  The symbol table ignores these names because   301         they aren't present in the program text.   302         """   303         if self.optimized:   304             self.emit(prefix + '_FAST', name)   305         else:   306             self.emit(prefix + '_NAME', name)   307    308     # The set_lineno() function and the explicit emit() calls for   309     # SET_LINENO below are only used to generate the line number table.   310     # As of Python 2.3, the interpreter does not have a SET_LINENO   311     # instruction.  pyassem treats SET_LINENO opcodes as a special case.   312    313     def set_lineno(self, node, force=False):   314         """Emit SET_LINENO if necessary.   315    316         The instruction is considered necessary if the node has a   317         lineno attribute and it is different than the last lineno   318         emitted.   319    320         Returns true if SET_LINENO was emitted.   321    322         There are no rules for when an AST node should have a lineno   323         attribute.  The transformer and AST code need to be reviewed   324         and a consistent policy implemented and documented.  Until   325         then, this method works around missing line numbers.   326         """   327         lineno = getattr(node, 'lineno', None)   328         if lineno is not None and (lineno != self.last_lineno   329                                    or force):   330             self.emit('SET_LINENO', lineno)   331             self.last_lineno = lineno   332             return True   333         return False   334    335     # The first few visitor methods handle nodes that generator new   336     # code objects.  They use class attributes to determine what   337     # specialized code generators to use.   338    339     NameFinder = LocalNameFinder   340     FunctionGen = None   341     ClassGen = None   342    343     def visitModule(self, node):   344         self.scopes = self.parseSymbols(node)   345         self.scope = self.scopes[node]   346         self.emit('SET_LINENO', 0)   347         if node.doc:   348             self.emit('LOAD_CONST', node.doc)   349             self.storeName('__doc__')   350         lnf = walk(node.node, self.NameFinder(), verbose=0)   351         self.locals.push(lnf.getLocals())   352         self.visit(node.node)   353         self.emit('LOAD_CONST', None)   354         self.emit('RETURN_VALUE')   355    356     def visitExpression(self, node):   357         self.set_lineno(node)   358         self.scopes = self.parseSymbols(node)   359         self.scope = self.scopes[node]   360         self.visit(node.node)   361         self.emit('RETURN_VALUE')   362    363     def visitFunction(self, node):   364         self._visitFuncOrLambda(node, isLambda=0)   365         if node.doc:   366             self.setDocstring(node.doc)   367         self.storeName(node.name)   368    369     def visitLambda(self, node):   370         self._visitFuncOrLambda(node, isLambda=1)   371    372     def _visitFuncOrLambda(self, node, isLambda=0):   373         if not isLambda and node.decorators:   374             for decorator in node.decorators.nodes:   375                 self.visit(decorator)   376             ndecorators = len(node.decorators.nodes)   377         else:   378             ndecorators = 0   379    380         gen = self.FunctionGen(node, self.scopes, isLambda,   381                                self.class_name, self.get_module())   382         walk(node.code, gen)   383         gen.finish()   384         self.set_lineno(node)   385         for default in node.defaults:   386             self.visit(default)   387         self._makeClosure(gen, len(node.defaults))   388         for i in range(ndecorators):   389             self.emit('CALL_FUNCTION', 1)   390    391     def visitClass(self, node):   392         gen = self.ClassGen(node, self.scopes,   393                             self.get_module())   394         walk(node.code, gen)   395         gen.finish()   396         self.set_lineno(node)   397         self.emit('LOAD_CONST', node.name)   398         for base in node.bases:   399             self.visit(base)   400         self.emit('BUILD_TUPLE', len(node.bases))   401         self._makeClosure(gen, 0)   402         self.emit('CALL_FUNCTION', 0)   403         self.emit('BUILD_CLASS')   404         self.storeName(node.name)   405    406     # The rest are standard visitor methods   407    408     # The next few implement control-flow statements   409    410     def visitIf(self, node):   411         end = self.newBlock()   412         numtests = len(node.tests)   413         for i in range(numtests):   414             test, suite = node.tests[i]   415             if is_constant_false(test):   416                 # XXX will need to check generator stuff here   417                 continue   418             self.set_lineno(test)   419             self.visit(test)   420             nextTest = self.newBlock()   421             self.emit('JUMP_IF_FALSE', nextTest)   422             self.nextBlock()   423             self.emit('POP_TOP')   424             self.visit(suite)   425             self.emit('JUMP_FORWARD', end)   426             self.startBlock(nextTest)   427             self.emit('POP_TOP')   428         if node.else_:   429             self.visit(node.else_)   430         self.nextBlock(end)   431    432     def visitWhile(self, node):   433         self.set_lineno(node)   434    435         loop = self.newBlock()   436         else_ = self.newBlock()   437    438         after = self.newBlock()   439         self.emit('SETUP_LOOP', after)   440    441         self.nextBlock(loop)   442         self.setups.push((LOOP, loop))   443    444         self.set_lineno(node, force=True)   445         self.visit(node.test)   446         self.emit('JUMP_IF_FALSE', else_ or after)   447    448         self.nextBlock()   449         self.emit('POP_TOP')   450         self.visit(node.body)   451         self.emit('JUMP_ABSOLUTE', loop)   452    453         self.startBlock(else_) # or just the POPs if not else clause   454         self.emit('POP_TOP')   455         self.emit('POP_BLOCK')   456         self.setups.pop()   457         if node.else_:   458             self.visit(node.else_)   459         self.nextBlock(after)   460    461     def visitFor(self, node):   462         start = self.newBlock()   463         anchor = self.newBlock()   464         after = self.newBlock()   465         self.setups.push((LOOP, start))   466    467         self.set_lineno(node)   468         self.emit('SETUP_LOOP', after)   469         self.visit(node.list)   470         self.emit('GET_ITER')   471    472         self.nextBlock(start)   473         self.set_lineno(node, force=1)   474         self.emit('FOR_ITER', anchor)   475         self.visit(node.assign)   476         self.visit(node.body)   477         self.emit('JUMP_ABSOLUTE', start)   478         self.nextBlock(anchor)   479         self.emit('POP_BLOCK')   480         self.setups.pop()   481         if node.else_:   482             self.visit(node.else_)   483         self.nextBlock(after)   484    485     def visitBreak(self, node):   486         if not self.setups:   487             raise SyntaxError, "'break' outside loop (%s, %d)" % \   488                   (node.filename, node.lineno)   489         self.set_lineno(node)   490         self.emit('BREAK_LOOP')   491    492     def visitContinue(self, node):   493         if not self.setups:   494             raise SyntaxError, "'continue' outside loop (%s, %d)" % \   495                   (node.filename, node.lineno)   496         kind, block = self.setups.top()   497         if kind == LOOP:   498             self.set_lineno(node)   499             self.emit('JUMP_ABSOLUTE', block)   500             self.nextBlock()   501         elif kind == EXCEPT or kind == TRY_FINALLY:   502             self.set_lineno(node)   503             # find the block that starts the loop   504             top = len(self.setups)   505             while top > 0:   506                 top = top - 1   507                 kind, loop_block = self.setups[top]   508                 if kind == LOOP:   509                     break   510             if kind != LOOP:   511                 raise SyntaxError, "'continue' outside loop (%s, %d)" % \   512                       (node.filename, node.lineno)   513             self.emit('CONTINUE_LOOP', loop_block)   514             self.nextBlock()   515         elif kind == END_FINALLY:   516             msg = "'continue' not allowed inside 'finally' clause (%s, %d)"   517             raise SyntaxError, msg % (node.filename, node.lineno)   518    519     def visitTest(self, node, jump):   520         end = self.newBlock()   521         for child in node.nodes[:-1]:   522             self.visit(child)   523             self.emit(jump, end)   524             self.nextBlock()   525             self.emit('POP_TOP')   526         self.visit(node.nodes[-1])   527         self.nextBlock(end)   528    529     def visitAnd(self, node):   530         self.visitTest(node, 'JUMP_IF_FALSE')   531    532     def visitOr(self, node):   533         self.visitTest(node, 'JUMP_IF_TRUE')   534    535     def visitIfExp(self, node):   536         endblock = self.newBlock()   537         elseblock = self.newBlock()   538         self.visit(node.test)   539         self.emit('JUMP_IF_FALSE', elseblock)   540         self.emit('POP_TOP')   541         self.visit(node.then)   542         self.emit('JUMP_FORWARD', endblock)   543         self.nextBlock(elseblock)   544         self.emit('POP_TOP')   545         self.visit(node.else_)   546         self.nextBlock(endblock)   547    548     def visitCompare(self, node):   549         self.visit(node.expr)   550         cleanup = self.newBlock()   551         for op, code in node.ops[:-1]:   552             self.visit(code)   553             self.emit('DUP_TOP')   554             self.emit('ROT_THREE')   555             self.emit('COMPARE_OP', op)   556             self.emit('JUMP_IF_FALSE', cleanup)   557             self.nextBlock()   558             self.emit('POP_TOP')   559         # now do the last comparison   560         if node.ops:   561             op, code = node.ops[-1]   562             self.visit(code)   563             self.emit('COMPARE_OP', op)   564         if len(node.ops) > 1:   565             end = self.newBlock()   566             self.emit('JUMP_FORWARD', end)   567             self.startBlock(cleanup)   568             self.emit('ROT_TWO')   569             self.emit('POP_TOP')   570             self.nextBlock(end)   571    572     # list comprehensions   573     __list_count = 0   574    575     def visitListComp(self, node):   576         self.set_lineno(node)   577         # setup list   578         tmpname = "$list%d" % self.__list_count   579         self.__list_count = self.__list_count + 1   580         self.emit('BUILD_LIST', 0)   581         self.emit('DUP_TOP')   582         self._implicitNameOp('STORE', tmpname)   583    584         stack = []   585         for i, for_ in zip(range(len(node.quals)), node.quals):   586             start, anchor = self.visit(for_)   587             cont = None   588             for if_ in for_.ifs:   589                 if cont is None:   590                     cont = self.newBlock()   591                 self.visit(if_, cont)   592             stack.insert(0, (start, cont, anchor))   593    594         self._implicitNameOp('LOAD', tmpname)   595         self.visit(node.expr)   596         self.emit('LIST_APPEND')   597    598         for start, cont, anchor in stack:   599             if cont:   600                 skip_one = self.newBlock()   601                 self.emit('JUMP_FORWARD', skip_one)   602                 self.startBlock(cont)   603                 self.emit('POP_TOP')   604                 self.nextBlock(skip_one)   605             self.emit('JUMP_ABSOLUTE', start)   606             self.startBlock(anchor)   607         self._implicitNameOp('DELETE', tmpname)   608    609         self.__list_count = self.__list_count - 1   610    611     def visitListCompFor(self, node):   612         start = self.newBlock()   613         anchor = self.newBlock()   614    615         self.visit(node.list)   616         self.emit('GET_ITER')   617         self.nextBlock(start)   618         self.set_lineno(node, force=True)   619         self.emit('FOR_ITER', anchor)   620         self.nextBlock()   621         self.visit(node.assign)   622         return start, anchor   623    624     def visitListCompIf(self, node, branch):   625         self.set_lineno(node, force=True)   626         self.visit(node.test)   627         self.emit('JUMP_IF_FALSE', branch)   628         self.newBlock()   629         self.emit('POP_TOP')   630    631     def _makeClosure(self, gen, args):   632         frees = gen.scope.get_free_vars()   633         if frees:   634             for name in frees:   635                 self.emit('LOAD_CLOSURE', name)   636             self.emit('BUILD_TUPLE', len(frees))   637             self.emit('LOAD_CONST', gen)   638             self.emit('MAKE_CLOSURE', args)   639         else:   640             self.emit('LOAD_CONST', gen)   641             self.emit('MAKE_FUNCTION', args)   642    643     def visitGenExpr(self, node):   644         gen = GenExprCodeGenerator(node, self.scopes, self.class_name,   645                                    self.get_module())   646         walk(node.code, gen)   647         gen.finish()   648         self.set_lineno(node)   649         self._makeClosure(gen, 0)   650         # precomputation of outmost iterable   651         self.visit(node.code.quals[0].iter)   652         self.emit('GET_ITER')   653         self.emit('CALL_FUNCTION', 1)   654    655     def visitGenExprInner(self, node):   656         self.set_lineno(node)   657         # setup list   658    659         stack = []   660         for i, for_ in zip(range(len(node.quals)), node.quals):   661             start, anchor, end = self.visit(for_)   662             cont = None   663             for if_ in for_.ifs:   664                 if cont is None:   665                     cont = self.newBlock()   666                 self.visit(if_, cont)   667             stack.insert(0, (start, cont, anchor, end))   668    669         self.visit(node.expr)   670         self.emit('YIELD_VALUE')   671         self.emit('POP_TOP')   672    673         for start, cont, anchor, end in stack:   674             if cont:   675                 skip_one = self.newBlock()   676                 self.emit('JUMP_FORWARD', skip_one)   677                 self.startBlock(cont)   678                 self.emit('POP_TOP')   679                 self.nextBlock(skip_one)   680             self.emit('JUMP_ABSOLUTE', start)   681             self.startBlock(anchor)   682             self.emit('POP_BLOCK')   683             self.setups.pop()   684             self.startBlock(end)   685    686         self.emit('LOAD_CONST', None)   687    688     def visitGenExprFor(self, node):   689         start = self.newBlock()   690         anchor = self.newBlock()   691         end = self.newBlock()   692    693         self.setups.push((LOOP, start))   694         self.emit('SETUP_LOOP', end)   695    696         if node.is_outmost:   697             self.loadName('.0')   698         else:   699             self.visit(node.iter)   700             self.emit('GET_ITER')   701    702         self.nextBlock(start)   703         self.set_lineno(node, force=True)   704         self.emit('FOR_ITER', anchor)   705         self.nextBlock()   706         self.visit(node.assign)   707         return start, anchor, end   708    709     def visitGenExprIf(self, node, branch):   710         self.set_lineno(node, force=True)   711         self.visit(node.test)   712         self.emit('JUMP_IF_FALSE', branch)   713         self.newBlock()   714         self.emit('POP_TOP')   715    716     # exception related   717    718     def visitAssert(self, node):   719         # XXX would be interesting to implement this via a   720         # transformation of the AST before this stage   721         if __debug__:   722             end = self.newBlock()   723             self.set_lineno(node)   724             # XXX AssertionError appears to be special case -- it is always   725             # loaded as a global even if there is a local name.  I guess this   726             # is a sort of renaming op.   727             self.nextBlock()   728             self.visit(node.test)   729             self.emit('JUMP_IF_TRUE', end)   730             self.nextBlock()   731             self.emit('POP_TOP')   732             self.emit('LOAD_GLOBAL', 'AssertionError')   733             if node.fail:   734                 self.visit(node.fail)   735                 self.emit('RAISE_VARARGS', 2)   736             else:   737                 self.emit('RAISE_VARARGS', 1)   738             self.nextBlock(end)   739             self.emit('POP_TOP')   740    741     def visitRaise(self, node):   742         self.set_lineno(node)   743         n = 0   744         if node.expr1:   745             self.visit(node.expr1)   746             n = n + 1   747         if node.expr2:   748             self.visit(node.expr2)   749             n = n + 1   750         if node.expr3:   751             self.visit(node.expr3)   752             n = n + 1   753         self.emit('RAISE_VARARGS', n)   754    755     def visitTryExcept(self, node):   756         body = self.newBlock()   757         handlers = self.newBlock()   758         end = self.newBlock()   759         if node.else_:   760             lElse = self.newBlock()   761         else:   762             lElse = end   763         self.set_lineno(node)   764         self.emit('SETUP_EXCEPT', handlers)   765         self.nextBlock(body)   766         self.setups.push((EXCEPT, body))   767         self.visit(node.body)   768         self.emit('POP_BLOCK')   769         self.setups.pop()   770         self.emit('JUMP_FORWARD', lElse)   771         self.startBlock(handlers)   772    773         last = len(node.handlers) - 1   774         for i in range(len(node.handlers)):   775             expr, target, body = node.handlers[i]   776             self.set_lineno(expr)   777             if expr:   778                 self.emit('DUP_TOP')   779                 self.visit(expr)   780                 self.emit('COMPARE_OP', 'exception match')   781                 next = self.newBlock()   782                 self.emit('JUMP_IF_FALSE', next)   783                 self.nextBlock()   784                 self.emit('POP_TOP')   785             self.emit('POP_TOP')   786             if target:   787                 self.visit(target)   788             else:   789                 self.emit('POP_TOP')   790             self.emit('POP_TOP')   791             self.visit(body)   792             self.emit('JUMP_FORWARD', end)   793             if expr:   794                 self.nextBlock(next)   795             else:   796                 self.nextBlock()   797             if expr: # XXX   798                 self.emit('POP_TOP')   799         self.emit('END_FINALLY')   800         if node.else_:   801             self.nextBlock(lElse)   802             self.visit(node.else_)   803         self.nextBlock(end)   804    805     def visitTryFinally(self, node):   806         body = self.newBlock()   807         final = self.newBlock()   808         self.set_lineno(node)   809         self.emit('SETUP_FINALLY', final)   810         self.nextBlock(body)   811         self.setups.push((TRY_FINALLY, body))   812         self.visit(node.body)   813         self.emit('POP_BLOCK')   814         self.setups.pop()   815         self.emit('LOAD_CONST', None)   816         self.nextBlock(final)   817         self.setups.push((END_FINALLY, final))   818         self.visit(node.final)   819         self.emit('END_FINALLY')   820         self.setups.pop()   821    822     __with_count = 0   823    824     def visitWith(self, node):   825         body = self.newBlock()   826         final = self.newBlock()   827         valuevar = "$value%d" % self.__with_count   828         self.__with_count += 1   829         self.set_lineno(node)   830         self.visit(node.expr)   831         self.emit('DUP_TOP')   832         self.emit('LOAD_ATTR', '__exit__')   833         self.emit('ROT_TWO')   834         self.emit('LOAD_ATTR', '__enter__')   835         self.emit('CALL_FUNCTION', 0)   836         if node.vars is None:   837             self.emit('POP_TOP')   838         else:   839             self._implicitNameOp('STORE', valuevar)   840         self.emit('SETUP_FINALLY', final)   841         self.nextBlock(body)   842         self.setups.push((TRY_FINALLY, body))   843         if node.vars is not None:   844             self._implicitNameOp('LOAD', valuevar)   845             self._implicitNameOp('DELETE', valuevar)   846             self.visit(node.vars)   847         self.visit(node.body)   848         self.emit('POP_BLOCK')   849         self.setups.pop()   850         self.emit('LOAD_CONST', None)   851         self.nextBlock(final)   852         self.setups.push((END_FINALLY, final))   853         self.emit('WITH_CLEANUP')   854         self.emit('END_FINALLY')   855         self.setups.pop()   856         self.__with_count -= 1   857    858     # misc   859    860     def visitDiscard(self, node):   861         self.set_lineno(node)   862         self.visit(node.expr)   863         self.emit('POP_TOP')   864    865     def visitConst(self, node):   866         self.emit('LOAD_CONST', node.value)   867    868     def visitKeyword(self, node):   869         self.emit('LOAD_CONST', node.name)   870         self.visit(node.expr)   871    872     def visitGlobal(self, node):   873         # no code to generate   874         pass   875    876     def visitName(self, node):   877         self.set_lineno(node)   878         self.loadName(node.name)   879    880     def visitPass(self, node):   881         self.set_lineno(node)   882    883     def visitImport(self, node):   884         self.set_lineno(node)   885         level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1   886         for name, alias in node.names:   887             if VERSION > 1:   888                 self.emit('LOAD_CONST', level)   889                 self.emit('LOAD_CONST', None)   890             self.emit('IMPORT_NAME', name)   891             mod = name.split(".")[0]   892             if alias:   893                 self._resolveDots(name)   894                 self.storeName(alias)   895             else:   896                 self.storeName(mod)   897    898     def visitFrom(self, node):   899         self.set_lineno(node)   900         level = node.level   901         if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):   902             level = -1   903         fromlist = tuple(name for (name, alias) in node.names)   904         if VERSION > 1:   905             self.emit('LOAD_CONST', level)   906             self.emit('LOAD_CONST', fromlist)   907         self.emit('IMPORT_NAME', node.modname)   908         for name, alias in node.names:   909             if VERSION > 1:   910                 if name == '*':   911                     self.namespace = 0   912                     self.emit('IMPORT_STAR')   913                     # There can only be one name w/ from ... import *   914                     assert len(node.names) == 1   915                     return   916                 else:   917                     self.emit('IMPORT_FROM', name)   918                     self._resolveDots(name)   919                     self.storeName(alias or name)   920             else:   921                 self.emit('IMPORT_FROM', name)   922         self.emit('POP_TOP')   923    924     def _resolveDots(self, name):   925         elts = name.split(".")   926         if len(elts) == 1:   927             return   928         for elt in elts[1:]:   929             self.emit('LOAD_ATTR', elt)   930    931     def visitGetattr(self, node):   932         self.visit(node.expr)   933         self.emit('LOAD_ATTR', self.mangle(node.attrname))   934    935     # next five implement assignments   936    937     def visitAssign(self, node):   938         self.set_lineno(node)   939         self.visit(node.expr)   940         dups = len(node.nodes) - 1   941         for i in range(len(node.nodes)):   942             elt = node.nodes[i]   943             if i < dups:   944                 self.emit('DUP_TOP')   945             if isinstance(elt, ast.Node):   946                 self.visit(elt)   947    948     def visitAssName(self, node):   949         if node.flags == 'OP_ASSIGN':   950             self.storeName(node.name)   951         elif node.flags == 'OP_DELETE':   952             self.set_lineno(node)   953             self.delName(node.name)   954         else:   955             print "oops", node.flags   956    957     def visitAssAttr(self, node):   958         self.visit(node.expr)   959         if node.flags == 'OP_ASSIGN':   960             self.emit('STORE_ATTR', self.mangle(node.attrname))   961         elif node.flags == 'OP_DELETE':   962             self.emit('DELETE_ATTR', self.mangle(node.attrname))   963         else:   964             print "warning: unexpected flags:", node.flags   965             print node   966    967     def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):   968         if findOp(node) != 'OP_DELETE':   969             self.emit(op, len(node.nodes))   970         for child in node.nodes:   971             self.visit(child)   972    973     if VERSION > 1:   974         visitAssTuple = _visitAssSequence   975         visitAssList = _visitAssSequence   976     else:   977         def visitAssTuple(self, node):   978             self._visitAssSequence(node, 'UNPACK_TUPLE')   979    980         def visitAssList(self, node):   981             self._visitAssSequence(node, 'UNPACK_LIST')   982    983     # augmented assignment   984    985     def visitAugAssign(self, node):   986         self.set_lineno(node)   987         aug_node = wrap_aug(node.node)   988         self.visit(aug_node, "load")   989         self.visit(node.expr)   990         self.emit(self._augmented_opcode[node.op])   991         self.visit(aug_node, "store")   992    993     _augmented_opcode = {   994         '+=' : 'INPLACE_ADD',   995         '-=' : 'INPLACE_SUBTRACT',   996         '*=' : 'INPLACE_MULTIPLY',   997         '/=' : 'INPLACE_DIVIDE',   998         '//=': 'INPLACE_FLOOR_DIVIDE',   999         '%=' : 'INPLACE_MODULO',  1000         '**=': 'INPLACE_POWER',  1001         '>>=': 'INPLACE_RSHIFT',  1002         '<<=': 'INPLACE_LSHIFT',  1003         '&=' : 'INPLACE_AND',  1004         '^=' : 'INPLACE_XOR',  1005         '|=' : 'INPLACE_OR',  1006         }  1007   1008     def visitAugName(self, node, mode):  1009         if mode == "load":  1010             self.loadName(node.name)  1011         elif mode == "store":  1012             self.storeName(node.name)  1013   1014     def visitAugGetattr(self, node, mode):  1015         if mode == "load":  1016             self.visit(node.expr)  1017             self.emit('DUP_TOP')  1018             self.emit('LOAD_ATTR', self.mangle(node.attrname))  1019         elif mode == "store":  1020             self.emit('ROT_TWO')  1021             self.emit('STORE_ATTR', self.mangle(node.attrname))  1022   1023     def visitAugSlice(self, node, mode):  1024         if mode == "load":  1025             self.visitSlice(node, 1)  1026         elif mode == "store":  1027             slice = 0  1028             if node.lower:  1029                 slice = slice | 1  1030             if node.upper:  1031                 slice = slice | 2  1032             if slice == 0:  1033                 self.emit('ROT_TWO')  1034             elif slice == 3:  1035                 self.emit('ROT_FOUR')  1036             else:  1037                 self.emit('ROT_THREE')  1038             self.emit('STORE_SLICE+%d' % slice)  1039   1040     def visitAugSubscript(self, node, mode):  1041         if mode == "load":  1042             self.visitSubscript(node, 1)  1043         elif mode == "store":  1044             self.emit('ROT_THREE')  1045             self.emit('STORE_SUBSCR')  1046   1047     def visitExec(self, node):  1048         self.visit(node.expr)  1049         if node.locals is None:  1050             self.emit('LOAD_CONST', None)  1051         else:  1052             self.visit(node.locals)  1053         if node.globals is None:  1054             self.emit('DUP_TOP')  1055         else:  1056             self.visit(node.globals)  1057         self.emit('EXEC_STMT')  1058   1059     def visitCallFunc(self, node):  1060         pos = 0  1061         kw = 0  1062         self.set_lineno(node)  1063         self.visit(node.node)  1064         for arg in node.args:  1065             self.visit(arg)  1066             if isinstance(arg, ast.Keyword):  1067                 kw = kw + 1  1068             else:  1069                 pos = pos + 1  1070         if node.star_args is not None:  1071             self.visit(node.star_args)  1072         if node.dstar_args is not None:  1073             self.visit(node.dstar_args)  1074         have_star = node.star_args is not None  1075         have_dstar = node.dstar_args is not None  1076         opcode = callfunc_opcode_info[have_star, have_dstar]  1077         self.emit(opcode, kw << 8 | pos)  1078   1079     def visitPrint(self, node, newline=0):  1080         self.set_lineno(node)  1081         if node.dest:  1082             self.visit(node.dest)  1083         for child in node.nodes:  1084             if node.dest:  1085                 self.emit('DUP_TOP')  1086             self.visit(child)  1087             if node.dest:  1088                 self.emit('ROT_TWO')  1089                 self.emit('PRINT_ITEM_TO')  1090             else:  1091                 self.emit('PRINT_ITEM')  1092         if node.dest and not newline:  1093             self.emit('POP_TOP')  1094   1095     def visitPrintnl(self, node):  1096         self.visitPrint(node, newline=1)  1097         if node.dest:  1098             self.emit('PRINT_NEWLINE_TO')  1099         else:  1100             self.emit('PRINT_NEWLINE')  1101   1102     def visitReturn(self, node):  1103         self.set_lineno(node)  1104         self.visit(node.value)  1105         self.emit('RETURN_VALUE')  1106   1107     def visitYield(self, node):  1108         self.set_lineno(node)  1109         self.visit(node.value)  1110         self.emit('YIELD_VALUE')  1111   1112     # slice and subscript stuff  1113   1114     def visitSlice(self, node, aug_flag=None):  1115         # aug_flag is used by visitAugSlice  1116         self.visit(node.expr)  1117         slice = 0  1118         if node.lower:  1119             self.visit(node.lower)  1120             slice = slice | 1  1121         if node.upper:  1122             self.visit(node.upper)  1123             slice = slice | 2  1124         if aug_flag:  1125             if slice == 0:  1126                 self.emit('DUP_TOP')  1127             elif slice == 3:  1128                 self.emit('DUP_TOPX', 3)  1129             else:  1130                 self.emit('DUP_TOPX', 2)  1131         if node.flags == 'OP_APPLY':  1132             self.emit('SLICE+%d' % slice)  1133         elif node.flags == 'OP_ASSIGN':  1134             self.emit('STORE_SLICE+%d' % slice)  1135         elif node.flags == 'OP_DELETE':  1136             self.emit('DELETE_SLICE+%d' % slice)  1137         else:  1138             print "weird slice", node.flags  1139             raise  1140   1141     def visitSubscript(self, node, aug_flag=None):  1142         self.visit(node.expr)  1143         for sub in node.subs:  1144             self.visit(sub)  1145         if len(node.subs) > 1:  1146             self.emit('BUILD_TUPLE', len(node.subs))  1147         if aug_flag:  1148             self.emit('DUP_TOPX', 2)  1149         if node.flags == 'OP_APPLY':  1150             self.emit('BINARY_SUBSCR')  1151         elif node.flags == 'OP_ASSIGN':  1152             self.emit('STORE_SUBSCR')  1153         elif node.flags == 'OP_DELETE':  1154             self.emit('DELETE_SUBSCR')  1155   1156     # binary ops  1157   1158     def binaryOp(self, node, op):  1159         self.visit(node.left)  1160         self.visit(node.right)  1161         self.emit(op)  1162   1163     def visitAdd(self, node):  1164         return self.binaryOp(node, 'BINARY_ADD')  1165   1166     def visitSub(self, node):  1167         return self.binaryOp(node, 'BINARY_SUBTRACT')  1168   1169     def visitMul(self, node):  1170         return self.binaryOp(node, 'BINARY_MULTIPLY')  1171   1172     def visitDiv(self, node):  1173         return self.binaryOp(node, self._div_op)  1174   1175     def visitFloorDiv(self, node):  1176         return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')  1177   1178     def visitMod(self, node):  1179         return self.binaryOp(node, 'BINARY_MODULO')  1180   1181     def visitPower(self, node):  1182         return self.binaryOp(node, 'BINARY_POWER')  1183   1184     def visitLeftShift(self, node):  1185         return self.binaryOp(node, 'BINARY_LSHIFT')  1186   1187     def visitRightShift(self, node):  1188         return self.binaryOp(node, 'BINARY_RSHIFT')  1189   1190     # unary ops  1191   1192     def unaryOp(self, node, op):  1193         self.visit(node.expr)  1194         self.emit(op)  1195   1196     def visitInvert(self, node):  1197         return self.unaryOp(node, 'UNARY_INVERT')  1198   1199     def visitUnarySub(self, node):  1200         return self.unaryOp(node, 'UNARY_NEGATIVE')  1201   1202     def visitUnaryAdd(self, node):  1203         return self.unaryOp(node, 'UNARY_POSITIVE')  1204   1205     def visitUnaryInvert(self, node):  1206         return self.unaryOp(node, 'UNARY_INVERT')  1207   1208     def visitNot(self, node):  1209         return self.unaryOp(node, 'UNARY_NOT')  1210   1211     def visitBackquote(self, node):  1212         return self.unaryOp(node, 'UNARY_CONVERT')  1213   1214     # bit ops  1215   1216     def bitOp(self, nodes, op):  1217         self.visit(nodes[0])  1218         for node in nodes[1:]:  1219             self.visit(node)  1220             self.emit(op)  1221   1222     def visitBitand(self, node):  1223         return self.bitOp(node.nodes, 'BINARY_AND')  1224   1225     def visitBitor(self, node):  1226         return self.bitOp(node.nodes, 'BINARY_OR')  1227   1228     def visitBitxor(self, node):  1229         return self.bitOp(node.nodes, 'BINARY_XOR')  1230   1231     # object constructors  1232   1233     def visitEllipsis(self, node):  1234         self.emit('LOAD_CONST', Ellipsis)  1235   1236     def visitTuple(self, node):  1237         self.set_lineno(node)  1238         for elt in node.nodes:  1239             self.visit(elt)  1240         self.emit('BUILD_TUPLE', len(node.nodes))  1241   1242     def visitList(self, node):  1243         self.set_lineno(node)  1244         for elt in node.nodes:  1245             self.visit(elt)  1246         self.emit('BUILD_LIST', len(node.nodes))  1247   1248     def visitSliceobj(self, node):  1249         for child in node.nodes:  1250             self.visit(child)  1251         self.emit('BUILD_SLICE', len(node.nodes))  1252   1253     def visitDict(self, node):  1254         self.set_lineno(node)  1255         self.emit('BUILD_MAP', 0)  1256         for k, v in node.items:  1257             self.emit('DUP_TOP')  1258             self.visit(k)  1259             self.visit(v)  1260             self.emit('ROT_THREE')  1261             self.emit('STORE_SUBSCR')  1262   1263 class NestedScopeMixin:  1264     """Defines initClass() for nested scoping (Python 2.2-compatible)"""  1265     def initClass(self):  1266         self.__class__.NameFinder = LocalNameFinder  1267         self.__class__.FunctionGen = FunctionCodeGenerator  1268         self.__class__.ClassGen = ClassCodeGenerator  1269   1270 class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):  1271     __super_init = CodeGenerator.__init__  1272   1273     scopes = None  1274   1275     def __init__(self, tree):  1276         self.graph = pyassem.PyFlowGraph("<module>", tree.filename)  1277         self.futures = future.find_futures(tree)  1278         self.__super_init()  1279         walk(tree, self)  1280   1281     def get_module(self):  1282         return self  1283   1284 class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):  1285     __super_init = CodeGenerator.__init__  1286   1287     scopes = None  1288     futures = ()  1289   1290     def __init__(self, tree):  1291         self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)  1292         self.__super_init()  1293         walk(tree, self)  1294   1295     def get_module(self):  1296         return self  1297   1298 class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):  1299   1300     __super_init = CodeGenerator.__init__  1301   1302     scopes = None  1303     futures = ()  1304   1305     def __init__(self, tree):  1306         self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)  1307         self.__super_init()  1308         self.set_lineno(tree)  1309         walk(tree, self)  1310         self.emit('RETURN_VALUE')  1311   1312     def get_module(self):  1313         return self  1314   1315     def visitDiscard(self, node):  1316         # XXX Discard means it's an expression.  Perhaps this is a bad  1317         # name.  1318         self.visit(node.expr)  1319         self.emit('PRINT_EXPR')  1320   1321 class AbstractFunctionCode:  1322     optimized = 1  1323     lambdaCount = 0  1324   1325     def __init__(self, func, scopes, isLambda, class_name, mod):  1326         self.class_name = class_name  1327         self.module = mod  1328         if isLambda:  1329             klass = FunctionCodeGenerator  1330             name = "<lambda.%d>" % klass.lambdaCount  1331             klass.lambdaCount = klass.lambdaCount + 1  1332         else:  1333             name = func.name  1334   1335         args, hasTupleArg = generateArgList(func.argnames)  1336         self.graph = pyassem.PyFlowGraph(name, func.filename, args,  1337                                          optimized=1)  1338         self.isLambda = isLambda  1339         self.super_init()  1340   1341         if not isLambda and func.doc:  1342             self.setDocstring(func.doc)  1343   1344         lnf = walk(func.code, self.NameFinder(args), verbose=0)  1345         self.locals.push(lnf.getLocals())  1346         if func.varargs:  1347             self.graph.setFlag(CO_VARARGS)  1348         if func.kwargs:  1349             self.graph.setFlag(CO_VARKEYWORDS)  1350         self.set_lineno(func)  1351         if hasTupleArg:  1352             self.generateArgUnpack(func.argnames)  1353   1354     def get_module(self):  1355         return self.module  1356   1357     def finish(self):  1358         self.graph.startExitBlock()  1359         if not self.isLambda:  1360             self.emit('LOAD_CONST', None)  1361         self.emit('RETURN_VALUE')  1362   1363     def generateArgUnpack(self, args):  1364         for i in range(len(args)):  1365             arg = args[i]  1366             if isinstance(arg, tuple):  1367                 self.emit('LOAD_FAST', '.%d' % (i * 2))  1368                 self.unpackSequence(arg)  1369   1370     def unpackSequence(self, tup):  1371         if VERSION > 1:  1372             self.emit('UNPACK_SEQUENCE', len(tup))  1373         else:  1374             self.emit('UNPACK_TUPLE', len(tup))  1375         for elt in tup:  1376             if isinstance(elt, tuple):  1377                 self.unpackSequence(elt)  1378             else:  1379                 self._nameOp('STORE', elt)  1380   1381     unpackTuple = unpackSequence  1382   1383 class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,  1384                             CodeGenerator):  1385     super_init = CodeGenerator.__init__ # call be other init  1386     scopes = None  1387   1388     __super_init = AbstractFunctionCode.__init__  1389   1390     def __init__(self, func, scopes, isLambda, class_name, mod):  1391         self.scopes = scopes  1392         self.scope = scopes[func]  1393         self.__super_init(func, scopes, isLambda, class_name, mod)  1394         self.graph.setFreeVars(self.scope.get_free_vars())  1395         self.graph.setCellVars(self.scope.get_cell_vars())  1396         if self.scope.generator is not None:  1397             self.graph.setFlag(CO_GENERATOR)  1398   1399 class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,  1400                            CodeGenerator):  1401     super_init = CodeGenerator.__init__ # call be other init  1402     scopes = None  1403   1404     __super_init = AbstractFunctionCode.__init__  1405   1406     def __init__(self, gexp, scopes, class_name, mod):  1407         self.scopes = scopes  1408         self.scope = scopes[gexp]  1409         self.__super_init(gexp, scopes, 1, class_name, mod)  1410         self.graph.setFreeVars(self.scope.get_free_vars())  1411         self.graph.setCellVars(self.scope.get_cell_vars())  1412         self.graph.setFlag(CO_GENERATOR)  1413   1414 class AbstractClassCode:  1415   1416     def __init__(self, klass, scopes, module):  1417         self.class_name = klass.name  1418         self.module = module  1419         self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,  1420                                            optimized=0, klass=1)  1421         self.super_init()  1422         lnf = walk(klass.code, self.NameFinder(), verbose=0)  1423         self.locals.push(lnf.getLocals())  1424         self.graph.setFlag(CO_NEWLOCALS)  1425         if klass.doc:  1426             self.setDocstring(klass.doc)  1427   1428     def get_module(self):  1429         return self.module  1430   1431     def finish(self):  1432         self.graph.startExitBlock()  1433         self.emit('LOAD_LOCALS')  1434         self.emit('RETURN_VALUE')  1435   1436 class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):  1437     super_init = CodeGenerator.__init__  1438     scopes = None  1439   1440     __super_init = AbstractClassCode.__init__  1441   1442     def __init__(self, klass, scopes, module):  1443         self.scopes = scopes  1444         self.scope = scopes[klass]  1445         self.__super_init(klass, scopes, module)  1446         self.graph.setFreeVars(self.scope.get_free_vars())  1447         self.graph.setCellVars(self.scope.get_cell_vars())  1448         self.set_lineno(klass)  1449         self.emit("LOAD_GLOBAL", "__name__")  1450         self.storeName("__module__")  1451         if klass.doc:  1452             self.emit("LOAD_CONST", klass.doc)  1453             self.storeName('__doc__')  1454   1455 def generateArgList(arglist):  1456     """Generate an arg list marking TupleArgs"""  1457     args = []  1458     extra = []  1459     count = 0  1460     for i in range(len(arglist)):  1461         elt = arglist[i]  1462         if isinstance(elt, str):  1463             args.append(elt)  1464         elif isinstance(elt, tuple):  1465             args.append(TupleArg(i * 2, elt))  1466             extra.extend(misc.flatten(elt))  1467             count = count + 1  1468         else:  1469             raise ValueError, "unexpect argument type:", elt  1470     return args + extra, count  1471   1472 def findOp(node):  1473     """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""  1474     v = OpFinder()  1475     walk(node, v, verbose=0)  1476     return v.op  1477   1478 class OpFinder:  1479     def __init__(self):  1480         self.op = None  1481     def visitAssName(self, node):  1482         if self.op is None:  1483             self.op = node.flags  1484         elif self.op != node.flags:  1485             raise ValueError, "mixed ops in stmt"  1486     visitAssAttr = visitAssName  1487     visitSubscript = visitAssName  1488   1489 class Delegator:  1490     """Base class to support delegation for augmented assignment nodes  1491   1492     To generator code for augmented assignments, we use the following  1493     wrapper classes.  In visitAugAssign, the left-hand expression node  1494     is visited twice.  The first time the visit uses the normal method  1495     for that node .  The second time the visit uses a different method  1496     that generates the appropriate code to perform the assignment.  1497     These delegator classes wrap the original AST nodes in order to  1498     support the variant visit methods.  1499     """  1500     def __init__(self, obj):  1501         self.obj = obj  1502   1503     def __getattr__(self, attr):  1504         return getattr(self.obj, attr)  1505   1506 class AugGetattr(Delegator):  1507     pass  1508   1509 class AugName(Delegator):  1510     pass  1511   1512 class AugSlice(Delegator):  1513     pass  1514   1515 class AugSubscript(Delegator):  1516     pass  1517   1518 wrapper = {  1519     ast.Getattr: AugGetattr,  1520     ast.Name: AugName,  1521     ast.Slice: AugSlice,  1522     ast.Subscript: AugSubscript,  1523     }  1524   1525 def wrap_aug(node):  1526     return wrapper[node.__class__](node)  1527   1528 if __name__ == "__main__":  1529     for file in sys.argv[1:]:  1530         compileFile(file)