python-2.5.2/win32/Lib/compiler/pycodegen.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     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)
       
    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 
       
   222     def initClass(self):
       
   223         """This method is called once for each class"""
       
   224 
       
   225     def checkClass(self):
       
   226         """Verify that class is constructed correctly"""
       
   227         try:
       
   228             assert hasattr(self, 'graph')
       
   229             assert getattr(self, 'NameFinder')
       
   230             assert getattr(self, 'FunctionGen')
       
   231             assert getattr(self, 'ClassGen')
       
   232         except AssertionError, msg:
       
   233             intro = "Bad class construction for %s" % self.__class__.__name__
       
   234             raise AssertionError, intro
       
   235 
       
   236     def _setupGraphDelegation(self):
       
   237         self.emit = self.graph.emit
       
   238         self.newBlock = self.graph.newBlock
       
   239         self.startBlock = self.graph.startBlock
       
   240         self.nextBlock = self.graph.nextBlock
       
   241         self.setDocstring = self.graph.setDocstring
       
   242 
       
   243     def getCode(self):
       
   244         """Return a code object"""
       
   245         return self.graph.getCode()
       
   246 
       
   247     def mangle(self, name):
       
   248         if self.class_name is not None:
       
   249             return misc.mangle(name, self.class_name)
       
   250         else:
       
   251             return name
       
   252 
       
   253     def parseSymbols(self, tree):
       
   254         s = symbols.SymbolVisitor()
       
   255         walk(tree, s)
       
   256         return s.scopes
       
   257 
       
   258     def get_module(self):
       
   259         raise RuntimeError, "should be implemented by subclasses"
       
   260 
       
   261     # Next five methods handle name access
       
   262 
       
   263     def isLocalName(self, name):
       
   264         return self.locals.top().has_elt(name)
       
   265 
       
   266     def storeName(self, name):
       
   267         self._nameOp('STORE', name)
       
   268 
       
   269     def loadName(self, name):
       
   270         self._nameOp('LOAD', name)
       
   271 
       
   272     def delName(self, name):
       
   273         self._nameOp('DELETE', name)
       
   274 
       
   275     def _nameOp(self, prefix, name):
       
   276         name = self.mangle(name)
       
   277         scope = self.scope.check_name(name)
       
   278         if scope == SC_LOCAL:
       
   279             if not self.optimized:
       
   280                 self.emit(prefix + '_NAME', name)
       
   281             else:
       
   282                 self.emit(prefix + '_FAST', name)
       
   283         elif scope == SC_GLOBAL:
       
   284             if not self.optimized:
       
   285                 self.emit(prefix + '_NAME', name)
       
   286             else:
       
   287                 self.emit(prefix + '_GLOBAL', name)
       
   288         elif scope == SC_FREE or scope == SC_CELL:
       
   289             self.emit(prefix + '_DEREF', name)
       
   290         else:
       
   291             raise RuntimeError, "unsupported scope for var %s: %d" % \
       
   292                   (name, scope)
       
   293 
       
   294     def _implicitNameOp(self, prefix, name):
       
   295         """Emit name ops for names generated implicitly by for loops
       
   296 
       
   297         The interpreter generates names that start with a period or
       
   298         dollar sign.  The symbol table ignores these names because
       
   299         they aren't present in the program text.
       
   300         """
       
   301         if self.optimized:
       
   302             self.emit(prefix + '_FAST', name)
       
   303         else:
       
   304             self.emit(prefix + '_NAME', name)
       
   305 
       
   306     # The set_lineno() function and the explicit emit() calls for
       
   307     # SET_LINENO below are only used to generate the line number table.
       
   308     # As of Python 2.3, the interpreter does not have a SET_LINENO
       
   309     # instruction.  pyassem treats SET_LINENO opcodes as a special case.
       
   310 
       
   311     def set_lineno(self, node, force=False):
       
   312         """Emit SET_LINENO if necessary.
       
   313 
       
   314         The instruction is considered necessary if the node has a
       
   315         lineno attribute and it is different than the last lineno
       
   316         emitted.
       
   317 
       
   318         Returns true if SET_LINENO was emitted.
       
   319 
       
   320         There are no rules for when an AST node should have a lineno
       
   321         attribute.  The transformer and AST code need to be reviewed
       
   322         and a consistent policy implemented and documented.  Until
       
   323         then, this method works around missing line numbers.
       
   324         """
       
   325         lineno = getattr(node, 'lineno', None)
       
   326         if lineno is not None and (lineno != self.last_lineno
       
   327                                    or force):
       
   328             self.emit('SET_LINENO', lineno)
       
   329             self.last_lineno = lineno
       
   330             return True
       
   331         return False
       
   332 
       
   333     # The first few visitor methods handle nodes that generator new
       
   334     # code objects.  They use class attributes to determine what
       
   335     # specialized code generators to use.
       
   336 
       
   337     NameFinder = LocalNameFinder
       
   338     FunctionGen = None
       
   339     ClassGen = None
       
   340 
       
   341     def visitModule(self, node):
       
   342         self.scopes = self.parseSymbols(node)
       
   343         self.scope = self.scopes[node]
       
   344         self.emit('SET_LINENO', 0)
       
   345         if node.doc:
       
   346             self.emit('LOAD_CONST', node.doc)
       
   347             self.storeName('__doc__')
       
   348         lnf = walk(node.node, self.NameFinder(), verbose=0)
       
   349         self.locals.push(lnf.getLocals())
       
   350         self.visit(node.node)
       
   351         self.emit('LOAD_CONST', None)
       
   352         self.emit('RETURN_VALUE')
       
   353 
       
   354     def visitExpression(self, node):
       
   355         self.set_lineno(node)
       
   356         self.scopes = self.parseSymbols(node)
       
   357         self.scope = self.scopes[node]
       
   358         self.visit(node.node)
       
   359         self.emit('RETURN_VALUE')
       
   360 
       
   361     def visitFunction(self, node):
       
   362         self._visitFuncOrLambda(node, isLambda=0)
       
   363         if node.doc:
       
   364             self.setDocstring(node.doc)
       
   365         self.storeName(node.name)
       
   366 
       
   367     def visitLambda(self, node):
       
   368         self._visitFuncOrLambda(node, isLambda=1)
       
   369 
       
   370     def _visitFuncOrLambda(self, node, isLambda=0):
       
   371         if not isLambda and node.decorators:
       
   372             for decorator in node.decorators.nodes:
       
   373                 self.visit(decorator)
       
   374             ndecorators = len(node.decorators.nodes)
       
   375         else:
       
   376             ndecorators = 0
       
   377 
       
   378         gen = self.FunctionGen(node, self.scopes, isLambda,
       
   379                                self.class_name, self.get_module())
       
   380         walk(node.code, gen)
       
   381         gen.finish()
       
   382         self.set_lineno(node)
       
   383         for default in node.defaults:
       
   384             self.visit(default)
       
   385         self._makeClosure(gen, len(node.defaults))
       
   386         for i in range(ndecorators):
       
   387             self.emit('CALL_FUNCTION', 1)
       
   388 
       
   389     def visitClass(self, node):
       
   390         gen = self.ClassGen(node, self.scopes,
       
   391                             self.get_module())
       
   392         walk(node.code, gen)
       
   393         gen.finish()
       
   394         self.set_lineno(node)
       
   395         self.emit('LOAD_CONST', node.name)
       
   396         for base in node.bases:
       
   397             self.visit(base)
       
   398         self.emit('BUILD_TUPLE', len(node.bases))
       
   399         self._makeClosure(gen, 0)
       
   400         self.emit('CALL_FUNCTION', 0)
       
   401         self.emit('BUILD_CLASS')
       
   402         self.storeName(node.name)
       
   403 
       
   404     # The rest are standard visitor methods
       
   405 
       
   406     # The next few implement control-flow statements
       
   407 
       
   408     def visitIf(self, node):
       
   409         end = self.newBlock()
       
   410         numtests = len(node.tests)
       
   411         for i in range(numtests):
       
   412             test, suite = node.tests[i]
       
   413             if is_constant_false(test):
       
   414                 # XXX will need to check generator stuff here
       
   415                 continue
       
   416             self.set_lineno(test)
       
   417             self.visit(test)
       
   418             nextTest = self.newBlock()
       
   419             self.emit('JUMP_IF_FALSE', nextTest)
       
   420             self.nextBlock()
       
   421             self.emit('POP_TOP')
       
   422             self.visit(suite)
       
   423             self.emit('JUMP_FORWARD', end)
       
   424             self.startBlock(nextTest)
       
   425             self.emit('POP_TOP')
       
   426         if node.else_:
       
   427             self.visit(node.else_)
       
   428         self.nextBlock(end)
       
   429 
       
   430     def visitWhile(self, node):
       
   431         self.set_lineno(node)
       
   432 
       
   433         loop = self.newBlock()
       
   434         else_ = self.newBlock()
       
   435 
       
   436         after = self.newBlock()
       
   437         self.emit('SETUP_LOOP', after)
       
   438 
       
   439         self.nextBlock(loop)
       
   440         self.setups.push((LOOP, loop))
       
   441 
       
   442         self.set_lineno(node, force=True)
       
   443         self.visit(node.test)
       
   444         self.emit('JUMP_IF_FALSE', else_ or after)
       
   445 
       
   446         self.nextBlock()
       
   447         self.emit('POP_TOP')
       
   448         self.visit(node.body)
       
   449         self.emit('JUMP_ABSOLUTE', loop)
       
   450 
       
   451         self.startBlock(else_) # or just the POPs if not else clause
       
   452         self.emit('POP_TOP')
       
   453         self.emit('POP_BLOCK')
       
   454         self.setups.pop()
       
   455         if node.else_:
       
   456             self.visit(node.else_)
       
   457         self.nextBlock(after)
       
   458 
       
   459     def visitFor(self, node):
       
   460         start = self.newBlock()
       
   461         anchor = self.newBlock()
       
   462         after = self.newBlock()
       
   463         self.setups.push((LOOP, start))
       
   464 
       
   465         self.set_lineno(node)
       
   466         self.emit('SETUP_LOOP', after)
       
   467         self.visit(node.list)
       
   468         self.emit('GET_ITER')
       
   469 
       
   470         self.nextBlock(start)
       
   471         self.set_lineno(node, force=1)
       
   472         self.emit('FOR_ITER', anchor)
       
   473         self.visit(node.assign)
       
   474         self.visit(node.body)
       
   475         self.emit('JUMP_ABSOLUTE', start)
       
   476         self.nextBlock(anchor)
       
   477         self.emit('POP_BLOCK')
       
   478         self.setups.pop()
       
   479         if node.else_:
       
   480             self.visit(node.else_)
       
   481         self.nextBlock(after)
       
   482 
       
   483     def visitBreak(self, node):
       
   484         if not self.setups:
       
   485             raise SyntaxError, "'break' outside loop (%s, %d)" % \
       
   486                   (node.filename, node.lineno)
       
   487         self.set_lineno(node)
       
   488         self.emit('BREAK_LOOP')
       
   489 
       
   490     def visitContinue(self, node):
       
   491         if not self.setups:
       
   492             raise SyntaxError, "'continue' outside loop (%s, %d)" % \
       
   493                   (node.filename, node.lineno)
       
   494         kind, block = self.setups.top()
       
   495         if kind == LOOP:
       
   496             self.set_lineno(node)
       
   497             self.emit('JUMP_ABSOLUTE', block)
       
   498             self.nextBlock()
       
   499         elif kind == EXCEPT or kind == TRY_FINALLY:
       
   500             self.set_lineno(node)
       
   501             # find the block that starts the loop
       
   502             top = len(self.setups)
       
   503             while top > 0:
       
   504                 top = top - 1
       
   505                 kind, loop_block = self.setups[top]
       
   506                 if kind == LOOP:
       
   507                     break
       
   508             if kind != LOOP:
       
   509                 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
       
   510                       (node.filename, node.lineno)
       
   511             self.emit('CONTINUE_LOOP', loop_block)
       
   512             self.nextBlock()
       
   513         elif kind == END_FINALLY:
       
   514             msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
       
   515             raise SyntaxError, msg % (node.filename, node.lineno)
       
   516 
       
   517     def visitTest(self, node, jump):
       
   518         end = self.newBlock()
       
   519         for child in node.nodes[:-1]:
       
   520             self.visit(child)
       
   521             self.emit(jump, end)
       
   522             self.nextBlock()
       
   523             self.emit('POP_TOP')
       
   524         self.visit(node.nodes[-1])
       
   525         self.nextBlock(end)
       
   526 
       
   527     def visitAnd(self, node):
       
   528         self.visitTest(node, 'JUMP_IF_FALSE')
       
   529 
       
   530     def visitOr(self, node):
       
   531         self.visitTest(node, 'JUMP_IF_TRUE')
       
   532 
       
   533     def visitIfExp(self, node):
       
   534         endblock = self.newBlock()
       
   535         elseblock = self.newBlock()
       
   536         self.visit(node.test)
       
   537         self.emit('JUMP_IF_FALSE', elseblock)
       
   538         self.emit('POP_TOP')
       
   539         self.visit(node.then)
       
   540         self.emit('JUMP_FORWARD', endblock)
       
   541         self.nextBlock(elseblock)
       
   542         self.emit('POP_TOP')
       
   543         self.visit(node.else_)
       
   544         self.nextBlock(endblock)
       
   545 
       
   546     def visitCompare(self, node):
       
   547         self.visit(node.expr)
       
   548         cleanup = self.newBlock()
       
   549         for op, code in node.ops[:-1]:
       
   550             self.visit(code)
       
   551             self.emit('DUP_TOP')
       
   552             self.emit('ROT_THREE')
       
   553             self.emit('COMPARE_OP', op)
       
   554             self.emit('JUMP_IF_FALSE', cleanup)
       
   555             self.nextBlock()
       
   556             self.emit('POP_TOP')
       
   557         # now do the last comparison
       
   558         if node.ops:
       
   559             op, code = node.ops[-1]
       
   560             self.visit(code)
       
   561             self.emit('COMPARE_OP', op)
       
   562         if len(node.ops) > 1:
       
   563             end = self.newBlock()
       
   564             self.emit('JUMP_FORWARD', end)
       
   565             self.startBlock(cleanup)
       
   566             self.emit('ROT_TWO')
       
   567             self.emit('POP_TOP')
       
   568             self.nextBlock(end)
       
   569 
       
   570     # list comprehensions
       
   571     __list_count = 0
       
   572 
       
   573     def visitListComp(self, node):
       
   574         self.set_lineno(node)
       
   575         # setup list
       
   576         append = "$append%d" % self.__list_count
       
   577         self.__list_count = self.__list_count + 1
       
   578         self.emit('BUILD_LIST', 0)
       
   579         self.emit('DUP_TOP')
       
   580         self.emit('LOAD_ATTR', 'append')
       
   581         self._implicitNameOp('STORE', append)
       
   582 
       
   583         stack = []
       
   584         for i, for_ in zip(range(len(node.quals)), node.quals):
       
   585             start, anchor = self.visit(for_)
       
   586             cont = None
       
   587             for if_ in for_.ifs:
       
   588                 if cont is None:
       
   589                     cont = self.newBlock()
       
   590                 self.visit(if_, cont)
       
   591             stack.insert(0, (start, cont, anchor))
       
   592 
       
   593         self._implicitNameOp('LOAD', append)
       
   594         self.visit(node.expr)
       
   595         self.emit('CALL_FUNCTION', 1)
       
   596         self.emit('POP_TOP')
       
   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', append)
       
   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         exitvar = "$exit%d" % self.__with_count
       
   828         valuevar = "$value%d" % self.__with_count
       
   829         self.__with_count += 1
       
   830         self.set_lineno(node)
       
   831         self.visit(node.expr)
       
   832         self.emit('DUP_TOP')
       
   833         self.emit('LOAD_ATTR', '__exit__')
       
   834         self._implicitNameOp('STORE', exitvar)
       
   835         self.emit('LOAD_ATTR', '__enter__')
       
   836         self.emit('CALL_FUNCTION', 0)
       
   837         if node.vars is None:
       
   838             self.emit('POP_TOP')
       
   839         else:
       
   840             self._implicitNameOp('STORE', valuevar)
       
   841         self.emit('SETUP_FINALLY', final)
       
   842         self.nextBlock(body)
       
   843         self.setups.push((TRY_FINALLY, body))
       
   844         if node.vars is not None:
       
   845             self._implicitNameOp('LOAD', valuevar)
       
   846             self._implicitNameOp('DELETE', valuevar)
       
   847             self.visit(node.vars)
       
   848         self.visit(node.body)
       
   849         self.emit('POP_BLOCK')
       
   850         self.setups.pop()
       
   851         self.emit('LOAD_CONST', None)
       
   852         self.nextBlock(final)
       
   853         self.setups.push((END_FINALLY, final))
       
   854         self._implicitNameOp('LOAD', exitvar)
       
   855         self._implicitNameOp('DELETE', exitvar)
       
   856         self.emit('WITH_CLEANUP')
       
   857         self.emit('END_FINALLY')
       
   858         self.setups.pop()
       
   859         self.__with_count -= 1
       
   860 
       
   861     # misc
       
   862 
       
   863     def visitDiscard(self, node):
       
   864         self.set_lineno(node)
       
   865         self.visit(node.expr)
       
   866         self.emit('POP_TOP')
       
   867 
       
   868     def visitConst(self, node):
       
   869         self.emit('LOAD_CONST', node.value)
       
   870 
       
   871     def visitKeyword(self, node):
       
   872         self.emit('LOAD_CONST', node.name)
       
   873         self.visit(node.expr)
       
   874 
       
   875     def visitGlobal(self, node):
       
   876         # no code to generate
       
   877         pass
       
   878 
       
   879     def visitName(self, node):
       
   880         self.set_lineno(node)
       
   881         self.loadName(node.name)
       
   882 
       
   883     def visitPass(self, node):
       
   884         self.set_lineno(node)
       
   885 
       
   886     def visitImport(self, node):
       
   887         self.set_lineno(node)
       
   888         level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1
       
   889         for name, alias in node.names:
       
   890             if VERSION > 1:
       
   891                 self.emit('LOAD_CONST', level)
       
   892                 self.emit('LOAD_CONST', None)
       
   893             self.emit('IMPORT_NAME', name)
       
   894             mod = name.split(".")[0]
       
   895             if alias:
       
   896                 self._resolveDots(name)
       
   897                 self.storeName(alias)
       
   898             else:
       
   899                 self.storeName(mod)
       
   900 
       
   901     def visitFrom(self, node):
       
   902         self.set_lineno(node)
       
   903         level = node.level
       
   904         if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
       
   905             level = -1
       
   906         fromlist = map(lambda (name, alias): name, node.names)
       
   907         if VERSION > 1:
       
   908             self.emit('LOAD_CONST', level)
       
   909             self.emit('LOAD_CONST', tuple(fromlist))
       
   910         self.emit('IMPORT_NAME', node.modname)
       
   911         for name, alias in node.names:
       
   912             if VERSION > 1:
       
   913                 if name == '*':
       
   914                     self.namespace = 0
       
   915                     self.emit('IMPORT_STAR')
       
   916                     # There can only be one name w/ from ... import *
       
   917                     assert len(node.names) == 1
       
   918                     return
       
   919                 else:
       
   920                     self.emit('IMPORT_FROM', name)
       
   921                     self._resolveDots(name)
       
   922                     self.storeName(alias or name)
       
   923             else:
       
   924                 self.emit('IMPORT_FROM', name)
       
   925         self.emit('POP_TOP')
       
   926 
       
   927     def _resolveDots(self, name):
       
   928         elts = name.split(".")
       
   929         if len(elts) == 1:
       
   930             return
       
   931         for elt in elts[1:]:
       
   932             self.emit('LOAD_ATTR', elt)
       
   933 
       
   934     def visitGetattr(self, node):
       
   935         self.visit(node.expr)
       
   936         self.emit('LOAD_ATTR', self.mangle(node.attrname))
       
   937 
       
   938     # next five implement assignments
       
   939 
       
   940     def visitAssign(self, node):
       
   941         self.set_lineno(node)
       
   942         self.visit(node.expr)
       
   943         dups = len(node.nodes) - 1
       
   944         for i in range(len(node.nodes)):
       
   945             elt = node.nodes[i]
       
   946             if i < dups:
       
   947                 self.emit('DUP_TOP')
       
   948             if isinstance(elt, ast.Node):
       
   949                 self.visit(elt)
       
   950 
       
   951     def visitAssName(self, node):
       
   952         if node.flags == 'OP_ASSIGN':
       
   953             self.storeName(node.name)
       
   954         elif node.flags == 'OP_DELETE':
       
   955             self.set_lineno(node)
       
   956             self.delName(node.name)
       
   957         else:
       
   958             print "oops", node.flags
       
   959 
       
   960     def visitAssAttr(self, node):
       
   961         self.visit(node.expr)
       
   962         if node.flags == 'OP_ASSIGN':
       
   963             self.emit('STORE_ATTR', self.mangle(node.attrname))
       
   964         elif node.flags == 'OP_DELETE':
       
   965             self.emit('DELETE_ATTR', self.mangle(node.attrname))
       
   966         else:
       
   967             print "warning: unexpected flags:", node.flags
       
   968             print node
       
   969 
       
   970     def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
       
   971         if findOp(node) != 'OP_DELETE':
       
   972             self.emit(op, len(node.nodes))
       
   973         for child in node.nodes:
       
   974             self.visit(child)
       
   975 
       
   976     if VERSION > 1:
       
   977         visitAssTuple = _visitAssSequence
       
   978         visitAssList = _visitAssSequence
       
   979     else:
       
   980         def visitAssTuple(self, node):
       
   981             self._visitAssSequence(node, 'UNPACK_TUPLE')
       
   982 
       
   983         def visitAssList(self, node):
       
   984             self._visitAssSequence(node, 'UNPACK_LIST')
       
   985 
       
   986     # augmented assignment
       
   987 
       
   988     def visitAugAssign(self, node):
       
   989         self.set_lineno(node)
       
   990         aug_node = wrap_aug(node.node)
       
   991         self.visit(aug_node, "load")
       
   992         self.visit(node.expr)
       
   993         self.emit(self._augmented_opcode[node.op])
       
   994         self.visit(aug_node, "store")
       
   995 
       
   996     _augmented_opcode = {
       
   997         '+=' : 'INPLACE_ADD',
       
   998         '-=' : 'INPLACE_SUBTRACT',
       
   999         '*=' : 'INPLACE_MULTIPLY',
       
  1000         '/=' : 'INPLACE_DIVIDE',
       
  1001         '//=': 'INPLACE_FLOOR_DIVIDE',
       
  1002         '%=' : 'INPLACE_MODULO',
       
  1003         '**=': 'INPLACE_POWER',
       
  1004         '>>=': 'INPLACE_RSHIFT',
       
  1005         '<<=': 'INPLACE_LSHIFT',
       
  1006         '&=' : 'INPLACE_AND',
       
  1007         '^=' : 'INPLACE_XOR',
       
  1008         '|=' : 'INPLACE_OR',
       
  1009         }
       
  1010 
       
  1011     def visitAugName(self, node, mode):
       
  1012         if mode == "load":
       
  1013             self.loadName(node.name)
       
  1014         elif mode == "store":
       
  1015             self.storeName(node.name)
       
  1016 
       
  1017     def visitAugGetattr(self, node, mode):
       
  1018         if mode == "load":
       
  1019             self.visit(node.expr)
       
  1020             self.emit('DUP_TOP')
       
  1021             self.emit('LOAD_ATTR', self.mangle(node.attrname))
       
  1022         elif mode == "store":
       
  1023             self.emit('ROT_TWO')
       
  1024             self.emit('STORE_ATTR', self.mangle(node.attrname))
       
  1025 
       
  1026     def visitAugSlice(self, node, mode):
       
  1027         if mode == "load":
       
  1028             self.visitSlice(node, 1)
       
  1029         elif mode == "store":
       
  1030             slice = 0
       
  1031             if node.lower:
       
  1032                 slice = slice | 1
       
  1033             if node.upper:
       
  1034                 slice = slice | 2
       
  1035             if slice == 0:
       
  1036                 self.emit('ROT_TWO')
       
  1037             elif slice == 3:
       
  1038                 self.emit('ROT_FOUR')
       
  1039             else:
       
  1040                 self.emit('ROT_THREE')
       
  1041             self.emit('STORE_SLICE+%d' % slice)
       
  1042 
       
  1043     def visitAugSubscript(self, node, mode):
       
  1044         if mode == "load":
       
  1045             self.visitSubscript(node, 1)
       
  1046         elif mode == "store":
       
  1047             self.emit('ROT_THREE')
       
  1048             self.emit('STORE_SUBSCR')
       
  1049 
       
  1050     def visitExec(self, node):
       
  1051         self.visit(node.expr)
       
  1052         if node.locals is None:
       
  1053             self.emit('LOAD_CONST', None)
       
  1054         else:
       
  1055             self.visit(node.locals)
       
  1056         if node.globals is None:
       
  1057             self.emit('DUP_TOP')
       
  1058         else:
       
  1059             self.visit(node.globals)
       
  1060         self.emit('EXEC_STMT')
       
  1061 
       
  1062     def visitCallFunc(self, node):
       
  1063         pos = 0
       
  1064         kw = 0
       
  1065         self.set_lineno(node)
       
  1066         self.visit(node.node)
       
  1067         for arg in node.args:
       
  1068             self.visit(arg)
       
  1069             if isinstance(arg, ast.Keyword):
       
  1070                 kw = kw + 1
       
  1071             else:
       
  1072                 pos = pos + 1
       
  1073         if node.star_args is not None:
       
  1074             self.visit(node.star_args)
       
  1075         if node.dstar_args is not None:
       
  1076             self.visit(node.dstar_args)
       
  1077         have_star = node.star_args is not None
       
  1078         have_dstar = node.dstar_args is not None
       
  1079         opcode = callfunc_opcode_info[have_star, have_dstar]
       
  1080         self.emit(opcode, kw << 8 | pos)
       
  1081 
       
  1082     def visitPrint(self, node, newline=0):
       
  1083         self.set_lineno(node)
       
  1084         if node.dest:
       
  1085             self.visit(node.dest)
       
  1086         for child in node.nodes:
       
  1087             if node.dest:
       
  1088                 self.emit('DUP_TOP')
       
  1089             self.visit(child)
       
  1090             if node.dest:
       
  1091                 self.emit('ROT_TWO')
       
  1092                 self.emit('PRINT_ITEM_TO')
       
  1093             else:
       
  1094                 self.emit('PRINT_ITEM')
       
  1095         if node.dest and not newline:
       
  1096             self.emit('POP_TOP')
       
  1097 
       
  1098     def visitPrintnl(self, node):
       
  1099         self.visitPrint(node, newline=1)
       
  1100         if node.dest:
       
  1101             self.emit('PRINT_NEWLINE_TO')
       
  1102         else:
       
  1103             self.emit('PRINT_NEWLINE')
       
  1104 
       
  1105     def visitReturn(self, node):
       
  1106         self.set_lineno(node)
       
  1107         self.visit(node.value)
       
  1108         self.emit('RETURN_VALUE')
       
  1109 
       
  1110     def visitYield(self, node):
       
  1111         self.set_lineno(node)
       
  1112         self.visit(node.value)
       
  1113         self.emit('YIELD_VALUE')
       
  1114 
       
  1115     # slice and subscript stuff
       
  1116 
       
  1117     def visitSlice(self, node, aug_flag=None):
       
  1118         # aug_flag is used by visitAugSlice
       
  1119         self.visit(node.expr)
       
  1120         slice = 0
       
  1121         if node.lower:
       
  1122             self.visit(node.lower)
       
  1123             slice = slice | 1
       
  1124         if node.upper:
       
  1125             self.visit(node.upper)
       
  1126             slice = slice | 2
       
  1127         if aug_flag:
       
  1128             if slice == 0:
       
  1129                 self.emit('DUP_TOP')
       
  1130             elif slice == 3:
       
  1131                 self.emit('DUP_TOPX', 3)
       
  1132             else:
       
  1133                 self.emit('DUP_TOPX', 2)
       
  1134         if node.flags == 'OP_APPLY':
       
  1135             self.emit('SLICE+%d' % slice)
       
  1136         elif node.flags == 'OP_ASSIGN':
       
  1137             self.emit('STORE_SLICE+%d' % slice)
       
  1138         elif node.flags == 'OP_DELETE':
       
  1139             self.emit('DELETE_SLICE+%d' % slice)
       
  1140         else:
       
  1141             print "weird slice", node.flags
       
  1142             raise
       
  1143 
       
  1144     def visitSubscript(self, node, aug_flag=None):
       
  1145         self.visit(node.expr)
       
  1146         for sub in node.subs:
       
  1147             self.visit(sub)
       
  1148         if len(node.subs) > 1:
       
  1149             self.emit('BUILD_TUPLE', len(node.subs))
       
  1150         if aug_flag:
       
  1151             self.emit('DUP_TOPX', 2)
       
  1152         if node.flags == 'OP_APPLY':
       
  1153             self.emit('BINARY_SUBSCR')
       
  1154         elif node.flags == 'OP_ASSIGN':
       
  1155             self.emit('STORE_SUBSCR')
       
  1156         elif node.flags == 'OP_DELETE':
       
  1157             self.emit('DELETE_SUBSCR')
       
  1158 
       
  1159     # binary ops
       
  1160 
       
  1161     def binaryOp(self, node, op):
       
  1162         self.visit(node.left)
       
  1163         self.visit(node.right)
       
  1164         self.emit(op)
       
  1165 
       
  1166     def visitAdd(self, node):
       
  1167         return self.binaryOp(node, 'BINARY_ADD')
       
  1168 
       
  1169     def visitSub(self, node):
       
  1170         return self.binaryOp(node, 'BINARY_SUBTRACT')
       
  1171 
       
  1172     def visitMul(self, node):
       
  1173         return self.binaryOp(node, 'BINARY_MULTIPLY')
       
  1174 
       
  1175     def visitDiv(self, node):
       
  1176         return self.binaryOp(node, self._div_op)
       
  1177 
       
  1178     def visitFloorDiv(self, node):
       
  1179         return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
       
  1180 
       
  1181     def visitMod(self, node):
       
  1182         return self.binaryOp(node, 'BINARY_MODULO')
       
  1183 
       
  1184     def visitPower(self, node):
       
  1185         return self.binaryOp(node, 'BINARY_POWER')
       
  1186 
       
  1187     def visitLeftShift(self, node):
       
  1188         return self.binaryOp(node, 'BINARY_LSHIFT')
       
  1189 
       
  1190     def visitRightShift(self, node):
       
  1191         return self.binaryOp(node, 'BINARY_RSHIFT')
       
  1192 
       
  1193     # unary ops
       
  1194 
       
  1195     def unaryOp(self, node, op):
       
  1196         self.visit(node.expr)
       
  1197         self.emit(op)
       
  1198 
       
  1199     def visitInvert(self, node):
       
  1200         return self.unaryOp(node, 'UNARY_INVERT')
       
  1201 
       
  1202     def visitUnarySub(self, node):
       
  1203         return self.unaryOp(node, 'UNARY_NEGATIVE')
       
  1204 
       
  1205     def visitUnaryAdd(self, node):
       
  1206         return self.unaryOp(node, 'UNARY_POSITIVE')
       
  1207 
       
  1208     def visitUnaryInvert(self, node):
       
  1209         return self.unaryOp(node, 'UNARY_INVERT')
       
  1210 
       
  1211     def visitNot(self, node):
       
  1212         return self.unaryOp(node, 'UNARY_NOT')
       
  1213 
       
  1214     def visitBackquote(self, node):
       
  1215         return self.unaryOp(node, 'UNARY_CONVERT')
       
  1216 
       
  1217     # bit ops
       
  1218 
       
  1219     def bitOp(self, nodes, op):
       
  1220         self.visit(nodes[0])
       
  1221         for node in nodes[1:]:
       
  1222             self.visit(node)
       
  1223             self.emit(op)
       
  1224 
       
  1225     def visitBitand(self, node):
       
  1226         return self.bitOp(node.nodes, 'BINARY_AND')
       
  1227 
       
  1228     def visitBitor(self, node):
       
  1229         return self.bitOp(node.nodes, 'BINARY_OR')
       
  1230 
       
  1231     def visitBitxor(self, node):
       
  1232         return self.bitOp(node.nodes, 'BINARY_XOR')
       
  1233 
       
  1234     # object constructors
       
  1235 
       
  1236     def visitEllipsis(self, node):
       
  1237         self.emit('LOAD_CONST', Ellipsis)
       
  1238 
       
  1239     def visitTuple(self, node):
       
  1240         self.set_lineno(node)
       
  1241         for elt in node.nodes:
       
  1242             self.visit(elt)
       
  1243         self.emit('BUILD_TUPLE', len(node.nodes))
       
  1244 
       
  1245     def visitList(self, node):
       
  1246         self.set_lineno(node)
       
  1247         for elt in node.nodes:
       
  1248             self.visit(elt)
       
  1249         self.emit('BUILD_LIST', len(node.nodes))
       
  1250 
       
  1251     def visitSliceobj(self, node):
       
  1252         for child in node.nodes:
       
  1253             self.visit(child)
       
  1254         self.emit('BUILD_SLICE', len(node.nodes))
       
  1255 
       
  1256     def visitDict(self, node):
       
  1257         self.set_lineno(node)
       
  1258         self.emit('BUILD_MAP', 0)
       
  1259         for k, v in node.items:
       
  1260             self.emit('DUP_TOP')
       
  1261             self.visit(k)
       
  1262             self.visit(v)
       
  1263             self.emit('ROT_THREE')
       
  1264             self.emit('STORE_SUBSCR')
       
  1265 
       
  1266 class NestedScopeMixin:
       
  1267     """Defines initClass() for nested scoping (Python 2.2-compatible)"""
       
  1268     def initClass(self):
       
  1269         self.__class__.NameFinder = LocalNameFinder
       
  1270         self.__class__.FunctionGen = FunctionCodeGenerator
       
  1271         self.__class__.ClassGen = ClassCodeGenerator
       
  1272 
       
  1273 class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
       
  1274     __super_init = CodeGenerator.__init__
       
  1275 
       
  1276     scopes = None
       
  1277 
       
  1278     def __init__(self, tree):
       
  1279         self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
       
  1280         self.futures = future.find_futures(tree)
       
  1281         self.__super_init()
       
  1282         walk(tree, self)
       
  1283 
       
  1284     def get_module(self):
       
  1285         return self
       
  1286 
       
  1287 class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
       
  1288     __super_init = CodeGenerator.__init__
       
  1289 
       
  1290     scopes = None
       
  1291     futures = ()
       
  1292 
       
  1293     def __init__(self, tree):
       
  1294         self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
       
  1295         self.__super_init()
       
  1296         walk(tree, self)
       
  1297 
       
  1298     def get_module(self):
       
  1299         return self
       
  1300 
       
  1301 class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
       
  1302 
       
  1303     __super_init = CodeGenerator.__init__
       
  1304 
       
  1305     scopes = None
       
  1306     futures = ()
       
  1307 
       
  1308     def __init__(self, tree):
       
  1309         self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
       
  1310         self.__super_init()
       
  1311         self.set_lineno(tree)
       
  1312         walk(tree, self)
       
  1313         self.emit('RETURN_VALUE')
       
  1314 
       
  1315     def get_module(self):
       
  1316         return self
       
  1317 
       
  1318     def visitDiscard(self, node):
       
  1319         # XXX Discard means it's an expression.  Perhaps this is a bad
       
  1320         # name.
       
  1321         self.visit(node.expr)
       
  1322         self.emit('PRINT_EXPR')
       
  1323 
       
  1324 class AbstractFunctionCode:
       
  1325     optimized = 1
       
  1326     lambdaCount = 0
       
  1327 
       
  1328     def __init__(self, func, scopes, isLambda, class_name, mod):
       
  1329         self.class_name = class_name
       
  1330         self.module = mod
       
  1331         if isLambda:
       
  1332             klass = FunctionCodeGenerator
       
  1333             name = "<lambda.%d>" % klass.lambdaCount
       
  1334             klass.lambdaCount = klass.lambdaCount + 1
       
  1335         else:
       
  1336             name = func.name
       
  1337 
       
  1338         args, hasTupleArg = generateArgList(func.argnames)
       
  1339         self.graph = pyassem.PyFlowGraph(name, func.filename, args,
       
  1340                                          optimized=1)
       
  1341         self.isLambda = isLambda
       
  1342         self.super_init()
       
  1343 
       
  1344         if not isLambda and func.doc:
       
  1345             self.setDocstring(func.doc)
       
  1346 
       
  1347         lnf = walk(func.code, self.NameFinder(args), verbose=0)
       
  1348         self.locals.push(lnf.getLocals())
       
  1349         if func.varargs:
       
  1350             self.graph.setFlag(CO_VARARGS)
       
  1351         if func.kwargs:
       
  1352             self.graph.setFlag(CO_VARKEYWORDS)
       
  1353         self.set_lineno(func)
       
  1354         if hasTupleArg:
       
  1355             self.generateArgUnpack(func.argnames)
       
  1356 
       
  1357     def get_module(self):
       
  1358         return self.module
       
  1359 
       
  1360     def finish(self):
       
  1361         self.graph.startExitBlock()
       
  1362         if not self.isLambda:
       
  1363             self.emit('LOAD_CONST', None)
       
  1364         self.emit('RETURN_VALUE')
       
  1365 
       
  1366     def generateArgUnpack(self, args):
       
  1367         for i in range(len(args)):
       
  1368             arg = args[i]
       
  1369             if isinstance(arg, tuple):
       
  1370                 self.emit('LOAD_FAST', '.%d' % (i * 2))
       
  1371                 self.unpackSequence(arg)
       
  1372 
       
  1373     def unpackSequence(self, tup):
       
  1374         if VERSION > 1:
       
  1375             self.emit('UNPACK_SEQUENCE', len(tup))
       
  1376         else:
       
  1377             self.emit('UNPACK_TUPLE', len(tup))
       
  1378         for elt in tup:
       
  1379             if isinstance(elt, tuple):
       
  1380                 self.unpackSequence(elt)
       
  1381             else:
       
  1382                 self._nameOp('STORE', elt)
       
  1383 
       
  1384     unpackTuple = unpackSequence
       
  1385 
       
  1386 class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
       
  1387                             CodeGenerator):
       
  1388     super_init = CodeGenerator.__init__ # call be other init
       
  1389     scopes = None
       
  1390 
       
  1391     __super_init = AbstractFunctionCode.__init__
       
  1392 
       
  1393     def __init__(self, func, scopes, isLambda, class_name, mod):
       
  1394         self.scopes = scopes
       
  1395         self.scope = scopes[func]
       
  1396         self.__super_init(func, scopes, isLambda, class_name, mod)
       
  1397         self.graph.setFreeVars(self.scope.get_free_vars())
       
  1398         self.graph.setCellVars(self.scope.get_cell_vars())
       
  1399         if self.scope.generator is not None:
       
  1400             self.graph.setFlag(CO_GENERATOR)
       
  1401 
       
  1402 class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
       
  1403                            CodeGenerator):
       
  1404     super_init = CodeGenerator.__init__ # call be other init
       
  1405     scopes = None
       
  1406 
       
  1407     __super_init = AbstractFunctionCode.__init__
       
  1408 
       
  1409     def __init__(self, gexp, scopes, class_name, mod):
       
  1410         self.scopes = scopes
       
  1411         self.scope = scopes[gexp]
       
  1412         self.__super_init(gexp, scopes, 1, class_name, mod)
       
  1413         self.graph.setFreeVars(self.scope.get_free_vars())
       
  1414         self.graph.setCellVars(self.scope.get_cell_vars())
       
  1415         self.graph.setFlag(CO_GENERATOR)
       
  1416 
       
  1417 class AbstractClassCode:
       
  1418 
       
  1419     def __init__(self, klass, scopes, module):
       
  1420         self.class_name = klass.name
       
  1421         self.module = module
       
  1422         self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
       
  1423                                            optimized=0, klass=1)
       
  1424         self.super_init()
       
  1425         lnf = walk(klass.code, self.NameFinder(), verbose=0)
       
  1426         self.locals.push(lnf.getLocals())
       
  1427         self.graph.setFlag(CO_NEWLOCALS)
       
  1428         if klass.doc:
       
  1429             self.setDocstring(klass.doc)
       
  1430 
       
  1431     def get_module(self):
       
  1432         return self.module
       
  1433 
       
  1434     def finish(self):
       
  1435         self.graph.startExitBlock()
       
  1436         self.emit('LOAD_LOCALS')
       
  1437         self.emit('RETURN_VALUE')
       
  1438 
       
  1439 class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
       
  1440     super_init = CodeGenerator.__init__
       
  1441     scopes = None
       
  1442 
       
  1443     __super_init = AbstractClassCode.__init__
       
  1444 
       
  1445     def __init__(self, klass, scopes, module):
       
  1446         self.scopes = scopes
       
  1447         self.scope = scopes[klass]
       
  1448         self.__super_init(klass, scopes, module)
       
  1449         self.graph.setFreeVars(self.scope.get_free_vars())
       
  1450         self.graph.setCellVars(self.scope.get_cell_vars())
       
  1451         self.set_lineno(klass)
       
  1452         self.emit("LOAD_GLOBAL", "__name__")
       
  1453         self.storeName("__module__")
       
  1454         if klass.doc:
       
  1455             self.emit("LOAD_CONST", klass.doc)
       
  1456             self.storeName('__doc__')
       
  1457 
       
  1458 def generateArgList(arglist):
       
  1459     """Generate an arg list marking TupleArgs"""
       
  1460     args = []
       
  1461     extra = []
       
  1462     count = 0
       
  1463     for i in range(len(arglist)):
       
  1464         elt = arglist[i]
       
  1465         if isinstance(elt, str):
       
  1466             args.append(elt)
       
  1467         elif isinstance(elt, tuple):
       
  1468             args.append(TupleArg(i * 2, elt))
       
  1469             extra.extend(misc.flatten(elt))
       
  1470             count = count + 1
       
  1471         else:
       
  1472             raise ValueError, "unexpect argument type:", elt
       
  1473     return args + extra, count
       
  1474 
       
  1475 def findOp(node):
       
  1476     """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
       
  1477     v = OpFinder()
       
  1478     walk(node, v, verbose=0)
       
  1479     return v.op
       
  1480 
       
  1481 class OpFinder:
       
  1482     def __init__(self):
       
  1483         self.op = None
       
  1484     def visitAssName(self, node):
       
  1485         if self.op is None:
       
  1486             self.op = node.flags
       
  1487         elif self.op != node.flags:
       
  1488             raise ValueError, "mixed ops in stmt"
       
  1489     visitAssAttr = visitAssName
       
  1490     visitSubscript = visitAssName
       
  1491 
       
  1492 class Delegator:
       
  1493     """Base class to support delegation for augmented assignment nodes
       
  1494 
       
  1495     To generator code for augmented assignments, we use the following
       
  1496     wrapper classes.  In visitAugAssign, the left-hand expression node
       
  1497     is visited twice.  The first time the visit uses the normal method
       
  1498     for that node .  The second time the visit uses a different method
       
  1499     that generates the appropriate code to perform the assignment.
       
  1500     These delegator classes wrap the original AST nodes in order to
       
  1501     support the variant visit methods.
       
  1502     """
       
  1503     def __init__(self, obj):
       
  1504         self.obj = obj
       
  1505 
       
  1506     def __getattr__(self, attr):
       
  1507         return getattr(self.obj, attr)
       
  1508 
       
  1509 class AugGetattr(Delegator):
       
  1510     pass
       
  1511 
       
  1512 class AugName(Delegator):
       
  1513     pass
       
  1514 
       
  1515 class AugSlice(Delegator):
       
  1516     pass
       
  1517 
       
  1518 class AugSubscript(Delegator):
       
  1519     pass
       
  1520 
       
  1521 wrapper = {
       
  1522     ast.Getattr: AugGetattr,
       
  1523     ast.Name: AugName,
       
  1524     ast.Slice: AugSlice,
       
  1525     ast.Subscript: AugSubscript,
       
  1526     }
       
  1527 
       
  1528 def wrap_aug(node):
       
  1529     return wrapper[node.__class__](node)
       
  1530 
       
  1531 if __name__ == "__main__":
       
  1532     for file in sys.argv[1:]:
       
  1533         compileFile(file)